欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

Three.js测量功能封装--距离、角度与面积

程序员文章站 2022-07-08 18:09:57
模型距离、角度、占地面积计算...

模型距离、角度、占地面积计算

1.获取屏幕坐标位置,转化为三维坐标位置。代码如下:

var Sx = event.clientX;//屏幕X轴坐标
var Sy = event.clientY;//屏幕Y轴坐标
var x = ( Sx / window.innerWidth ) * 2 - 1;
var
y = -( Sy / window.innerHeight ) * 2 + 1;
var
standardVector  = new THREE.Vector3(x, y, 0.5);//新建一个三维单位向量 假设z方向就是0.5

       2.需要将得到的三维向量坐标转为视点坐标系(参照是摄像机),并且创建射线,方向是选定模型点与摄像机两点的连线。代码如下:

var ray = worldVector.sub(camera.position).normalize();//在视点坐标系中形成射线,射线的起点向量是照相机, 射线的方向向量是照相机到点击的点,这个向量应该归一标准化。
var raycaster = new THREE.Raycaster(camera.position, ray);//射线和模型求交,选中直线
var intersects = raycaster.intersectObjects(name,true);

       3.依靠前两步封装测量点击事件方法。需声明一全局变量measure_distance_point=new Array()(以下称为点变量)以便保存点历史位置信息与measure_distance_draw=new Array()(以下称为模型模型变量)。当用户点击模型时,判断点变量是否为空,若为空记录点击时的x\y\z保存至点变量中,并且生成一条线段,该线段两端都为该点击点,并将生成线段添加至模型变量与场景中。当点变量不为空时 ,在测量距离中代码类似,不赘述。代码如下:

if (intersects.length > 0) {
       
if (measure_distance_point.length===0){
            measure_distance_point.
push(intersects[0].point.x);
           
measure_distance_point.push(intersects[0].point.y);
           
measure_distance_point.push(intersects[0].point.z);
           
//prative_tool_point.push(name[0].children[0].geometry.boundingBox.max.z);
           
var material = new THREE.LineBasicMaterial({color:0xFF1493,depthTest: false});//depthTest检测深度
            material.transparent=true;
           
material.opacity=0.5;
           
material.linewidth=100;
            var
geometry = new THREE.Geometry();
           
geometry.vertices.push(new THREE.Vector3(intersects[0].point.x,intersects[0].point.y,intersects[0].point.z));
           
geometry.vertices.push(new THREE.Vector3(intersects[0].point.x,intersects[0].point.y,intersects[0].point.z));
            var
line=new THREE.Line(geometry,material);
           
measure_distance_draw.push(line);
           
scene.add(line);
       
}else
           
{
                measure_distance_point.
push(intersects[0].point.x);
               
measure_distance_point.push(intersects[0].point.y);
               
measure_distance_point.push(intersects[0].point.z);
                var
material = new THREE.LineBasicMaterial({color:0xFF1493,depthTest: false});
               
material.transparent=true;
               
material.opacity=0.9;
                var
geometry = new THREE.Geometry();
               
geometry.vertices.push(new THREE.Vector3(intersects[0].point.x,intersects[0].point.y,intersects[0].point.z));
               
geometry.vertices.push(new THREE.Vector3(intersects[0].point.x,intersects[0].point.y,intersects[0].point.z));
                var
line=new THREE.Line(geometry,material);
               
measure_distance_draw.push(line);
             

          
    }
}

 

       4.需要封装测量鼠标移动事件方法。将第三步中生成的线段尾端可以实现随着鼠标移动而变化,此时需要判断模型变量是否为空,不为空就获取最后一次添加的模型的尾端点,让其跟随鼠标移动。注:此时需要打开geometry的verticesNeedUpdate为true。封装代码如下:

function Measure_Moveing(name) {
   
var Sx = event.clientX;//屏幕X轴坐标
    var Sy = event.clientY;//屏幕Y轴坐标
    var x = ( Sx / window.innerWidth ) * 2 - 1;
    var
y = -( Sy / window.innerHeight ) * 2 + 1;
    var
standardVector  = new THREE.Vector3(x, y, 0.5);//新建一个三维单位向量 假设z方向就是0.5
   
var worldVector = standardVector.unproject(camera); //根据照相机,把这个向量转换到视点坐标系
    var ray = worldVector.sub(camera.position).normalize();//在视点坐标系中形成射线,射线的起点向量是照相机, 射线的方向向量是照相机到点击的点,这个向量应该归一标准化。
    var raycaster = new THREE.Raycaster(camera.position, ray);//射线和模型求交,选中直线
    var intersects = raycaster.intersectObjects(name,true);
    if
(intersects.length > 0) {
       
if( measure_distance_draw.length>0){
           
var draw_Num=measure_distance_draw.length-1;
            var
point_Num=measure_distance_draw[draw_Num].geometry.vertices.length-1;
            
measure_distance_draw[draw_Num].geometry.vertices[point_Num].x=intersects[0].point.x;
           
measure_distance_draw[draw_Num].geometry.vertices[point_Num].y=intersects[0].point.y;
           
measure_distance_draw[draw_Num].geometry.vertices[point_Num].z=intersects[0].point.z;
           
measure_distance_draw[draw_Num].geometry.verticesNeedUpdate=true;
       
}
    }
}

 

5.算距离。直接上代码:

