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); } } }