Skip to content

TilesMultClip 3D Tiles 多面裁剪

对 3D Tileset 挂载持久化的 ClippingPlaneCollection,把每个多边形(世界坐标)转换为一组 垂直裁剪平面。裁剪平面法线朝外、交集语义(Cesium 默认)下裁剪"多边形柱体"(挖洞), 对齐源案例 Analysis/TilesMultClip;clear() 清空全部裁剪平面。


能力定位

TilesMultClip 适合:

  • 单区域开挖/切割:3D Tiles 建筑/地形多边形挖洞展示;
  • 重叠多边形叠加裁剪:多个相互重叠的多边形交集 = 重叠区,可叠加成更大裁剪区;
  • 与交互绘制组合:配合 DrawManager 实现鼠标绘制多边形即时裁剪(模板采用"每次替换"语义)。

为什么是替换语义(交互模板):Cesium 单 ClippingPlaneCollection 只能表达一个 裁剪区。多个不相交多边形在交集语义下裁剪区交集为空 → 模型整体不再被裁剪 ("第二次裁剪就不生效");并集语义下每个多边形的内侧并集铺满平面 → 整个模型被裁没。 因此交互模板每次绘制clear()add(),一次只保留当前一个裁剪区,保证每次 绘制都有可见裁剪效果。类本身保留累计 add,供"重叠多边形叠加"这类交集有意义的使用。

与单次替换裁剪的分工(共用同一垂直平面算法,互不重叠):

能力API行为
单次替换裁剪viewerTilesClipMixinviewer.tilesClip.clip(tileset, positions)每次调用先清后建,适合单个裁剪区
多面裁剪TilesMultClip(本类)add 追加不替换(交集语义);交互模板为每次替换

构造函数

ts
constructor(tileset: Cesium3DTileset, options?: TilesMultClipOptions)
ts
interface TilesMultClipOptions {
  edgeColor?: Color             // 裁剪边高亮色,默认 WHITE(对齐源案例)
  edgeWidth?: number            // 裁剪边宽度(像素),默认 1
  enabled?: boolean             // 裁剪平面集合是否启用,默认 true
}
参数类型默认值描述
tilesetCesium3DTileset(必填)待裁剪的 3D Tileset
edgeColorColorWHITE裁剪边高亮色
edgeWidthnumber1裁剪边宽度(像素)
enabledbooleantrue裁剪平面集合是否启用

生命周期与操作

实现 Lifecycle<Viewer> 契约,on/off/destroy 均幂等:

ts
on(viewer: Viewer): void   // 保存 tileset 原裁剪状态 + 挂载裁剪平面集合(交集语义)
add(positions: Cartesian3[]): void  // 追加一个多边形的垂直裁剪平面(顺时针自动反转;未 on 抛错)
clear(): void             // 清空全部裁剪平面(未 on 抛错)
off(viewer: Viewer): void // 还原 tileset 原裁剪状态
destroy(viewer: Viewer): void // 等价于 off
get planeCount: number    // 当前裁剪平面总数(未 on 时为 0)

清理完整性on 保存 tileset.clippingPlanes 原值,off/destroy 还原;本类只持有 tileset.clippingPlanes 与自身裁剪集合,不触碰调用方其他资源(对齐 ClusterLayer 的还原纪律)。

基础示例

ts
import { TilesMultClip } from '@nexa/gis-cesium'

const tileset = await Cesium.Cesium3DTileset.fromUrl('https://your-host/tileset.json')
viewer.scene.primitives.add(tileset)

const clip = new TilesMultClip(tileset)
clip.on(viewer)

// 追加一个裁剪多边形(世界坐标,顺时针自动反转)
clip.add([
  Cesium.Cartesian3.fromDegrees(108.96, 34.22, 0),
  Cesium.Cartesian3.fromDegrees(108.97, 34.22, 0),
  Cesium.Cartesian3.fromDegrees(108.97, 34.23, 0),
  Cesium.Cartesian3.fromDegrees(108.96, 34.23, 0),
])
console.log(clip.planeCount) // 4(四边形 × 4 边)

// 替换语义:新多边形覆盖上一个裁剪区(每次绘制只保留一个裁剪区)
clip.clear()
clip.add([ /* 第二组顶点 */ ])
console.log(clip.planeCount) // 4

// 页面或场景退出时统一销毁(幂等)
clip.destroy(viewer)

多个重叠多边形可累计 add:交集 = 重叠区,裁剪区随追加扩大(如从一块地逐步扩到 相邻地块)。不相交多边形的交集为空、模型整体不裁剪,此时应用替换语义(先 clearadd)。

进阶示例

DrawManager 组合,鼠标绘制多边形即时裁剪(每次替换):

ts
import { TilesMultClip } from '@nexa/gis-cesium'

const clip = new TilesMultClip(tileset)
clip.on(viewer)

drawManager.startDraw('polygon') // DrawManager 进入多边形绘制态(左键加点/双击闭合/右键取消)
drawManager.onDrawComplete(({ positions }) => {
  clip.clear()      // 替换语义:先清空上一个裁剪区
  clip.add(positions) // 再追加新多边形 → 一次只保留一个裁剪区
})

实现说明

  • 垂直裁剪平面:多边形每边构造一个垂直平面——up=(0,0,10)normal = (p2 − p1) × up, 以 Plane.fromPointNormal + ClippingPlane.fromPlane 构造,平面位于 tileset 本地坐标系
  • 法线朝外(right × up):Cesium 裁剪"法线反侧"(getPointDistance < 0 即 discard), 因此交集语义下多边形柱体被挖掉——对齐源案例 Analysis/TilesMultClip 的模型裁剪效果;
  • 坐标转换inverseTransformroot.transform(非单位阵)或 Transforms.eastNorthUpToFixedFrame(boundingSphere.center),把世界坐标多边形转入本地系;
  • 判向:shoelace 面积 sum > 0 判定顺时针并自动反转(与源案例 turf.booleanClockwise 逐位等价,不引入 turf 依赖);
  • 累计语义add 向持久集合追加(不替换);clearremoveAll() 清空且集合可复用;
  • 退化边防护:双击闭合产生的连续重复顶点会在 add 中按绝对 1µm 阈值去重,近零法线 (EPSILON9)跳过,避免 normalize(0)DeveloperError
  • 资源所有权:本类只持有 tileset.clippingPlanes 与自身裁剪集合,on 保存原状态、 off/destroy 还原(d.ts 的 clippingPlanes 非可空,原无裁剪时还原为空集合,运行时等效无裁剪)。

清理责任

ts
clip.destroy(viewer) // 或 clip.off(viewer),等价且幂等

重复调用 destroy/off 安全(未 on 时为空操作)。销毁后重新 on 可再次启用裁剪。

Cesium 版本限制

  • 依赖 Cesium 公共 ClippingPlaneCollection / ClippingPlane / Plane / Cesium3DTileset.clippingPlanes
  • 已验证目标版本:Cesium 1.133.1。