You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
150 lines
4.4 KiB
150 lines
4.4 KiB
using System; |
|
using System.Collections.Generic; |
|
using System.Text; |
|
|
|
namespace YLScsDrawing.Drawing3d |
|
{ |
|
public struct Quaternion |
|
{ |
|
public double X, Y, Z, W; |
|
|
|
public Quaternion(double w, double x, double y, double z) |
|
{ |
|
W = w; X = x; Y = y; Z = z; |
|
} |
|
|
|
public Quaternion(double w, Vector3d v) |
|
{ |
|
W = w; X = v.X; Y = v.Y; Z = v.Z; |
|
} |
|
|
|
public Vector3d V |
|
{ |
|
set { X = value.X; Y = value.Y; Z = value.Z; } |
|
get { return new Vector3d(X, Y, Z); } |
|
} |
|
|
|
public void Normalise() |
|
{ |
|
double m = W * W + X * X + Y * Y + Z * Z; |
|
if (m > 0.001) |
|
{ |
|
m = Math.Sqrt(m); |
|
W /= m; |
|
X /= m; |
|
Y /= m; |
|
Z /= m; |
|
} |
|
else |
|
{ |
|
W = 1; X = 0; Y = 0; Z = 0; |
|
} |
|
} |
|
|
|
public void Conjugate() |
|
{ |
|
X = -X; Y = -Y; Z = -Z; |
|
} |
|
|
|
public void FromAxisAngle(Vector3d axis, double angleRadian) |
|
{ |
|
double m = axis.Magnitude; |
|
if (m > 0.0001) |
|
{ |
|
double ca = Math.Cos(angleRadian / 2); |
|
double sa = Math.Sin(angleRadian / 2); |
|
X = axis.X / m * sa; |
|
Y = axis.Y / m * sa; |
|
Z = axis.Z / m * sa; |
|
W = ca; |
|
} |
|
else |
|
{ |
|
W = 1; X = 0; Y = 0; Z = 0; |
|
} |
|
} |
|
|
|
public Quaternion Copy() |
|
{ |
|
return new Quaternion(W, X, Y, Z); |
|
} |
|
|
|
public void Multiply(Quaternion q) |
|
{ |
|
this *= q; |
|
} |
|
|
|
// -1 |
|
// V'=q*V*q , |
|
public void Rotate(Point3d pt) |
|
{ |
|
this.Normalise(); |
|
Quaternion q1 = this.Copy(); |
|
q1.Conjugate(); |
|
|
|
Quaternion qNode = new Quaternion(0, pt.X, pt.Y, pt.Z); |
|
qNode = this * qNode * q1; |
|
pt.X = qNode.X; |
|
pt.Y = qNode.Y; |
|
pt.Z = qNode.Z; |
|
} |
|
|
|
public void Rotate(Point3d[] nodes) |
|
{ |
|
this.Normalise(); |
|
Quaternion q1 = this.Copy(); |
|
q1.Conjugate(); |
|
for (int i = 0; i < nodes.Length; i++) |
|
{ |
|
Quaternion qNode = new Quaternion(0, nodes[i].X, nodes[i].Y, nodes[i].Z); |
|
qNode = this * qNode * q1; |
|
nodes[i].X = qNode.X; |
|
nodes[i].Y = qNode.Y; |
|
nodes[i].Z = qNode.Z; |
|
} |
|
} |
|
|
|
// Multiplying q1 with q2 is meaning of doing q2 firstly then q1 |
|
public static Quaternion operator *(Quaternion q1, Quaternion q2) |
|
{ |
|
double nw = q1.W * q2.W - q1.X * q2.X - q1.Y * q2.Y - q1.Z * q2.Z; |
|
double nx = q1.W * q2.X + q1.X * q2.W + q1.Y * q2.Z - q1.Z * q2.Y; |
|
double ny = q1.W * q2.Y + q1.Y * q2.W + q1.Z * q2.X - q1.X * q2.Z; |
|
double nz = q1.W * q2.Z + q1.Z * q2.W + q1.X * q2.Y - q1.Y * q2.X; |
|
return new Quaternion(nw, nx, ny, nz); |
|
} |
|
|
|
public static Vector3d operator *(Quaternion self, Vector3d other) |
|
{ |
|
double w = self.W; |
|
double x = self.X; |
|
double y = self.Y; |
|
double z = self.Z; |
|
double Vx = other.X; |
|
double Vy = other.Y; |
|
double Vz = other.Z; |
|
double ww = w * w; |
|
double w2 = w * 2; |
|
double wx2 = w2 * x; |
|
double wy2 = w2 * y; |
|
double wz2 = w2 * z; |
|
double xx = x * x; |
|
double x2 = x * 2; |
|
double xy2 = x2 * y; |
|
double xz2 = x2 * z; |
|
double yy = y * y; |
|
double yz2 = 2 * y * z; |
|
double zz = z * z; |
|
return new Vector3d( |
|
ww * Vx + wy2 * Vz - wz2 * Vy + |
|
xx * Vx + xy2 * Vy + xz2 * Vz - |
|
zz * Vx - yy * Vx, |
|
xy2 * Vx + yy * Vy + yz2 * Vz + |
|
wz2 * Vx - zz * Vy + ww * Vy - |
|
wx2 * Vz - xx * Vy, |
|
xz2 * Vx + yz2 * Vy + |
|
zz * Vz - wy2 * Vx - yy * Vz + |
|
wx2 * Vy - xx * Vz + ww * Vz); |
|
} |
|
} |
|
}
|
|
|