Cesium 二三维视图联动

近期做了二三维视图联动,简单记录一下。

主要功能就是同时开启二维和三维视图一起查看。

大概思路就是新创建一个 2D 视图,相机实时同步(其实部分资源也应该同步,不过这需要做一个数据状态管理的功能,让数据在两个视图同步,懒得做了,后面要做资源管理的功能再说吧)。

二维和三维视图其实相机焦点是有区别的,因为二维视图只有平移和缩放,没有旋转,故如何正确找到三维视图中的相机焦点是关键。

方法一:获取屏幕中心坐标,转为世界坐标

// canvas 中心位置为相机焦点
let viewCenter = new Cesium.Cartesian2(
    Math.floor(this.#viewer3D.canvas.clientWidth / 2),
    Math.floor(this.#viewer3D.canvas.clientHeight / 2)
);

// 给定中心的像素,获取世界位置
let worldPosition = this.#viewer3D.scene.camera.pickEllipsoid(
    viewCenter,
    this.#viewer3D.scene.globe.ellipsoid
);

方法二:通过射线求交获取坐标

构建射线:

// 构建相机射线
let ray = new Cesium.Ray(
    this.#viewer3D.camera.positionWC,
    this.#viewer3D.camera.directionWC
);

求射线与椭球交点:

方法1:

使用IntersectionTests,获取射线与椭球交点,注意,Intercal 属性包括两个标量,因为交点应该是两个,正面与反面,我们取正面的交点,然后通过 getPoint 方法获取具体坐标

let interval = Cesium.IntersectionTests.rayEllipsoid(
    ray,
    this.#viewer3D.scene.globe.ellipsoid
);
let worldPosition = Cesium.Ray.getPoint(ray, interval.start);

方法2:

 使用 global 中的 pick 方法直接获取

let worldPosition = this.#viewer3D.scene.globe.pick(
    ray,
    this.#viewer3D.scene
)

其实方法还有很多,不一一列举了

获取到坐标后,我们需要获取缩放距离

 Cartesian3 提供了计算方法,我们只需要计算出高度,设置 camera 即可

// 同步相机视角
if (Cesium.defined(worldPosition)) {
    // 计算高度
    let distance = Cesium.Cartesian3.distance(
        worldPosition!,
        this.#viewer3D.camera.positionWC
    );
    this.#viewer2D!.camera.lookAt(
        worldPosition!,
        new Cesium.Cartesian3(0, 0, distance)
    );
}

若想只保存 3D 视图的移动,让 2D 视图跟随,也可关闭 2D 视图的鼠标控制

// 禁止移动缩放
this.#viewer2D.scene.screenSpaceCameraController.enableZoom = false;
this.#viewer2D.scene.screenSpaceCameraController.enableTranslate = false;

若想更换其他厂商的地图,直接在新建 viewer 时设置即可

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

posted @ 2023-01-20 00:20  邢韬  阅读(959)  评论(0编辑  收藏  举报