Math.sqrt( Math.pow(measure_distance_draw[0].geometry.vertices[0].x - measure_distance_draw[0].geometry.vertices[1].x, 2) +
       
Math.pow(measure_distance_draw[0].geometry.vertices[0].y -measure_distance_draw[0].geometry.vertices[1].y, 2)+
       
Math.pow(measure_distance_draw[0].geometry.vertices[0].z -measure_distance_draw[0].geometry.vertices[1].z, 2)),

6.效果展示

Three.js测量功能封装--距离、角度与面积

1.与距离测量类似,只是计算的是角度。以下是计算角度的代码:

var lengthAB = Math.sqrt( Math.pow(measure_distance_draw[0].geometry.vertices[0].x - measure_distance_draw[0].geometry.vertices[1].x, 2) +
       
Math.pow(measure_distance_draw[0].geometry.vertices[0].y -measure_distance_draw[0].geometry.vertices[1].y, 2)+
       
Math.pow(measure_distance_draw[0].geometry.vertices[0].z -measure_distance_draw[0].geometry.vertices[1].z, 2)),
   
lengthAC = Math.sqrt( Math.pow(measure_distance_draw[1].geometry.vertices[0].x - measure_distance_draw[1].geometry.vertices[1].x, 2) +
       
Math.pow(measure_distance_draw[1].geometry.vertices[0].y -measure_distance_draw[1].geometry.vertices[1].y, 2)+
       
Math.pow(measure_distance_draw[1].geometry.vertices[0].z -measure_distance_draw[1].geometry.vertices[1].z, 2)),
   
lengthBC = Math.sqrt( Math.pow(measure_distance_draw[0].geometry.vertices[0].x - measure_distance_draw[1].geometry.vertices[1].x, 2) +
       
Math.pow(measure_distance_draw[0].geometry.vertices[0].y - measure_distance_draw[1].geometry.vertices[1].y, 2)+
       
Math.pow(measure_distance_draw[0].geometry.vertices[0].z - measure_distance_draw[1].geometry.vertices[1].z, 2));
var
cosA = (Math.pow(lengthAB, 2) + Math.pow(lengthAC, 2) - Math.pow(lengthBC, 2)) /
    (
2 * lengthAB * lengthAC);
var
angleA = Math.round( Math.acos(cosA) * 180 / Math.PI );

2.效果展示

Three.js测量功能封装--距离、角度与面积

1.需要实时显示我们在屏幕上画出的面积,这就要实时生成面,我采用的是三角面逐一生成的方式,主要采用几个for循环去实现它,第一个循环点变量,添加到THREE.Geometry()的vertices中,最后添加我们这次点击的点,第二个循环就是要算出三点一面的法线位置了,并且基于这些点的THREE.Face3面,也将其添加到geometry的faces中,至此geometry的工作完成了。生成网格Mesh,添加到场景中即可。(鼠标移动封装方法相同)代码如下:

if ( measure_distance_point.length>0){
    scene.
remove(measure_distance_draw[0]);
   
measure_distance_point.push(intersects[0].point.x);
   
measure_distance_point.push(intersects[0].point.y);
   
measure_distance_point.push(intersects[0].point.z);
    var
material = new THREE.LineBasicMaterial({color:0xFF1493, side:THREE.DoubleSide, depthTest: false});//深度测试关闭
    material.transparent=true;
   
material.opacity=0.5;
    var
geometry = new THREE.Geometry();
   
console.log( measure_distance_point);
    for
(var i=0;i<measure_distance_point.length/3;i++){
        geometry.
vertices.push(new THREE.Vector3( measure_distance_point[3*i], measure_distance_point[3*i+1], measure_distance_point[3*i+2]));
   
}
    geometry.
vertices.push(new THREE.Vector3(intersects[0].point.x,intersects[0].point.y,intersects[0].point.z));
   
console.log(geometry.vertices);
    for
(var j=0;j<measure_distance_point.length/3-1;j++)
    {
       
var normal = Get_normal(geometry.vertices[0],geometry.vertices[j+1],geometry.vertices[j+2]);
        var
face = new THREE.Face3( 0, j+1, j+2, normal);
       
geometry.faces.push( face );
   
}
   
var mesh=new THREE.Mesh(geometry,material);
   
measure_distance_draw[0]=mesh;
   
scene.add(mesh);

}

function Get_normal(p1,p2,p3) {
   
var   a = ( (p2.y-p1.y)*(p3.z-p1.z)-(p2.z-p1.z)*(p3.y-p1.y) );
    var  
b = ( (p2.z-p1.z)*(p3.x-p1.x)-(p2.x-p1.x)*(p3.z-p1.z) );
    var   
c = ( (p2.x-p1.x)*(p3.y-p1.y)-(p2.y-p1.y)*(p3.x-p1.x) );

    return
THREE.Vector3(a,b,c);

}

 

 

2.算做出来图形的占地面积了,以z轴向上,代码如下:

var area=0.0;
for
(var j=0;j<measure_distance_draw[0].geometry.vertices.length-2;j++)
{
   
var point_1=measure_distance_draw[0].geometry.vertices[0];
    var
point_2=measure_distance_draw[0].geometry.vertices[j+1];
    var
point_3=measure_distance_draw[0].geometry.vertices[j+2];
    
area+=0.5*Math.abs(point_2.x*point_3.y+point_1.x*point_2.y+point_3.x*point_1.y-point_3.x*point_2.y-point_2.x*point_1.y-point_1.x*point_3.y);
}

3.效果展示

 Three.js测量功能封装--距离、角度与面积

本文地址:https://blog.csdn.net/weixin_40676050/article/details/107774649