Drawing a torus with three.js
In previous posts, I have shown how to draw a torus whose equator passes by three given points with Haskell, R and POV-Ray. In this gist I provide the code for Asymptote. Here I’m going to provide the code for three.js.
Firstly, below is the Javascript function which returns the transformation matrix and the radius of the torus. The function takes as inputs the three points, each given as a Vector3, and returns an object containing the matrix as a Matrix4 and a number, the radius.
function TorusTransfo(p1, p2, p3) {
var p12 = new THREE.Vector3();
p12.addVectors(p1, p2).divideScalar(2);
var p23 = new THREE.Vector3();
p23.addVectors(p2, p3).divideScalar(2);
var xcoef = (p1.y - p2.y) * (p2.z - p3.z) - (p1.z - p2.z) * (p2.y - p3.y);
var ycoef = (p1.z - p2.z) * (p2.x - p3.x) - (p1.x - p2.x) * (p2.z - p3.z);
var zcoef = (p1.x - p2.x) * (p2.y - p3.y) - (p1.y - p2.y) * (p2.x - p3.x);
var offset1 = p1.x * xcoef + p1.y * ycoef + p1.z * zcoef;
var v12 = p2.clone(); v12.sub(p1);
var v23 = p3.clone(); v23.sub(p2);
var offset21 = p12.dot(v12); var offset22 = p23.dot(v23);
var M = new THREE.Matrix3();
M.set(xcoef, v12.x, v23.x, ycoef, v12.y, v23.y, zcoef, v12.z, v23.z);
invM = new THREE.Matrix3();
invM.getInverse(M);
// center = invM * (offset1, offset21, offset22)
var A = invM.toArray();
var center = new THREE.Vector3(
A[0] * offset1 + A[1] * offset21 + A[2] * offset22,
A[3] * offset1 + A[4] * offset21 + A[5] * offset22,
A[6] * offset1 + A[7] * offset21 + A[8] * offset22
);
var v = p1.clone(); v.sub(center);
var radius = v.length();
var T = new THREE.Matrix4();
if (xcoef == 0 && ycoef == 0) {
T.identity();
T.setPosition(center);
return { matrix: T, radius: radius };
}
var n = new THREE.Vector3(xcoef, ycoef, zcoef);
n.normalize();
var s = Math.sqrt(n.x * n.x + n.y * n.y);
var a = n.x / s; var b = n.y / s;
var u = new THREE.Vector3(b, -a, 0);
var v = new THREE.Vector3(); v.crossVectors(n, u);
T.set(
u.x, v.x, n.x, center.x,
u.y, v.y, n.y, center.y,
u.z, v.z, n.z, center.z,
0, 0, 0, 1
);
return { matrix: T, radius: radius };
}The addTorus function below conveniently adds the torus to a three.js object. The last argument r is the desired minor radius of the torus.
function addTorus(object, p1, p2, p3, r) {
var TR = TorusTransfo(p1, p2, p3);
var geom = new THREE.TorusGeometry(TR.radius, r, 32, 100);
var mesh = new THREE.Mesh(geom, new THREE.MeshNormalMaterial());
mesh.matrix = TR.matrix;
mesh.matrixAutoUpdate = false;
object.add(mesh);
}Then we apply the addTorus function as follows. First, define three points and the desired minor radius:
var A = new THREE.Vector3(0, 0, 0);
var B = new THREE.Vector3(0, 1, 0);
var C = new THREE.Vector3(1, 0, 1);
var r = 0.3;Then add the torus to an object in this way:
var scene = new THREE.Scene();
var object = new THREE.Object3D();
addTorus(object, A, B, C, r);
scene.add(object);As an illustration, below are the linked cyclides plotted with three.js. Click on the object and drag the mouse to play with it. You can get the full code by looking at the source, or by going to this gist.