• 【WebGIS实例】(11)Cesium自定义区域裁剪(挖除&挖出)


    前言

    本篇博客完全参考cesium-地面裁剪(多个剪切面)_cesium clippingplane-CSDN博客,感谢孙霸天大佬提供的实现方法。在此博客的基础上,本篇博客做了以下工作:

    1. 修复点位集合逆时针和顺时针导致不同的结果的问题
    2. 新增了挖出的实现方案
    3. 创建裁切面部分添加了大量注释

    挖出
    挖出
    挖除
    挖除
    注: 仅支持凸多边形的裁剪。

    代码

    其实就是一个方法,接收两个参数:坐标点集合和裁剪类型。

    坐标点集合数据示例

    const pointList = [
      {
        "x": 831378.7404354169,
        "y": -4856690.379372356,
        "z": 4036359.538261747
      },
      {
        "x": 3334347.320785613,
        "y": -4763032.687230717,
        "z": 2613474.0729391705
      },
      {
        "x": 133401.66014090632,
        "y": -6152120.724266897,
        "z": 1671946.9335355863
      }
    ]
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    核心代码

    import { viewer } from '@/utils/createCesium.js' // 引入地图对象
    import * as Cesium from 'cesium'
    
    /**
     * Calculates the area clipping of a set of points.
     *
     * @param {Array} points - The points to calculate the area clipping for.
     * @param {boolean} [type=false] - The type of area clipping: false:保留多边形外,挖除 ; true:保留多边形内,挖出
     * @return {void} This function does not return a value.
     */
    export function areaClipping(points, type = false) {
      // 获取点坐标,计算
      const pointsCoor = points.map(({ x, y, z }) => new Cesium.Cartesian3(x, y, z))
      let sum = 0
      for (let i = 0; i < pointsCoor.length; i++) {
        const pointA = pointsCoor[i]
        const pointB = pointsCoor[(i + 1) % pointsCoor.length]
        const crossProduct = Cesium.Cartesian3.cross(pointA, pointB, new Cesium.Cartesian3()) // 计算pointA和pointB两个向量的叉乘
        sum += crossProduct.z
      }
    
      if (sum > 0 && type) { // 逆时针
        points.reverse()
      } else if (sum < 0 && !type) { // 顺时针
        points.reverse()
      }
    
      const clippingPlanes = [] // 存储ClippingPlane集合
      for (let i = 0; i < points.length; ++i) {
        const nextIndex = (i + 1) % points.length
    
        // 计算两个坐标点的分量和,取中点。
        const midpoint = Cesium.Cartesian3.add(points[i], points[nextIndex], new Cesium.Cartesian3())
        Cesium.Cartesian3.multiplyByScalar(midpoint, 0.5, midpoint)
    
        // up 是指从地球中心(原点)到 midpoint 的向量,即一个指向地球正上方的单位向量。
        const up = Cesium.Cartesian3.normalize(midpoint, new Cesium.Cartesian3())
    
        // 计算points[nextIndex]和midpoint的差值,得到一个表示从 points[nextIndex] 指向 midpoint 的向量
        const right = Cesium.Cartesian3.subtract(points[nextIndex], midpoint, new Cesium.Cartesian3())
        Cesium.Cartesian3.normalize(right, right) // 计算单位向量
    
        // 通过叉乘及归一化得到单位法向量
        const 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))
      }
    
      // 为地球添加裁剪面
      viewer.scene.globe.clippingPlanes = new Cesium.ClippingPlaneCollection({
        planes: clippingPlanes,
        enabled: true,
        modelMatrix: Cesium.Matrix4.IDENTITY,
        unionClippingRegions: type, // 内 || 外
        edgeColor: Cesium.Color.YELLOW,
        edgeWidth: 1.0
      })
    
      viewer.scene.globe.backFaceCulling = false
      viewer.scene.globe.showSkirts = false
    
      // viewer.scene.globe.clippingPlanes = null // 销毁
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68

    使用方法

    import { areaClipping } from '@/utils/clippingToCanyon.js'
    
    // 挖出
    areaClipping(pointList, true)
    
    // 挖除
    areaClipping(pointList, false)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
  • 相关阅读:
    Vuex插件的安装与使用原理
    回溯法介绍-回溯与递归的区别【详细且排版舒服】
    Java反射用例:
    【SpringBoot源码】源码分析
    用纯HTML写一个凭证并打印
    java计算机毕业设计冠状病毒疫情防控资讯交流推荐网站源码+mysql数据库+系统+lw文档+部署
    Redis的下载与安装
    快速排序——及其改进
    79. 单词搜索
    C语言和mfc按格式读取文件数据
  • 原文地址:https://blog.csdn.net/ReBeX/article/details/133433075