原理解析几何通用解法:
在空间中两条线上最短距离处的点连垂直于两条线L1、L2
算法描述:设两条无限长度直线s、t,起点为s0、t0,方向向量为u、v
1、最短直线两点:在s上为s0 + sc*u,在t上的为t0 + tc*v
2、记向量w为(s0+sc*u) - (t0+tc*v),记向量w0 = s0 - t0
记a = u*u,b = u*v,c = v*v,d = u*w0,e = v*w0 公式(a);
w向量与两线段分别垂直时最短,所存在 u*w = 0,v*w = 0 公式(b);
由于u*w = 0、v*w = 0,将w = -tc*v + w0 + sc*u 带入公式(b)得:
(u*u)*sc - (u*v)*tc = -u*w0 (公式2)
(v*u)*sc - (v*v)*tc = -v*w0 (公式3)
3、再将前式(a)带入可得sc=(be-cd)/(ac-b²)、tc=(ae-bd)/(ac-b²) 公式(c)
注意到ac-b2=|u|²|v|²-(|u||v|cosQ)²=(|u||v|sinQ)²不小于0
所以可以根据公式(c)判断sc、tc符号和sc、tc与1的关系即可分辨最近点是否在线段内
4、当ac-b2=0时,(公式2)(公式3)独立,表示两条直线平行。可令sc=0单独解出tc
5、最短距离最终就是w向量的模长
function CalcuateDistance() {/**计算空间两条直线之间的最短距离 */getShortDistance (firstLineData:any, secondLineData:any) {/**第一条线段对应起终点的坐标 */var x1 = firstLineData.startX;var y1 = firstLineData.startY;var z1 = firstLineData.startZ;var x2 = firstLineData.endX;var y2 = firstLineData.endY;var z2 = firstLineData.endZ;/**第二条线段对应起终点的坐标*/var x3 = secondLineData.startX;var y3 = secondLineData.startY;var z3 = secondLineData.startZ;var x4 = secondLineData.endX;var y4 = secondLineData.endY;var z4 = secondLineData.endZ;var ux = x2 - x1;var uy = y2 - y1;var uz = z2 - z1;var vx = x4 - x3;var vy = y4 - y3;var vz = z4 - z3;var wx = x1 - x3;var wy = y1 - y3;var wz = z1 - z3;/**根据公式(a)计算出对应的数值 */var a = (ux * ux + uy * uy + uz * uz); //u*uvar b = (ux * vx + uy * vy + uz * vz); //u*vvar c = (vx * vx + vy * vy + vz * vz); //v*vvar d = (ux * wx + uy * wy + uz * wz); //u*w var e = (vx * wx + vy * wy + vz * wz); //v*wvar dt = a * c - b * b;var sd = dt;var td = dt;/**sn = be - cd */var sn = 0.0;/**tn = ae - bd */var tn = 0.0;if (CalcuateDistance.IsEqual(dt, 0.0)) {/**若dt为0,这说明两条线重合或者平行(三角函数的相关知识) */sn = 0.0; //在s上指定取s0sd = 1.00; //防止计算时除0错误tn = Math.E; //按(公式3)求tctd = c;} else {sn = (b * e - c * d);tn = (a * e - b * d);if (sn < 0.0) {sn = 0.0;tn = e;td = c;} else if (sn > sd) {//最近点在s终点以外(即sc>1,则取sc=1)sn = sd;tn = Math.E + b; //按(公式3)计算td = c;}};if (tn < 0.0) {//最近点在t起点以外tn = 0.0;if (-d < 0.0) //按(公式2)计算,如果等号右边小于0,则sc也小于零,取sc=0sn = 0.0;else if (-d > a) //按(公式2)计算,如果sc大于1,取sc=1sn = sd;else {sn = -d;sd = a;}} else if (tn > td) {tn = td;if ((-d + b) < 0.0)sn = 0.0;else if ((-d + b) > a)sn = sd;else {sn = (-d + b);sd = a;}};var sc = 0.0;var tc = 0.0;if (CalcuateDistance.IsEqual(sn, 0.0))sc = 0.0;elsesc = sn / sd;if (CalcuateDistance.IsEqual(tn, 0.0))tc = 0.0;elsetc = tn / td;/**最终计算W向量的模长,即为空间两条线段的最短距离 */var dx = wx + (sc * ux) - (tc * vx);var dy = wy + (sc * uy) - (tc * vy);var dz = wz + (sc * uz) - (tc * vz);var MinDis = Math.sqrt(dx * dx + dy * dy + dz * dz);var distance = MinDis.toFixed(3);/**两条管线相聚最近上面的点坐标 */let minPoint1X = x1 + (sc * ux);let minPoint1Y = y1 + (sc * uy);let minPoint1Z = z1 + (sc * uz);let minPoint2X = x3 + (tc * vx);let minPoint2Y = y3 + (tc * vy);let minPoint2Z = z3 + (tc * vz);let obj = {distance:distance,point1:{x:minPoint1X,y:minPoint1Y,z:Number(minPoint1Z.toFixed(3))},point2:{x:minPoint2X,y:minPoint2Y,z:Number(minPoint2Z.toFixed(3))},}return obj;},/*** @description 判断是否相等* @param d1 * @param d2 * @returns */IsEqual(d1:number, d2:number):boolean {if (Math.abs(d1 - d2) < Math.pow(10, -7)) {return true;} else {return false;}}
}