Function rotateAroundAxis()
rotates point around any axis in 3D. It is my solution to the rotation in 3D using analytic geometry and programming to model the process. The code is in JavaScript.
function rotateAroundAxis(A, B, C, alpha, precision) {
// A is rotated point, BC is axis, alpha is angle
// A, B, C are points in format [Ax, Ay, Az], alpha is float, precision is int
// A2 is output in format [A2x, A2y, A2z]
if((A[0] - B[0])*(A[1] - C[1]) == (A[1] - B[1])*(A[0] - C[0]) && (A[1] - B[1])*(A[2] - C[2]) == (A[1] - C[1])*(A[2] - B[2]) && (A[0] - B[0])*(A[2] - C[2]) == (A[0] - C[0])*(A[2] - B[2])) {
return A
}// Return the original point if it is on the axis.
var D = findClosestPoint(A, B, C, precision);
var w = crossProduct(new Array(C[0] - B[0], C[1] - B[1], C[2] - B[2]), new Array(C[0] - A[0], C[1] - A[1], C[2] - A[2]));
var W = pointPlusVector(A, w);
var sizeAW = vectorSize(A, W);
var sizeDA = vectorSize(D, A);
var sizeAE = sizeDA*(Math.sin(0.5*alpha))/(Math.cos(0.5*alpha));
var E = new Array(A[0] + (W[0] - A[0])*sizeAE/sizeAW, A[1] + (W[1] - A[1])*sizeAE/sizeAW, A[2] + (W[2] - A[2])*sizeAE/sizeAW);
var sizeDE = vectorSize(D, E);
var sizeEF = sizeAE*Math.sin(alpha/2);
var F = new Array(D[0] + (E[0] - D[0])*(sizeDE - sizeEF)/sizeDE, D[1] + (E[1] - D[1])*(sizeDE - sizeEF)/sizeDE, D[2] + (E[2] - D[2])*(sizeDE - sizeEF)/sizeDE);
var A2 = new Array(A[0] + 2*(F[0] - A[0]), A[1] + 2*(F[1] - A[1]), A[2] + 2*(F[2] - A[2]))
return A2;
}
function angleSize(A, S, B) {
ux = A[0] - S[0]; uy = A[1] - S[1]; uz = A[2] - S[2];
vx = B[0] - S[0]; vy = B[1] - S[1]; vz = B[2] - S[2];
if((Math.sqrt(ux*ux + uy*uy + uz*uz)*Math.sqrt(vx*vx + vy*vy + vz*vz)) == 0) {return 0}
return Math.acos((ux*vx + uy*vy + uz*vz)/(Math.sqrt(ux*ux + uy*uy + uz*uz)*Math.sqrt(vx*vx + vy*vy + vz*vz)));
}
function findClosestPoint(N, B, C, precision) {
// We will devide the segment BC into many tiny segments and we will choose the point F where the |NB F| distance is the shortest.
if(B[0] == C[0] && B[1] == C[1] && B[2] == C[2]) {return B}
var shortest = 0;
for(var i = 0; i <= precision; i++) {
var Fx = Math.round(precision*precision*(B[0] + (C[0] - B[0])*i/precision))/(precision*precision);
var Fy = Math.round(precision*precision*(B[1] + (C[1] - B[1])*i/precision))/(precision*precision);
var Fz = Math.round(precision*precision*(B[2] + (C[2] - B[2])*i/precision))/(precision*precision);
var sizeF = vectorSize(new Array(N[0], N[1], N[2]), new Array(Fx, Fy, Fz));
if(i == 0 || sizeF < shortest) { // first run or condition
shortest = sizeF;
F = new Array(Fx, Fy, Fz);
}
}
// recursion, if it is an outer point return findClosestPoint(we mirror further point in the closer one)
if(F[0] == Math.round(precision*precision*(B[0]))/(precision*precision) && F[1] == Math.round(precision*precision*(B[1]))/(precision*precision) && F[2] == Math.round(precision*precision*(B[2]))/(precision*precision)) { // F == B
if(Math.round(precision*precision*180*angleSize(C, B, N)/Math.PI)/(precision*precision) <= 90){return F} else {return findClosestPoint(N, new Array(2*B[0] - C[0], 2*B[1] - C[1], 2*B[2] - C[2]), B, precision)}
} else if (F[0] == Math.round(precision*precision*(C[0]))/(precision*precision) && F[1] == Math.round(precision*precision*(C[1]))/(precision*precision) && F[2] == Math.round(precision*precision*(C[2]))/(precision*precision)) { // F == C
if(Math.round(precision*precision*180*angleSize(B, C, N)/Math.PI)/(precision*precision) <= 90) {return F} else {return findClosestPoint(N, C, new Array(2*C[0] - B[0], 2*C[1] - B[1], 2*C[2] - B[2]), precision)}
} else {return F;}
}
function vectorSize(A, B) {
var ux = A[0] - B[0];
var uy = A[1] - B[1];
var uz = A[2] - B[2];
return Math.sqrt(ux*ux + uy*uy + uz*uz);
}
function crossProduct(u, v) {
return (new Array(u[1]*v[2] - u[2]*v[1], u[2]*v[0] - u[0]*v[2], u[0]*v[1] - u[1]*v[0]));
}
function pointPlusVector (A, v) {
return (new Array(A[0] + v[0], A[1] + v[1], A[2] + v[2]));
}