Because I’m interested, I’ve made a little programme. It calculates the distance of skewed straight lines with two different formulas. With determinants and with cross vectors.
Then you can set an accuracy limit and determine the intersection point.
If there are two trajectories, you can use the size of the objects to detect collisions.
To simplify things, you can only change the direction of a line, the component x.
It can be tested there http://threejs.hofk.de/LinesDistance/LinesDistance.html
The full code:
<!DOCTYPE html>
<head>
<title> LinesDistance </title>
<meta charset="utf-8" />
</head>
<body>
mp.x <input type="range" id="mpx" min="0" max="1" value="0.725" step="0.0001" style="width: 90%;">
<div id="distance"> </div>
<div id="Pn"> </div>
<div id="Qn"> </div>
</body>
<script src="../js/three.min.102.js"></script>
<script src="../js/OrbitControls.js"></script>
<script>
// @author hofk
var mpx = document.getElementById( 'mpx' );
mpx.onchange = refresh;
var dpnqnDet, pnDet, qnDet; // uses determinant
var dpnqnCr, pnCr, qnCr; // uses cross vectors
var dist; // uses formula distance
var scene = new THREE.Scene();
var camera = new THREE.PerspectiveCamera( 55, window.innerWidth / window.innerHeight, 0.1, 1000 );
camera.position.set( 0, 10, 40 );
var renderer = new THREE.WebGLRenderer( { antialias: true } );
renderer.setSize( window.innerWidth, window.innerHeight );
renderer.setClearColor( 0xaaaaaa, 1 );
var container = document.createElement( 'div' );
document.body.appendChild( container );
container.appendChild( renderer.domElement );
var controls = new THREE.OrbitControls( camera, renderer.domElement );
var axesHelper = new THREE.AxesHelper( 28 );
scene.add( axesHelper );
var grid = new THREE.GridHelper( 50, 50 );
scene.add( grid );
var gLineP = new THREE.BufferGeometry( );
gLineP.positions = new Float32Array( 6 );
gLineP.addAttribute( 'position', new THREE.BufferAttribute( gLineP.positions, 3 ).setDynamic( true ) );
lineP = new THREE.Line( gLineP, new THREE.LineBasicMaterial( { color: 0x00ffff, side: THREE.DoubleSide } ) );
var p = new THREE.Vector3( -15, 12, -5 );
var mp = new THREE.Vector3( 35, -8 , 15 ); // mp.x can be changed with slider
gLineP.positions[ 0 ] = p.x;
gLineP.positions[ 1 ] = p.y;
gLineP.positions[ 2 ] = p.z;
gLineP.positions[ 3 ] = p.x + mp.x;
gLineP.positions[ 4 ] = p.y + mp.y;
gLineP.positions[ 5 ] = p.z + mp.z;
scene.add( lineP );
var gLineQ = new THREE.BufferGeometry( );
gLineQ.positions = new Float32Array( 6 );
gLineQ.addAttribute( 'position', new THREE.BufferAttribute( gLineQ.positions, 3 ) );
lineQ = new THREE.Line( gLineQ, new THREE.LineBasicMaterial( { color: 0xffff00, side: THREE.DoubleSide } ) );
var q = new THREE.Vector3( -12, 14, -15 );
var mq = new THREE.Vector3( 34, -12, 33 );
gLineQ.positions[ 0 ] = q.x;
gLineQ.positions[ 1 ] = q.y;
gLineQ.positions[ 2 ] = q.z;
gLineQ.positions[ 3 ] = q.x + mq.x;
gLineQ.positions[ 4 ] = q.y + mq.y;
gLineQ.positions[ 5 ] = q.z + mq.z;
scene.add( lineQ );
refresh( );
animate();
function animate() {
requestAnimationFrame( animate );
renderer.render( scene, camera );
controls.update();
}
function linesDistance( ) { // mp and mq non-collinear
var pq = new THREE.Vector3( ).subVectors( q, p );
var n = new THREE.Vector3( ).crossVectors( mp, mq ).normalize( );
var d = pq.dot( n );
return Math.abs( d );
}
function closestPointsDet( ) { // mp and mq non-collinear
// using determinant
var qp = new THREE.Vector3( ).subVectors( p, q );
var qpDotmp = qp.dot( mp );
var qpDotmq = qp.dot( mq );
var mpDotmp = mp.dot( mp );
var mqDotmq = mq.dot( mq );
var mpDotmq = mp.dot( mq );
var detp = qpDotmp * mqDotmq - qpDotmq * mpDotmq;
var detq = qpDotmp * mpDotmq - qpDotmq * mpDotmp;
var detm = mpDotmq * mpDotmq - mqDotmq * mpDotmp;
pnDet = p.clone( ).add( mp.clone( ).multiplyScalar( detp / detm ) );
qnDet = q.clone( ).add( mq.clone( ).multiplyScalar( detq / detm ) );
dpnqnDet = pnDet.clone( ).sub( qnDet ).length( );
}
function closestPointsCross( ) { // mp and mq non-collinear
// using cross vectors
var qp = new THREE.Vector3( ).subVectors( p, q );
var pq = qp.clone( ).multiplyScalar( -1 );
var npq = new THREE.Vector3( ).crossVectors( mp, mq ).normalize( );
var nqp = new THREE.Vector3( ).crossVectors( mq, mp ).normalize( );
var n1 = new THREE.Vector3( ).crossVectors( mp, nqp ).normalize( );
var n2 = new THREE.Vector3( ).crossVectors( mq, npq ).normalize( );
var qpDotn1 = qp.dot( n1 );
var pqDotn2 = pq.dot( n2 );
var mpDotn2 = mp.dot( n2 );
var mqDotn1 = mq.dot( n1 );
pnCr = p.clone( ).add( mp.clone( ).multiplyScalar( pqDotn2 / mpDotn2 ) );
qnCr = q.clone( ).add( mq.clone( ).multiplyScalar( qpDotn1 / mqDotn1 ) );
dpnqnCr = pnCr.clone( ).sub( qnCr ).length( );
}
function refresh( ) {
mp.x = mpx.value * 50;
gLineP.positions[ 3 ] = p.x + mp.x;
gLineP.attributes.position.needsUpdate = true;
closestPointsDet( );
closestPointsCross( );
Pn.innerHTML = ' Pn Det ( ' + pnDet.x + ', '+ pnDet.y + ', '+ pnDet.z + ' ) <==> Pn Cr ( ' + pnCr.x + ', '+ pnCr.y + ', '+ pnCr.z + ' ) ';
Qn.innerHTML = ' Qn Det ( ' + qnDet.x + ', '+ qnDet.y + ', '+ qnDet.z + ' ) <==> Qn Cr ( ' + qnCr.x + ', '+ qnCr.y + ', '+ qnCr.z + ' ) ';
dist = linesDistance( );
distance.innerHTML = 'distance: dPQ Determinant: ' + dpnqnDet + ' <==> function linesDistance( ) :' + dist + ' <==> dPQ Cross: ' + dpnqnCr;
}</script>
</html>