cesium.js视锥随卫星模型的航向,俯仰和横滚而变化,并且视锥的顶点位置保持不变

问题描述

我想用圆锥形表示卫星模型的正射影像,圆锥形随卫星模型的航向,俯仰和横滚而变化,圆锥的顶点位置保持不变。 效果类似于http://cesium.marsgis.cn/cesium-example/editor.html#27_space_satellite

这是一种根据我的需要查找我编写的圆锥矩阵的方法。当我仅更改音高值时,可以正确绘制圆锥体,并且同时更改音高和横滚时,圆锥体顶点会发生变化。 我知道它需要按偏移量计算,但是我不知道如何为任何滚动值计算正确的偏移量?

computedModelMatrix(position,attitude,length){
        //position Represents the latitude,longitude and altitude of the satellite,attitude represents 
        //the heading of the satellite,pitch,roll,length represents the length of the cone
        let oldZ = length/2;
        let oldLongitude=position.longitude;
        let oldLatitude=position.latitude;
        let roll=attitude.roll;
        let pitch=attitude.pitch;
        let headingradians=Cesium.Math.toradians(roll);
        let rollradians=Cesium.Math.toradians(roll);
        let pitchradians=Cesium.Math.toradians(pitch);
        let newLongitude:number,newLatitude:number,newAltitude: number;
        let L=oldZ/Math.cos(rollradians)/Math.cos(pitchradians);
        let deg=Math.acos(oldZ/L);
        let distance =oldZ*Math.tan(deg);
        let x=(oldZ*Math.tan(pitch));
        let y=(oldZ*Math.tan(roll));
        let angle;
        if (roll>=0&&pitch>=0){
            //夹角在0-90度
            if (pitch==0&&roll==0){
                angle=0;
            } else if (pitch==0){
                angle=0
            } else if (roll==0){
                angle=90;
            }else{
                angle =Math.atan(x/y);
            }
        }
        else if (pitch>0&&roll<0) {
            angle =Math.atan(y/x)+90;
        }
        else if (pitch<0&&roll<0){
            angle=Math.atan(x/y)+180;
        }
        else{
            angle=Math.atan(y/x)+270;
        }
        newAltitude=oldZ;
        //Find the longitude and latitude of another point by angle and distance
        let resultPisiotion =GetPosition.computerThatLonLat(oldLongitude,oldLatitude,angle,distance);
        newLongitude=resultPisiotion.lon;
        newLatitude=resultPisiotion.lat;
        let centerOnEllipsoid = Cesium.Cartesian3.fromdegrees(newLongitude,newLatitude,newAltitude);
        let hpr = new Cesium.headingPitchRoll(headingradians,pitchradians,rollradians);
        let result ={
            modelMatrix:Cesium.Transforms.headingPitchRollToFixedFrame(centerOnEllipsoid,hpr),length:2*L
        };
        return result;
    }

解决方法

computedModelMatrix(Cartesian3: any,attitude: any,length: any) {
        //锥体距离卫星的高度
        let oldLength = length / 2;
        let centerCartesian3 = new Cesium.Cartesian3(Cartesian3.x,Cartesian3.y,Cartesian3.z);
        let oldX = 0,oldY = 0,oldZ = -oldLength,newX = 0,newY = 0,newZ = 0;
        let heading = attitude.heading;
        //规定顺时针为正旋转,正东方向为0度
        if (heading < 0) {
            heading = heading + 360;
        }
        let roll = attitude.roll;
        let pitch = attitude.pitch;
        let headingRadians = Cesium.Math.toRadians(heading);
        let pitchRadians = Cesium.Math.toRadians(pitch);
        let rollRadians = Cesium.Math.toRadians(roll);
        let hpr = new Cesium.HeadingPitchRoll(headingRadians,pitchRadians,rollRadians);
        let orientation = Cesium.Transforms.headingPitchRollQuaternion(centerCartesian3,hpr);
        //旋转roll
        newY = oldY + oldLength * Math.sin(rollRadians);
        newZ = oldZ + oldLength - oldLength * Math.cos(rollRadians);
        let pitchTouying = oldLength * Math.cos(rollRadians);//进行pitch变化时在Y轴和Z轴组成的平面的投影
        //旋转pitch
        newX = oldX + pitchTouying * Math.sin(pitchRadians);
        newZ = newZ + (pitchTouying - pitchTouying * Math.cos(pitchRadians));
        if (heading != 0) {
            let headingTouying = Math.sqrt(Math.pow(Math.abs(newX),2) + Math.pow(Math.abs(newY),2));//进行heading变化时在Y轴和X轴组成的平面的投影
            //旋转heading
            let Xdeg = Cesium.Math.toDegrees(Math.acos(Math.abs(newX) / Math.abs(headingTouying)));//现有投影线与X轴的夹角
            let newXdeg = 0;//旋转heading后与X轴的夹角
            let newXRadians = 0;//旋转heading后与X轴的夹角弧度
            if (newX >= 0 && newY >= 0) {
                newXdeg = heading - Xdeg;
            } else if (newX > 0 && newY < 0) {
                newXdeg = heading + Xdeg;
            } else if (newX < 0 && newY > 0) {
                newXdeg = heading + (180 + Xdeg);
            } else {
                newXdeg = heading + (180 - Xdeg)
            }
            if (newXdeg >= 360) {
                newXdeg = 360 - newXdeg;
            }
            if (newXdeg >= 0 && newXdeg <= 90) {
                newXRadians = Cesium.Math.toRadians(newXdeg);
                newY = -headingTouying * Math.sin(newXRadians);
                newX = headingTouying * Math.cos(newXRadians);
            } else if (newXdeg > 90 && newXdeg <= 180) {
                newXRadians = Cesium.Math.toRadians(180 - newXdeg);
                newY = -headingTouying * Math.sin(newXRadians);
                newX = -headingTouying * Math.cos(newXRadians)
            } else if (newXdeg > 180 && newXdeg <= 270) {
                newXRadians = Cesium.Math.toRadians(newXdeg - 180);
                newY = headingTouying * Math.sin(newXRadians);
                newX = -(headingTouying * Math.cos(newXRadians))
            } else {
                newXRadians = Cesium.Math.toRadians(360 - newXdeg);
                newY = headingTouying * Math.sin(newXRadians);
                newX = headingTouying * Math.cos(newXRadians)
            }
        }
        let offset = new Cesium.Cartesian3(newX,newY,newZ);
        let newPosition = this.computeOffset(centerCartesian3,offset);
        return Cesium.Matrix4.fromTranslationQuaternionRotationScale(newPosition,orientation,new Cesium.Cartesian3(1,1,1))
    }
computeOffset(Cartesian3: any,offset: any) {
        let enuTransform = Cesium.Transforms.eastNorthUpToFixedFrame(Cartesian3);
        Cesium.Matrix4.multiplyByPointAsVector(enuTransform,offset,offset);
        return Cesium.Cartesian3.add(Cartesian3,new Cesium.Cartesian3());
    }