MapGIS Objects Java判断一条三维线段是否穿过一个三角形

计算一条三维线段与一个三角形所在的平面的交点

一、介绍

MapGIS Objects SDK : 是一款组件式地理信息开发平台,提供全空间数据存储、管理、显示、编辑、查询、分析、制图输出等二三维一体化核心 GIS 功能,提供 C++、.NET、Java、Python 等开发资源,接口简单易用,性能优越,具备跨平台开发能力。

本篇内容将引导您如何使用 MapGIS Objects SDK 实现如何在三维场景中根据一个三维点计算其到一条三维线段的垂足点。

二、开发环境

软件版本下载地址说明
MapGIS 10 x64 All In One SDK for Windows10.7开发包下载地址MapGIS 提供的一款地理信息开发平台,包含 MapGIS Objects Java 面向 Java 开发环境的跨平台组件式 GIS 开发资源。
MapGIS 开发授权\开发授权下载地址MapGIS 针对开发者提供开发授权,下载开发包并安装后,还需要获取开发授权才能正常使用。
IntelliJ IDEA2020.3 以上版本IDEA 下载地址一款适用于 Java 专业开发的集成开发环境(IDE)。
JDK1.8JDK 下载地址JDK 是 Java 语言的软件开发工具包,JDK 是整个 java 开发的核心,它包含了 JAVA 的运行环境(JVM+Java 系统类库)和 JAVA 工具。

三、几何原理

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传
​ 判断一条三维线段是否穿过某个三角形,可以通过先判断这条线段是否与三角形所在的平面是否相交,如果相交则计算其交点,然后再判断该交点是否在三角形的边界或者内部。计算线段与平面交点的算法在前面的文章中已经详细进行了说明,在这里不再赘述,而判断线段与平面的交点是否在三角形内,可以通过面积法来解决,面积法的主要方案如上图所示,如果线段与平面的交点 P 在三角形 ABC 内部或者三角形的边界上,需要满足大三角形的面积等于三个小三角形面积之和,即 S/∆ABC=S/∆PAB+S/∆PAC+S/∆PBC(S/∆ABC 表示三角形 ABC 的面积,S/∆PAB、S/∆PBC、S/∆PAC 类似),即 1=S/∆PAB/S/∆ABC+S/∆PAC/S/∆ABC+S/∆PBC/S/∆ABC,即可推导出=> α=S/∆PAB/S/∆ABC,β=S/∆PAC/S/∆ABC,γ=S/∆PBC/S/∆PAB,α+β+γ=1 。其中三角形的面积可根据向量的叉乘得到,α=|PA×PB|/2,β 和 γ 也可同样计算出,因此要确定一个点是否在三角形的边界或里面,只需要保证 α>0、β>0、γ>0,且 α+β+γ=1 即可。

四、算法实现

本篇以 MapGIS Objects Java 实现算法的基本思想,对于 MapGIS Objects Java 的开发入门在此不做赘述,详情可参考MapGIS Objects Java 的开发入门文档,api 文档参考 MapGIS Objects Java API

1.实现向量叉乘

    public Dot3D crossMultiVector(Dot3D dot1,Dot3D dot2){
        Dot3D rDot = new Dot3D();
        rDot.setX(dot1.getY() * dot2.getZ() - dot1.getZ() * dot2.getY());
        rDot.setY(dot1.getZ() * dot2.getX() - dot1.getX() * dot2.getZ());
        rDot.setZ(dot1.getX() * dot2.getY() - dot1.getY() * dot2.getX());
        return rDot;
    }

2.计算单位法向量

    public Dot3D computerNormal(Dot3D dotA,Dot3D dotB,Dot3D dotC){
        //向量AB
        Dot3D ab = new Dot3D();
        ab.setX(dotB.getX()-dotA.getX());
        ab.setY(dotB.getY()-dotA.getY());
        ab.setZ(dotB.getZ()-dotA.getZ());
        //向量AC
        Dot3D ac = new Dot3D();
        ac.setX(dotC.getX()-dotA.getX());
        ac.setY(dotC.getY()-dotA.getY());
        ac.setZ(dotC.getZ()-dotA.getZ());
        //向量叉乘计算法向量
        Dot3D pNormal=crossMultiVector(ab,ac);
        //计算法向量模长
        double len = Math.sqrt(Math.pow(pNormal.getX(),2)+Math.pow(pNormal.getY(),2)+Math.pow(pNormal.getZ(),2));
        //计算单位法向量
        pNormal.setX(pNormal.getX()/len);
        pNormal.setY(pNormal.getY()/len);
        pNormal.setZ(pNormal.getZ()/len);
        return  pNormal;
    }

