Cesium 几何编辑

最近做了个Cesium几何编辑的功能,通过鼠标画点线面等,记录一下问题

感兴趣的朋友可以移步:LiZzhi/cesium-plugin (github.com)

功能本身不难,无非就是封装鼠标事件,记录好数据,随时可以撤销,清除。

在做画矩形时,一些坐标转换的操作折腾了我挺久(学测绘的让坐标转换绕蒙圈属实有点丢人了。。。)。

封装一个方法,通过三个点确定一个矩形,大概的需求就是前两个点固定了一条边以后,第三个点要投影到固定边的法线上,并算出第四个点。

开始通过向量和三角函数计算,但是结果总有点小问题,后来索性直接翻CesiumAPI,发现利用Transforms基本就可以解决所有问题。

先说思路:

如下图,一次绘制 A、B、C 三点,C 点投影至 向量 AB 的法线上,确定 C1,再计算 D1

( 此处坐标轴只是为了易懂,并非真正的坐标系 )

思路有了,就该上代码了,首先要借助 Cesium 中的 Transforms API,将世界坐标系转为以 A 为原点,AB 为X轴的局部坐标系

headingPitchRollToFixedFrame 允许我们通过设置原点,姿态角等参数构建旋转矩阵

 首先我们先构建姿态角

function getHeadingPitch(pointA: Cartesian3, pointB: Cartesian3): number[]{
    // 建立以点A为原点,X轴为east,Y轴为north,Z轴朝上的坐标系
    let transform = Cesium.Transforms.eastNorthUpToFixedFrame(pointA);
    // 向量AB
    let positionvector = Cesium.Cartesian3.subtract(pointB, pointA, new Cesium.Cartesian3());
    // 因transform是将A为原点的eastNorthUp坐标系中的点转换到世界坐标系的矩阵
    // AB为世界坐标中的向量
    // 因此将AB向量转换为A原点坐标系中的向量,需乘以transform的逆矩阵。
    let vector = Cesium.Matrix4.multiplyByPointAsVector(Cesium.Matrix4.inverse(transform, new Cesium.Matrix4()), positionvector, new Cesium.Cartesian3());
    // 归一化
    let direction = Cesium.Cartesian3.normalize(vector, new Cesium.Cartesian3());
    // heading
    let heading = Math.atan2(direction.y, direction.x) - Cesium.Math.PI_OVER_TWO;
    heading = Cesium.Math.TWO_PI - Cesium.Math.zeroToTwoPi(heading)
    // pitch
    let pitch = Cesium.Math.PI_OVER_TWO - Cesium.Math.acosClamped(direction.z)
    return [heading, pitch]
}

然后构建旋转矩阵

let [heading, pitch] = getHeadingPitch(pointA, pointB)

let hpr = new Cesium.HeadingPitchRoll(heading, pitch, 0)
let localToWorldMatrix = Cesium.Transforms.headingPitchRollToFixedFrame(
    pointA, hpr, e
)

// 世界坐标系到局部坐标系的变换矩阵
let worldToLocalMatrix = Cesium.Matrix4.inverse(
    localToWorldMatrix,
    new Cesium.Matrix4()
);

然后计算局部坐标系中,C1 和 D 的坐标,并转为世界坐标系

// pointB,pointC 转局部坐标
let localPosB = Cesium.Matrix4.multiplyByPoint(
    worldToLocalMatrix,
    pointB,
    new Cesium.Cartesian3()
);    

let localPosC = Cesium.Matrix4.multiplyByPoint(
    worldToLocalMatrix,
    pointC,
    new Cesium.Cartesian3()
);
let localPosC1 = new Cesium.Cartesian3(localPosC.x , localPosB.y)
let localPosD = new Cesium.Cartesian3(localPosC.x, 0)

// C1,D 世界坐标
let worldPointC1 = Cesium.Matrix4.multiplyByPoint(
    localToWorldMatrix, 
    localPosC1, 
    new Cesium.Cartesian3()
);
let worldPointD = Cesium.Matrix4.multiplyByPoint(
    localToWorldMatrix, 
    localPosD, 
    new Cesium.Cartesian3()
);

上述代码其实并不复杂,很好理解。

完整版请移步LiZzhi/cesium-plugin (github.com),如果对您有帮助,请给我一颗star,谢谢。

posted @ 2023-01-12 22:19  邢韬  阅读(576)  评论(0编辑  收藏  举报