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,谢谢。