Cesium地图开挖求教

65 阅读2分钟

刚入门cesium,学着社区大佬做地图开挖,代码里面不知道是哪的问题,始终无法实现,只能显示挖掘区域

import { onMounted } from "vue"
import * as Cesium from "cesium"
import "./Widgets/widgets.css"
import CesiumInitializer from "./utils/cesiumInitializer"

let viewer = null
let handler = null
let isDrawing = false
let polygonPoints = []
let polygonEntity = null
let clippingPlaneCollection = null
let globe = null

onMounted(async () => {
    viewer = await CesiumInitializer.createViewer("cesiumContainer", {
        imageryProvider: new Cesium.UrlTemplateImageryProvider({
            url: "http://www.google.cn/maps/vt?lyrs=s@716&x={x}&y={y}&z={z}"
        }),
        selectionIndicator: false,
        infoBox: false
    })
    globe = viewer.scene.globe
    globe.depthTestAgainstTerrain = true

    // 初始化裁剪平面集合
    clippingPlaneCollection = new Cesium.ClippingPlaneCollection({
        edgeWidth: 1.0,
        edgeColor: Cesium.Color.WHITE,
        enabled: true
        // unionClippingRegions: false
    })

    // 应用裁剪平面到地球并设置额外属性
    globe.clippingPlanes = clippingPlaneCollection
    globe.backFaceCulling = true // 启用背面剔除
    globe.showSkirts = true // 显示地形裙边
    globe.clippingPlanesEnabled = true

    // 初始化事件处理器
    handler = new Cesium.ScreenSpaceEventHandler(viewer.scene.canvas)

    // 绑定鼠标左键点击事件绘制多边形顶点
    handler.setInputAction((movement) => {
        const cartesian = getClickPosition(movement.position)
        if (!cartesian) return

        if (!isDrawing) {
            // 开始绘制
            startDrawing(cartesian)
        } else {
            // 添加新顶点
            addPolygonPoint(cartesian)
        }
    }, Cesium.ScreenSpaceEventType.LEFT_CLICK)

    // 绑定鼠标移动事件更新多边形
    handler.setInputAction((movement) => {
        if (isDrawing && polygonPoints.length > 0) {
            const cartesian = getClickPosition(movement.endPosition)
            if (cartesian) {
                updatePolygonPreview(cartesian)
            }
        }
    }, Cesium.ScreenSpaceEventType.MOUSE_MOVE)

    // 绑定右键点击事件挖空区域
    handler.setInputAction(() => {
        if (isDrawing) {
            // 完成绘制
            finishDrawing()
        }
    }, Cesium.ScreenSpaceEventType.RIGHT_CLICK)

    // 设置初始相机位置
    viewer.camera.setView({
        destination: Cesium.Cartesian3.fromDegrees(116.39, 39.9, 10000),
        orientation: {
            heading: Cesium.Math.toRadians(0),
            pitch: Cesium.Math.toRadians(-45),
            roll: 0
        }
    })
    // 清除多边形
    document.addEventListener("keydown", (e) => {
        if (e.key === "Escape") {
            clippingPlaneCollection.planes = []
            viewer.entities.removeAll()
        }
    })
})

// 获取点击位置的三维坐标
function getClickPosition(screenPosition) {
    const ray = viewer.camera.getPickRay(screenPosition)
    return globe.pick(ray, viewer.scene)
}

// 开始绘制多边形
function startDrawing(initialPoint) {
    isDrawing = true
    polygonPoints = [initialPoint]

    // 创建多边形实体用于预览
    polygonEntity = viewer.entities.add({
        // 创建点
        // position: initialPoint,
        // point: {
        //     pixelSize: 10,
        //     color: Cesium.Color.RED,
        //     outlineColor: Cesium.Color.WHITE,
        //     outlineWidth: 4
        // }
        polygon: {
            hierarchy: new Cesium.CallbackProperty(getPolygonHierarchy, false),
            material: Cesium.Color.BLUE.withAlpha(0.3),
            outline: true,
            outlineColor: Cesium.Color.BLACK
        }
    })
}

// 添加多边形顶点
function addPolygonPoint(point) {
    polygonPoints.push(point)
}

// 更新多边形
function updatePolygonPreview(lastPoint) {
    // 创建临时数组,包含已有顶点和当前鼠标位置
    const tempPoints = [...polygonPoints, lastPoint]
    // 更新多边形层级
    polygonEntity.polygon.hierarchy = new Cesium.CallbackProperty(() => {
        return new Cesium.PolygonHierarchy(tempPoints)
    }, false)
}

// 获取多边形层级
function getPolygonHierarchy() {
    return new Cesium.PolygonHierarchy(polygonPoints)
}

// 挖空地形
function createPolygonClipArea(points) {
    if (points.length < 3) {
        alert("至少需要3个顶点才能创建多边形裁剪区域")
        return
    }

    // 计算每个边的裁剪平面
    const clippingPlanes = []
    const pointsLength = points.length

    for (let i = 0; i < pointsLength; ++i) {
        const p1 = points[i]
        const p2 = points[(i + 1) % pointsLength]

        // 计算边的中点
        const midpoint = Cesium.Cartesian3.add(p1, p2, new Cesium.Cartesian3())
        Cesium.Cartesian3.multiplyByScalar(midpoint, 0.5, midpoint)

        // 计算法向量(使用中点和叉乘)
        const up = Cesium.Cartesian3.normalize(midpoint, new Cesium.Cartesian3())
        const right = Cesium.Cartesian3.subtract(p2, p1, new Cesium.Cartesian3())
        Cesium.Cartesian3.normalize(right, right)

        // 通过叉乘计算法向量(右手坐标系)
        let normal = Cesium.Cartesian3.cross(right, up, new Cesium.Cartesian3())
        Cesium.Cartesian3.normalize(normal, normal)

        // 计算平面距离
        const originCenteredPlane = new Cesium.Plane(normal, 0.0)
        const distance = Cesium.Plane.getPointDistance(originCenteredPlane, midpoint)

        clippingPlanes.push(new Cesium.ClippingPlane(normal, distance))
    }

    // 设置裁剪平面属性
    clippingPlaneCollection.planes = clippingPlanes
    clippingPlaneCollection.edgeWidth = 1.0
    clippingPlaneCollection.edgeColor = Cesium.Color.WHITE
    clippingPlaneCollection.enabled = true

    // 预览裁剪区域
    viewer.entities.add({
        polygon: {
            hierarchy: new Cesium.PolygonHierarchy(points),
            material: Cesium.Color.RED.withAlpha(0.3),
            outline: true,
            outlineColor: Cesium.Color.RED
        }
    })

    console.log(`挖空区域已创建,顶点数: ${points.length},裁剪平面数: ${clippingPlanes.length}`)
}

// 完成绘制并挖空区域
function finishDrawing() {
    console.log(polygonPoints)
    createPolygonClipArea(polygonPoints)

    // 重置绘制状态
    isDrawing = false
    polygonPoints = []
    polygonEntity = null
}