简体   繁体   English

使用 Cesium.js 围绕顶点旋转锥体

[英]Cone rotation around apex with Cesium.js

I am trying to rotate a cone from its apex, rather than its centre, so that the apex remains in the same position.我试图从它的顶点而不是它的中心旋转一个圆锥体,以便顶点保持在相同的位置。

I've found the example below from the following link: https://groups.google.com/forum/#!topic/cesium-dev/f9ZiSWPMgus我从以下链接中找到了以下示例: https : //groups.google.com/forum/#!topic/cesium-dev/f9Z​​iSWPMgus

But it only shows how to rotate the cone by 90 degrees, if you choose a different value for roll, like 45 or 30 degrees, it gets skewed, and the apex ends up in the wrong place.但它只显示了如何将锥体旋转 90 度,如果您为滚动选择不同的值,例如 45 或 30 度,它会倾斜,并且顶点最终位于错误的位置。

I know its something to do with the offset, but can't make any progress from there.我知道它与偏移量有关,但无法从那里取得任何进展。 Is there some way to calculate the correct offset for any value of roll?有什么方法可以计算任何滚动值的正确偏移量?

I'd also like to extend the length of the cone when its rotated, so that when its rotated 30 degrees for example, the bottom of the cone will still reach the ground in that direction, while the apex still remains in its original place, I don't know how feasible that is though.我还想在旋转时延长锥体的长度,例如,当它旋转 30 度时,锥体的底部仍会沿该方向到达地面,而顶点仍保留在其原始位置,我不知道这有多可行。

Here's a glitch of the code sample below: https://glitch.com/edit/#!/cesium-cone-rotation这是下面代码示例的一个小故障: https ://glitch.com/edit/#!/cesium-cone-rotation

var viewer = new Cesium.Viewer('cesiumContainer');

var position = Cesium.Cartesian3.fromDegrees(-75, 40, 90); 

//Original, non-rotated cone for comparison.
viewer.entities.add(new Cesium.Entity({
    position: position,
    point: {
        color: Cesium.Color.YELLOW,
        show: true,
        pixelSize: 20
    },
    cylinder: {
        topRadius: 0,
        bottomRadius: 45,
        length: 180,
        material: Cesium.Color.YELLOW.withAlpha(0.5)
    }
}));

var heading = Cesium.Math.toRadians(0.0);
var pitch = Cesium.Math.toRadians(0.0);
var roll = Cesium.Math.toRadians(90.0);
var hpr = new Cesium.HeadingPitchRoll(heading, pitch, roll);

//Create a rotation
var orientation = Cesium.Transforms.headingPitchRollQuaternion(position, hpr);

// offset the rotation so it's rotating from the apex of the cone, instead of the centre
var offset = new Cesium.Cartesian3(0, 90, 90);

//Create a transform for the offset.
var enuTransform = Cesium.Transforms.eastNorthUpToFixedFrame(position);

//Transform the offset
Cesium.Matrix4.multiplyByPointAsVector(enuTransform, offset, offset);

//Add the offset to the original position to get the final value.
Cesium.Cartesian3.add(position,  offset,  position);

viewer.entities.add(new Cesium.Entity({
    position: position,
    orientation: orientation,
    point: {
        color: Cesium.Color.YELLOW,
        show: true,
        pixelSize: 20
    },
    cylinder: {
        topRadius: 0,
        bottomRadius: 45,
        length: 180,
        material: Cesium.Color.YELLOW.withAlpha(0.5)
    }
}));

viewer.zoomTo(viewer.entities);

Here's what I came up with to rotate and translate a cylinder when you want to point it in a specific orientation specified by an azimuth and elevation.当您想将圆柱体指向由方位角和仰角指定的特定方向时,这是我想出的旋转和平移圆柱体的方法。

/**
 * Calculate the position and orientation needed for the beam entity.
 * @param {Cesium.Cartesian3} position - The position of the desired origin.
 * @param {Number} az - The azimuth of the beam center in radians.
 * @param {Number} el - The elevation of the beam center in radians.
 * @param {Number} range - The range of the beam in meters.
 * 
 * @returns {[Cesium.Cartesian3, Cesium.Quaternion]} Array of the position and
 * orientation to use for the beam.
 */
calculateBeam(position, az, el, range) {
    // The origin of Cesium Cylinder entities is the center of the cylinder.
    // They are also pointed straight down towards the local East-North plane. The
    // math below rotates and translates the cylinder so that its origin is the tip
    // of the cylinder and its orientation is pointed in the direction specified by
    // the az/el.
    let heading = az - Cesium.Math.toRadians(90);
    let pitch = Cesium.Math.toRadians(90) + el;
    let hpr = new Cesium.HeadingPitchRoll(heading, pitch, 0.0);
    let x = range/2.0 * Math.sin(pitch) * Math.cos(heading);
    let y = -range/2.0 * Math.sin(heading) * Math.sin(pitch);
    let z = -range/2.0 * Math.cos(pitch);
    var offset = new Cesium.Cartesian3(x, y, z);
    let enuTransform = Cesium.Transforms.eastNorthUpToFixedFrame(position);
    Cesium.Matrix4.multiplyByPointAsVector(enuTransform, offset, offset);
    let newPosition = Cesium.Cartesian3.add(position, offset, new Cesium.Cartesian3());
    let orientation = Cesium.Transforms.headingPitchRollQuaternion(position, hpr);
    return [newPosition, orientation];
}

This will give you the position/orientation to use when you create the cylinder entity.这将为您提供创建圆柱实体时要使用的位置/方向。 It will place the cylinder such that the tip of the cylinder is located at 'position' and it is pointed in the direction specified by the azimuth and elevation.它将放置圆柱体,使圆柱体的尖端位于“位置”,并指向方位角和仰角指定的方向。 Azimuth is relative to North with positive angles towards East.方位角是相对于北向东的正角。 Elevation is relative to the North-East plane, with positive angles up.高程相对于东北平面,正角向上。 Range is the length of the cylinder.范围是圆柱体的长度。

This doesn't get you the behavior you wanted as far as lengthening the cylinder as you rotate it, but hopefully it helps.就在旋转圆柱体时延长圆柱体而言,这并不能满足您想要的行为,但希望它有所帮助。

I have the same problem as you.我和你有同样的问题。 This is my reference code.这是我的参考代码。 This is a function of computing the matrix of a cone at any angle.这是计算任何角度的锥体矩阵的函数。

 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, offset, new Cesium.Cartesian3());
    }

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM