virtualx-engine/modules/mono/glue/cs_files/Basis.cs

528 lines
16 KiB
C#
Raw Normal View History

2017-10-02 23:24:00 +02:00
using System;
using System.Runtime.InteropServices;
#if REAL_T_IS_DOUBLE
using real_t = System.Double;
#else
using real_t = System.Single;
#endif
2017-10-02 23:24:00 +02:00
namespace Godot
{
[StructLayout(LayoutKind.Sequential)]
public struct Basis : IEquatable<Basis>
{
private static readonly Basis identity = new Basis
(
new Vector3(1f, 0f, 0f),
new Vector3(0f, 1f, 0f),
new Vector3(0f, 0f, 1f)
);
private static readonly Basis[] orthoBases = new Basis[24]
{
new Basis(1f, 0f, 0f, 0f, 1f, 0f, 0f, 0f, 1f),
new Basis(0f, -1f, 0f, 1f, 0f, 0f, 0f, 0f, 1f),
new Basis(-1f, 0f, 0f, 0f, -1f, 0f, 0f, 0f, 1f),
new Basis(0f, 1f, 0f, -1f, 0f, 0f, 0f, 0f, 1f),
new Basis(1f, 0f, 0f, 0f, 0f, -1f, 0f, 1f, 0f),
new Basis(0f, 0f, 1f, 1f, 0f, 0f, 0f, 1f, 0f),
new Basis(-1f, 0f, 0f, 0f, 0f, 1f, 0f, 1f, 0f),
new Basis(0f, 0f, -1f, -1f, 0f, 0f, 0f, 1f, 0f),
new Basis(1f, 0f, 0f, 0f, -1f, 0f, 0f, 0f, -1f),
new Basis(0f, 1f, 0f, 1f, 0f, 0f, 0f, 0f, -1f),
new Basis(-1f, 0f, 0f, 0f, 1f, 0f, 0f, 0f, -1f),
new Basis(0f, -1f, 0f, -1f, 0f, 0f, 0f, 0f, -1f),
new Basis(1f, 0f, 0f, 0f, 0f, 1f, 0f, -1f, 0f),
new Basis(0f, 0f, -1f, 1f, 0f, 0f, 0f, -1f, 0f),
new Basis(-1f, 0f, 0f, 0f, 0f, -1f, 0f, -1f, 0f),
new Basis(0f, 0f, 1f, -1f, 0f, 0f, 0f, -1f, 0f),
new Basis(0f, 0f, 1f, 0f, 1f, 0f, -1f, 0f, 0f),
new Basis(0f, -1f, 0f, 0f, 0f, 1f, -1f, 0f, 0f),
new Basis(0f, 0f, -1f, 0f, -1f, 0f, -1f, 0f, 0f),
new Basis(0f, 1f, 0f, 0f, 0f, -1f, -1f, 0f, 0f),
new Basis(0f, 0f, 1f, 0f, -1f, 0f, 1f, 0f, 0f),
new Basis(0f, 1f, 0f, 0f, 0f, 1f, 1f, 0f, 0f),
new Basis(0f, 0f, -1f, 0f, 1f, 0f, 1f, 0f, 0f),
new Basis(0f, -1f, 0f, 0f, 0f, -1f, 1f, 0f, 0f)
};
public Vector3 x;
public Vector3 y;
public Vector3 z;
public static Basis Identity
{
get { return identity; }
}
public Vector3 Scale
{
get
{
return new Vector3
(
2017-11-21 23:32:19 +01:00
new Vector3(this[0, 0], this[1, 0], this[2, 0]).Length(),
new Vector3(this[0, 1], this[1, 1], this[2, 1]).Length(),
new Vector3(this[0, 2], this[1, 2], this[2, 2]).Length()
2017-10-02 23:24:00 +02:00
);
}
}
public Vector3 this[int index]
{
get
{
switch (index)
{
case 0:
return x;
case 1:
return y;
case 2:
return z;
default:
throw new IndexOutOfRangeException();
}
}
set
{
switch (index)
{
case 0:
x = value;
return;
case 1:
y = value;
return;
case 2:
z = value;
return;
default:
throw new IndexOutOfRangeException();
}
}
}
public real_t this[int index, int axis]
2017-10-02 23:24:00 +02:00
{
get
{
switch (index)
{
case 0:
return x[axis];
case 1:
return y[axis];
case 2:
return z[axis];
default:
throw new IndexOutOfRangeException();
}
}
set
{
switch (index)
{
case 0:
x[axis] = value;
return;
case 1:
y[axis] = value;
return;
case 2:
z[axis] = value;
return;
default:
throw new IndexOutOfRangeException();
}
}
}
2017-11-21 23:32:19 +01:00
internal static Basis CreateFromAxes(Vector3 xAxis, Vector3 yAxis, Vector3 zAxis)
2017-10-02 23:24:00 +02:00
{
return new Basis
(
new Vector3(xAxis.x, yAxis.x, zAxis.x),
new Vector3(xAxis.y, yAxis.y, zAxis.y),
new Vector3(xAxis.z, yAxis.z, zAxis.z)
);
}
public real_t Determinant()
2017-10-02 23:24:00 +02:00
{
return this[0, 0] * (this[1, 1] * this[2, 2] - this[2, 1] * this[1, 2]) -
this[1, 0] * (this[0, 1] * this[2, 2] - this[2, 1] * this[0, 2]) +
this[2, 0] * (this[0, 1] * this[1, 2] - this[1, 1] * this[0, 2]);
}
2017-11-21 23:32:19 +01:00
public Vector3 GetAxis(int axis)
2017-10-02 23:24:00 +02:00
{
return new Vector3(this[0, axis], this[1, axis], this[2, axis]);
}
2017-11-21 23:32:19 +01:00
public Vector3 GetEuler()
2017-10-02 23:24:00 +02:00
{
2017-11-21 23:32:19 +01:00
Basis m = this.Orthonormalized();
2017-10-02 23:24:00 +02:00
Vector3 euler;
euler.z = 0.0f;
2017-10-02 23:24:00 +02:00
real_t mxy = m.y[2];
2017-10-02 23:24:00 +02:00
if (mxy < 1.0f)
2017-10-02 23:24:00 +02:00
{
if (mxy > -1.0f)
2017-10-02 23:24:00 +02:00
{
2017-11-21 23:32:19 +01:00
euler.x = Mathf.Asin(-mxy);
euler.y = Mathf.Atan2(m.x[2], m.z[2]);
euler.z = Mathf.Atan2(m.y[0], m.y[1]);
2017-10-02 23:24:00 +02:00
}
else
{
euler.x = Mathf.PI * 0.5f;
2017-11-21 23:32:19 +01:00
euler.y = -Mathf.Atan2(-m.x[1], m.x[0]);
2017-10-02 23:24:00 +02:00
}
}
else
{
euler.x = -Mathf.PI * 0.5f;
2017-11-21 23:32:19 +01:00
euler.y = -Mathf.Atan2(m.x[1], m.x[0]);
2017-10-02 23:24:00 +02:00
}
return euler;
}
2017-11-21 23:32:19 +01:00
public int GetOrthogonalIndex()
2017-10-02 23:24:00 +02:00
{
Basis orth = this;
for (int i = 0; i < 3; i++)
{
for (int j = 0; j < 3; j++)
{
real_t v = orth[i, j];
2017-10-02 23:24:00 +02:00
if (v > 0.5f)
v = 1.0f;
else if (v < -0.5f)
v = -1.0f;
else
v = 0f;
orth[i, j] = v;
}
}
for (int i = 0; i < 24; i++)
{
if (orthoBases[i] == orth)
return i;
}
return 0;
}
2017-11-21 23:32:19 +01:00
public Basis Inverse()
2017-10-02 23:24:00 +02:00
{
Basis inv = this;
real_t[] co = new real_t[3]
2017-10-02 23:24:00 +02:00
{
inv[1, 1] * inv[2, 2] - inv[1, 2] * inv[2, 1],
inv[1, 2] * inv[2, 0] - inv[1, 0] * inv[2, 2],
inv[1, 0] * inv[2, 1] - inv[1, 1] * inv[2, 0]
};
real_t det = inv[0, 0] * co[0] + inv[0, 1] * co[1] + inv[0, 2] * co[2];
2017-10-02 23:24:00 +02:00
if (det == 0)
{
return new Basis
(
real_t.NaN, real_t.NaN, real_t.NaN,
real_t.NaN, real_t.NaN, real_t.NaN,
real_t.NaN, real_t.NaN, real_t.NaN
2017-10-02 23:24:00 +02:00
);
}
real_t s = 1.0f / det;
2017-10-02 23:24:00 +02:00
inv = new Basis
(
co[0] * s,
inv[0, 2] * inv[2, 1] - inv[0, 1] * inv[2, 2] * s,
inv[0, 1] * inv[1, 2] - inv[0, 2] * inv[1, 1] * s,
co[1] * s,
inv[0, 0] * inv[2, 2] - inv[0, 2] * inv[2, 0] * s,
inv[0, 2] * inv[1, 0] - inv[0, 0] * inv[1, 2] * s,
co[2] * s,
inv[0, 1] * inv[2, 0] - inv[0, 0] * inv[2, 1] * s,
inv[0, 0] * inv[1, 1] - inv[0, 1] * inv[1, 0] * s
);
return inv;
}
2017-11-21 23:32:19 +01:00
public Basis Orthonormalized()
2017-10-02 23:24:00 +02:00
{
2017-11-21 23:32:19 +01:00
Vector3 xAxis = GetAxis(0);
Vector3 yAxis = GetAxis(1);
Vector3 zAxis = GetAxis(2);
2017-10-02 23:24:00 +02:00
2017-11-21 23:32:19 +01:00
xAxis.Normalize();
yAxis = (yAxis - xAxis * (xAxis.Dot(yAxis)));
yAxis.Normalize();
zAxis = (zAxis - xAxis * (xAxis.Dot(zAxis)) - yAxis * (yAxis.Dot(zAxis)));
zAxis.Normalize();
2017-10-02 23:24:00 +02:00
2017-11-21 23:32:19 +01:00
return Basis.CreateFromAxes(xAxis, yAxis, zAxis);
2017-10-02 23:24:00 +02:00
}
public Basis Rotated(Vector3 axis, real_t phi)
2017-10-02 23:24:00 +02:00
{
return new Basis(axis, phi) * this;
2017-10-02 23:24:00 +02:00
}
2017-11-21 23:32:19 +01:00
public Basis Scaled(Vector3 scale)
2017-10-02 23:24:00 +02:00
{
Basis m = this;
m[0, 0] *= scale.x;
m[0, 1] *= scale.x;
m[0, 2] *= scale.x;
m[1, 0] *= scale.y;
2017-10-02 23:24:00 +02:00
m[1, 1] *= scale.y;
m[1, 2] *= scale.y;
m[2, 0] *= scale.z;
m[2, 1] *= scale.z;
2017-10-02 23:24:00 +02:00
m[2, 2] *= scale.z;
return m;
}
public real_t Tdotx(Vector3 with)
2017-10-02 23:24:00 +02:00
{
return this[0, 0] * with[0] + this[1, 0] * with[1] + this[2, 0] * with[2];
}
public real_t Tdoty(Vector3 with)
2017-10-02 23:24:00 +02:00
{
return this[0, 1] * with[0] + this[1, 1] * with[1] + this[2, 1] * with[2];
}
public real_t Tdotz(Vector3 with)
2017-10-02 23:24:00 +02:00
{
return this[0, 2] * with[0] + this[1, 2] * with[1] + this[2, 2] * with[2];
}
2017-11-21 23:32:19 +01:00
public Basis Transposed()
2017-10-02 23:24:00 +02:00
{
Basis tr = this;
real_t temp = this[0, 1];
2017-10-02 23:24:00 +02:00
this[0, 1] = this[1, 0];
this[1, 0] = temp;
temp = this[0, 2];
this[0, 2] = this[2, 0];
this[2, 0] = temp;
temp = this[1, 2];
this[1, 2] = this[2, 1];
this[2, 1] = temp;
return tr;
}
2017-11-21 23:32:19 +01:00
public Vector3 Xform(Vector3 v)
2017-10-02 23:24:00 +02:00
{
return new Vector3
(
2017-11-21 23:32:19 +01:00
this[0].Dot(v),
this[1].Dot(v),
this[2].Dot(v)
2017-10-02 23:24:00 +02:00
);
}
2017-11-21 23:32:19 +01:00
public Vector3 XformInv(Vector3 v)
2017-10-02 23:24:00 +02:00
{
return new Vector3
(
(this[0, 0] * v.x) + (this[1, 0] * v.y) + (this[2, 0] * v.z),
(this[0, 1] * v.x) + (this[1, 1] * v.y) + (this[2, 1] * v.z),
(this[0, 2] * v.x) + (this[1, 2] * v.y) + (this[2, 2] * v.z)
);
}
public Quat Quat() {
real_t trace = x[0] + y[1] + z[2];
if (trace > 0.0f) {
real_t s = Mathf.Sqrt(trace + 1.0f) * 2f;
real_t inv_s = 1f / s;
return new Quat(
(z[1] - y[2]) * inv_s,
(x[2] - z[0]) * inv_s,
(y[0] - x[1]) * inv_s,
s * 0.25f
);
} else if (x[0] > y[1] && x[0] > z[2]) {
real_t s = Mathf.Sqrt(x[0] - y[1] - z[2] + 1.0f) * 2f;
real_t inv_s = 1f / s;
return new Quat(
s * 0.25f,
(x[1] + y[0]) * inv_s,
(x[2] + z[0]) * inv_s,
(z[1] - y[2]) * inv_s
);
} else if (y[1] > z[2]) {
real_t s = Mathf.Sqrt(-x[0] + y[1] - z[2] + 1.0f) * 2f;
real_t inv_s = 1f / s;
return new Quat(
(x[1] + y[0]) * inv_s,
s * 0.25f,
(y[2] + z[1]) * inv_s,
(x[2] - z[0]) * inv_s
);
} else {
real_t s = Mathf.Sqrt(-x[0] - y[1] + z[2] + 1.0f) * 2f;
real_t inv_s = 1f / s;
return new Quat(
(x[2] + z[0]) * inv_s,
(y[2] + z[1]) * inv_s,
s * 0.25f,
(y[0] - x[1]) * inv_s
);
}
}
// Constructors
2017-10-02 23:24:00 +02:00
public Basis(Quat quat)
{
real_t s = 2.0f / quat.LengthSquared();
real_t xs = quat.x * s;
real_t ys = quat.y * s;
real_t zs = quat.z * s;
real_t wx = quat.w * xs;
real_t wy = quat.w * ys;
real_t wz = quat.w * zs;
real_t xx = quat.x * xs;
real_t xy = quat.x * ys;
real_t xz = quat.x * zs;
real_t yy = quat.y * ys;
real_t yz = quat.y * zs;
real_t zz = quat.z * zs;
2017-10-02 23:24:00 +02:00
this.x = new Vector3(1.0f - (yy + zz), xy - wz, xz + wy);
this.y = new Vector3(xy + wz, 1.0f - (xx + zz), yz - wx);
this.z = new Vector3(xz - wy, yz + wx, 1.0f - (xx + yy));
}
public Basis(Vector3 axis, real_t phi)
2017-10-02 23:24:00 +02:00
{
Vector3 axis_sq = new Vector3(axis.x * axis.x, axis.y * axis.y, axis.z * axis.z);
real_t cosine = Mathf.Cos( (real_t)phi);
real_t sine = Mathf.Sin( (real_t)phi);
2017-10-02 23:24:00 +02:00
this.x = new Vector3
(
axis_sq.x + cosine * (1.0f - axis_sq.x),
axis.x * axis.y * (1.0f - cosine) - axis.z * sine,
axis.z * axis.x * (1.0f - cosine) + axis.y * sine
);
this.y = new Vector3
(
axis.x * axis.y * (1.0f - cosine) + axis.z * sine,
axis_sq.y + cosine * (1.0f - axis_sq.y),
axis.y * axis.z * (1.0f - cosine) - axis.x * sine
);
this.z = new Vector3
(
axis.z * axis.x * (1.0f - cosine) - axis.y * sine,
axis.y * axis.z * (1.0f - cosine) + axis.x * sine,
axis_sq.z + cosine * (1.0f - axis_sq.z)
);
}
public Basis(Vector3 xAxis, Vector3 yAxis, Vector3 zAxis)
{
this.x = xAxis;
this.y = yAxis;
this.z = zAxis;
}
public Basis(real_t xx, real_t xy, real_t xz, real_t yx, real_t yy, real_t yz, real_t zx, real_t zy, real_t zz)
2017-10-02 23:24:00 +02:00
{
this.x = new Vector3(xx, yx, zx);
this.y = new Vector3(xy, yy, zy);
this.z = new Vector3(xz, yz, zz);
2017-10-02 23:24:00 +02:00
}
public static Basis operator *(Basis left, Basis right)
{
return new Basis
(
2017-11-21 23:32:19 +01:00
right.Tdotx(left[0]), right.Tdoty(left[0]), right.Tdotz(left[0]),
right.Tdotx(left[1]), right.Tdoty(left[1]), right.Tdotz(left[1]),
right.Tdotx(left[2]), right.Tdoty(left[2]), right.Tdotz(left[2])
2017-10-02 23:24:00 +02:00
);
}
public static bool operator ==(Basis left, Basis right)
{
return left.Equals(right);
}
public static bool operator !=(Basis left, Basis right)
{
return !left.Equals(right);
}
public override bool Equals(object obj)
{
if (obj is Basis)
{
return Equals((Basis)obj);
}
return false;
}
public bool Equals(Basis other)
{
return x.Equals(other.x) && y.Equals(other.y) && z.Equals(other.z);
}
public override int GetHashCode()
{
return x.GetHashCode() ^ y.GetHashCode() ^ z.GetHashCode();
}
public override string ToString()
{
return String.Format("({0}, {1}, {2})", new object[]
{
this.x.ToString(),
this.y.ToString(),
this.z.ToString()
});
}
public string ToString(string format)
{
return String.Format("({0}, {1}, {2})", new object[]
{
this.x.ToString(format),
this.y.ToString(format),
this.z.ToString(format)
});
}
}
}