threejs计算两条线段的交点和距离点最近的线段

threejs 创建的三维空间中,可以计算两条线段是否有交点,或者线段的延长线是否有交点,使用其中一条线段创建射线,使用另一条线段创建平面,获取射线和平面的交点就可以了。

还可以在三维空间的某个点上计算最近的线段,分别计算点到线段的距离就可以了。

下面是参考代码:


// 获取两条线的交点
var getPublicDot = function ( line1Dot, line1Direction, line2Dot, line2Direction ) {

    var dotPublic = new THREE.Vector3('x', 'y', 'z');

    function run () {
        var ray = new THREE.Ray( line1Dot, line1Direction );
        var line2DotPro = line2Dot.clone();
        var line2Vertical = line2Direction.clone();
        line2Vertical.applyAxisAngle(new THREE.Vector3(0, 1, 0), Math.PI/2);
        line2DotPro.projectOnVector(line2Vertical);
        var line2Pos = (line2DotPro.x * line2Vertical.x > 0 ? -1 : 1) * line2DotPro.distanceTo(new THREE.Vector3(0, 0, 0));
        var plane2 = new THREE.Plane( line2Vertical, line2Pos );
        ray.intersectPlane( plane2, dotPublic );
    }
    run();

    if ( dotPublic.x !== 'x' ) {
        return dotPublic;
    } else {

        line1Direction.applyAxisAngle(new THREE.Vector3(0, 1, 0), Math.PI);
        run();
        line1Direction.applyAxisAngle(new THREE.Vector3(0, 1, 0), Math.PI);

        if ( dotPublic.x !== 'x' ) {
            return dotPublic;
        } else {
            console.log('无法获取交点:', dotPublic);
            return null;
        }

    }

}

// 获取最近的线段
var getCloseLine = function ( dot, lines, refer ) {

    var lineDirection, lineVertical, lenMin, lineMin, dotPro, dotMin,
        dotProDir1, dotProDir2, check = false, dots, axisY = new THREE.Vector3(0, 1, 0);

    for (var i = 0, il = lines.length; i < il; i++) {

        dots = refer.getObjDots( lines[i] );

        for (var j = 0, jl = dots.length; j < jl-1; j++) {

            lineDirection = dots[j+1].clone();
            lineDirection = lineDirection.sub(dots[j]);
            lineVertical = lineDirection.clone();
            lineVertical.applyAxisAngle(axisY, Math.PI/2);
            lineDirection.normalize();
            lineVertical.normalize();

            dotPro = dot.clone();
            dotPro.projectOnPlane(lineVertical);
            dotPro.sub(dot);
            dotPro = refer.getPublicDot(dot, dotPro, dots[j], lineDirection);
            if (!dotPro) return null;

            dotProDir1 = dotPro.clone();
            dotProDir2 = dotPro.clone();
            dotProDir1.sub(dots[j]);
            dotProDir2.sub(dots[j+1]);
            dotProDir1.normalize();
            dotProDir2.normalize();
            check = dotProDir1.dot(dotProDir2);

            if ( ( !lenMin || lenMin > dotPro.distanceTo(dot) ) && (check.toFixed(4) === '-1.0000') ) {
                lenMin = dotPro.distanceTo(dot);
                lineMin = lines[i];
                dotMin = dotPro.clone();
            }

        }

    }

    if (lenMin) {
        return {
            dot: dotMin,
            line: lineMin
        };
    } else {
        return null;
    }

}

// 查找模型的端点
var getObjDots = function ( obj, refer ) {

    var dots = [], dotAll, dotTemp;

    if ( obj.geometry.type === 'Geometry' ) {
        dotAll = obj.geometry.vertices;
        for (var i = 0, il = dotAll.length; i < il; i++) {
            dotTemp = dotAll[i].clone();
            obj.localToWorld( dotTemp );

            if ( !refer ) {
                dots.push( dotTemp );
            } else if ( dotTemp[refer.axis] <= refer.max && dotTemp[refer.axis] >= refer.min ) {
                dots.push( dotTemp );
            }
        }
    } else if ( obj.geometry.type === 'BufferGeometry' ) {
        dotAll = obj.geometry.attributes.position;
        dotTemp = new THREE.Vector3();
        for (var i = 0, il = dotAll.count * 3; i < il; i+=3) {
            dotTemp.set(dotAll.array[i], dotAll.array[i+1], dotAll.array[i+2]);
            obj.localToWorld( dotTemp );

            if ( !refer ) {
                dots.push( dotTemp.clone() );
            } else if ( dotTemp[refer.axis] <= refer.max && dotTemp[refer.axis] >= refer.min ) {
                dots.push( dotTemp.clone() );
            }
        }
    }

    return dots;

}

  • 4
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

codehuicn

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值