import * as THREE from './lib/three.module.js'; function dotproduct(a, b){ var ret = 0; for (let i = 0; i v[i][j]){ min[j] = v[i][j]; } if (max[j] < v[i][j]){ max[j] = v[i][j]; } } } return { min: min, max: max, } } // v is array of vector, vl is vector length function array_as_vector_range(v, vl){ var n = v.length/vl; var min, max; if (n === 0){ return null; } else{ min = v.slice(0, vl); max = v.slice(0, vl); } for (var i=1; i v[i*vl+j]){ min[j] = v[i*vl+j]; } if (max[j] < v[i*vl+j]){ max[j] = v[i*vl+j]; } } } return { min: min, max: max, } } // v is 1-d array of vector, vl is vector length, p is index into v. function array_as_vector_index_range(v, vl, p){ var n = p.length; var min, max; if (n === 0){ return null; } else{ min = v.slice(p[0]*vl, (p[0]+1)*vl); max = v.slice(p[0]*vl, (p[0]+1)*vl); } for (var i=1; i v[p[i]*vl+j]){ min[j] = v[p[i]*vl+j]; } if (max[j] < v[p[i]*vl+j]){ max[j] = v[p[i]*vl+j]; } } } return { min: min, max: max, } } function vector3_nomalize(m){ var ret=[]; for (var i=0; iScalar(0))) { if(res[0] > Scalar(0)) { res[0] -= Scalar(Math.PI); } else { res[0] += Scalar(Math.PI); } res[1] = atan2(-coeff(i,k), -c2); } else res[1] = atan2(-coeff(i,k), c2); var s1 = sin(res[0]); var c1 = cos(res[0]); res[2] = atan2(s1*coeff(k,i)-c1*coeff(j,i), c1*coeff(j,j) - s1 * coeff(k,j)); if (!odd) res = res.map(function(x){return -x;}) return { x: res[0], y: res[1], z: res[2], } } var linalg_std = { euler_angle_to_rotation_matrix: function(euler){ var theta = [euler.x, euler.y, euler.z]; // Calculate rotation about x axis var R_x = new THREE.Matrix4(); R_x.set( 1, 0, 0, 0, 0, Math.cos(theta[0]), -Math.sin(theta[0]), 0, 0, Math.sin(theta[0]), Math.cos(theta[0]) , 0, 0, 0, 0, 1, ); // Calculate rotation about y axis var R_y = new THREE.Matrix4(); R_y.set( Math.cos(theta[1]), 0, Math.sin(theta[1]), 0, 0, 1, 0, 0, -Math.sin(theta[1]), 0, Math.cos(theta[1]), 0, 0, 0, 0, 1, ); // Calculate rotation about z axis var R_z = new THREE.Matrix4(); R_z.set( Math.cos(theta[2]), -Math.sin(theta[2]), 0, 0, Math.sin(theta[2]), Math.cos(theta[2]), 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, ); R_z.multiply(R_y); R_z.multiply(R_x); return R_z; }, euler_angle_from_rotation_matrix: function(m){ var euler = new THREE.Euler(); euler.setFromRotationMatrix(m); return euler; }, // {x:, y:, z:} euler_angle_composite: function(current, delta){ var current_matrix = this.euler_angle_to_rotation_matrix(current); var delta_matrix = this.euler_angle_to_rotation_matrix(delta); var composite_matrix = new THREE.Matrix4(); composite_matrix.multiplyMatrices(delta_matrix, current_matrix); return this.euler_angle_from_rotation_matrix(composite_matrix); } } function normalizeAngle(a) { while (true) { if ( a > Math.PI) a -= Math.PI *2; else if (a < -Math.PI) a += Math.PI * 2; else return a; } } // box(position, scale, rotation) to box corner corrdinates. // return 8 points, represented as (x,y,z,1) // note the vertices order cannot be changed, draw-box-on-image assumes // the first 4 vertex is the front plane, so it knows box direction. function psr_to_xyz_face_points(p,s,r, minGrid){ /* var trans_matrix=[ Math.cos(r.z), -Math.sin(r.z), 0, p.x, Math.sin(r.z), Math.cos(r.z), 0, p.y, 0, 0, 1, p.z, 0, 0, 0, 1, ]; */ var trans_matrix = euler_angle_to_rotate_matrix(r, p); var x=s.x/2; var y=s.y/2; var z=s.z/2; // var local_coord = [ // [x, y, -z], [x, -y, -z], //front-left-bottom, front-right-bottom // [x, -y, z], [x, y, z], //front-right-top, front-left-top // [-x, y, -z], [-x, -y, -z], //rear-left-bottom, rear-right-bottom // [-x, -y, z], [-x, y, z], //rear-right-top, rear-left-top // ]; let xs = []; for (let i = -x ; i <=x; i+=minGrid) { xs.push(i); } let ys = []; for (let i = -y ; i <=y; i+=minGrid) { ys.push(i); } let zs = []; for (let i = -z ; i <=z; i+=minGrid) { zs.push(i); } let points = []; points = points.concat(ys.map(i=>[x, i, -z, 1])); points = points.concat(ys.map(i=>[x, i, z, 1])); points = points.concat(ys.map(i=>[-x, i, -z, 1])); points = points.concat(ys.map(i=>[-x, i, z, 1])); points = points.concat(xs.map(i=>[i, y, -z, 1])); points = points.concat(xs.map(i=>[i, y, z, 1])); points = points.concat(xs.map(i=>[i, -y, -z, 1])); points = points.concat(xs.map(i=>[i, -y, z, 1])); points = points.concat(zs.map(i=>[x, y, i, 1])); points = points.concat(zs.map(i=>[x, -y, i, 1])); points = points.concat(zs.map(i=>[-x, -y, i, 1])); points = points.concat(zs.map(i=>[-x, y, i, 1])); points = points.reduce((a,b)=>a.concat(b)) let world_coord = matmul(trans_matrix, points, 4); return vector4to3(world_coord); } function cornersAinB(boxA,boxB){ let minGrid = Math.min( boxA.scale.x, boxA.scale.y, boxA.scale.z, boxB.scale.x, boxB.scale.y, boxB.scale.z, ); minGrid = minGrid / 2; // in world coord, offset by b pos let boxAPosInB = {x: boxA.position.x - boxB.position.x, y: boxA.position.y - boxB.position.y, z: boxA.position.z - boxB.position.z}; let cornersA = psr_to_xyz_face_points(boxAPosInB, boxA.scale, boxA.rotation, minGrid); // in world coordinates cornersA.push(boxAPosInB.x, boxAPosInB.y, boxAPosInB.z); //center point // in box b coord let matrixB = euler_angle_to_rotate_matrix_3by3(boxB.rotation); matrixB = transpose(matrixB,3) let cornersAInB = matmul(matrixB, cornersA, 3); for (let i =0; i < cornersAInB.length; i+=3){ let [x,y,z] = cornersAInB.slice(i, i+3) if ( Math.abs(x) < boxB.scale.x/2 && Math.abs(y) < boxB.scale.y/2 && Math.abs(z) < boxB.scale.z/2) { return true; } } return false; } // check if 2 boxes has non-empty intersection // the idea is to check if any corner of one box is inside the other one // when boxA contains B entirely, we shoudl test the opposite way. function intersect(boxA, boxB){ return cornersAinB(boxA, boxB) || cornersAinB(boxB, boxA); }; export {dotproduct, vector_range, array_as_vector_range, array_as_vector_index_range, vector4to3, vector3_nomalize, psr_to_xyz, matmul, matmul2, euler_angle_to_rotate_matrix_3by3, euler_angle_to_rotate_matrix, rotation_matrix_to_euler_angle, linalg_std, transpose, mat, normalizeAngle, intersect }