3.计算点到平面的距离

    //通过点法式构建平面方程计算点到平面距离
    public double computerDistanceToPlane(Dot3D pNormal,Dot3D dotPlane,Dot3D dotP){
        double nx = pNormal.getX();
        double ny = pNormal.getY();
        double nz = pNormal.getZ();
        double len =nx*dotP.getX()+ny*dotP.getY()+nz*dotP.getZ()-(nx*dotPlane.getX()+ny*dotPlane.getY()+nz*dotPlane.getZ());
        return len;
    }

4.判断线段是否与平面相交

    public boolean isIntersectWithPlane(Dot3D sDot,Dot3D eDot,Dot3D planeDot1,Dot3D planeDot2,Dot3D planeDot3){
        //1、计算平面单位法向量
        Dot3D pNormal = computerNormal(planeDot1,planeDot2,planeDot3);
        //2、计算线段的两个端点到平面距离
        double len1 = computerDistanceToPlane(pNormal,planeDot1,sDot);
        double len2 = computerDistanceToPlane(pNormal,planeDot1,eDot);
        //3、判断线段是否与平面相交
        if(len1*len2>0){
            return  false;
        }
        else{
            return  true;
        }
    }

5.计算线段与平面的交点

    public Dot3D ComputerIntersectDotInPlane(Dot3D sDot,Dot3D eDot,Dot3D planeDot1,Dot3D planeDot2,Dot3D planeDot3){
        //1、计算平面单位法向量
        Dot3D pNormal = computerNormal(planeDot1,planeDot2,planeDot3);
        //2、计算线段的两个端点到平面距离
        double len1 = computerDistanceToPlane(pNormal,planeDot1,sDot);
        double len2 = computerDistanceToPlane(pNormal,planeDot1,eDot);
        //3、线性插值计算交点
        if(len1<1e-3){
            return  sDot;
        }
        if(len2<1e-3){
            return eDot;
        }
        if(len1*len2<0){
            double t = -len1 / (len2 - len1);
            Dot3D pDot = new Dot3D();
            pDot.setX(sDot.getX()+t*(eDot.getX()-sDot.getX()));
            pDot.setY(sDot.getY()+t*(eDot.getY()-sDot.getY()));
            pDot.setZ(sDot.getZ()+t*(eDot.getZ()-sDot.getZ()));
            return  pDot;
        }
        else{
            return  null;
        }
    }

6.判断交点是否在三角形内

    public double ComputerTriangleArea(Dot3D dot1,Dot3D dot2,Dot3D dot3){
        Dot3D ab = new Dot3D();
        Dot3D ac = new Dot3D();
        ab.setX(dot2.getX()-dot1.getX());
        ab.setY(dot2.getY()-dot1.getY());
        ab.setZ(dot2.getZ()-dot1.getZ());
        ac.setX(dot3.getX()-dot1.getX());
        ac.setY(dot3.getY()-dot1.getY());
        ac.setZ(dot3.getZ()-dot1.getZ());
        Dot3D rDot = crossMultiVector(ab,ac);
        double len = Math.sqrt(rDot.getX()*rDot.getX()+rDot.getY()*rDot.getY()+rDot.getZ()*rDot.getZ());
        return  len/2.0;
    }
    public boolean isInTriangle(Dot3D dotA,Dot3D dotB,Dot3D dotC,Dot3D dotP){
       //1.计算三角形ABC的面积
        double Sabc = ComputerTriangleArea(dotA,dotB,dotC);
       //2.计算三角形PAB的面积
        double Spab = ComputerTriangleArea(dotP,dotA,dotB);
       //3.计算三角形PBC的面积
        double Spbc = ComputerTriangleArea(dotP,dotB,dotC);
       //4.计算三角形PAC的面积
        double Spac = ComputerTriangleArea(dotP,dotA,dotC);

        double α = Spab/Sabc;
        double β = Spbc/Sabc;
        double γ = Spac/Sabc;
        return  α>=0 && β>=0 && γ>=0 && Math.abs(α+β+γ-1)<1e-3;
    }
    ab.setZ(dot2.getZ()-dot1.getZ());
    ac.setX(dot3.getX()-dot1.getX());
    ac.setY(dot3.getY()-dot1.getY());
    ac.setZ(dot3.getZ()-dot1.getZ());
    Dot3D rDot = crossMul
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值