Appearance
TilesMultClip 3D Tiles 多面裁剪
对 3D Tileset 挂载持久化的
ClippingPlaneCollection,把每个多边形(世界坐标)转换为一组 垂直裁剪平面。裁剪平面法线朝外、交集语义(Cesium 默认)下裁剪"多边形柱体"(挖洞), 对齐源案例 Analysis/TilesMultClip;clear()清空全部裁剪平面。
能力定位
TilesMultClip 适合:
- 单区域开挖/切割:3D Tiles 建筑/地形多边形挖洞展示;
- 重叠多边形叠加裁剪:多个相互重叠的多边形交集 = 重叠区,可叠加成更大裁剪区;
- 与交互绘制组合:配合
DrawManager实现鼠标绘制多边形即时裁剪(模板采用"每次替换"语义)。
为什么是替换语义(交互模板):Cesium 单
ClippingPlaneCollection只能表达一个 凸裁剪区。多个不相交多边形在交集语义下裁剪区交集为空 → 模型整体不再被裁剪 ("第二次裁剪就不生效");并集语义下每个多边形的内侧并集铺满平面 → 整个模型被裁没。 因此交互模板每次绘制先clear()再add(),一次只保留当前一个裁剪区,保证每次 绘制都有可见裁剪效果。类本身保留累计add,供"重叠多边形叠加"这类交集有意义的使用。
与单次替换裁剪的分工(共用同一垂直平面算法,互不重叠):
| 能力 | API | 行为 |
|---|---|---|
| 单次替换裁剪 | viewerTilesClipMixin → viewer.tilesClip.clip(tileset, positions) | 每次调用先清后建,适合单个裁剪区 |
| 多面裁剪 | TilesMultClip(本类) | add 追加不替换(交集语义);交互模板为每次替换 |
构造函数
ts
constructor(tileset: Cesium3DTileset, options?: TilesMultClipOptions)ts
interface TilesMultClipOptions {
edgeColor?: Color // 裁剪边高亮色,默认 WHITE(对齐源案例)
edgeWidth?: number // 裁剪边宽度(像素),默认 1
enabled?: boolean // 裁剪平面集合是否启用,默认 true
}| 参数 | 类型 | 默认值 | 描述 |
|---|---|---|---|
tileset | Cesium3DTileset | (必填) | 待裁剪的 3D Tileset |
edgeColor | Color | WHITE | 裁剪边高亮色 |
edgeWidth | number | 1 | 裁剪边宽度(像素) |
enabled | boolean | true | 裁剪平面集合是否启用 |
生命周期与操作
实现 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:交集 = 重叠区,裁剪区随追加扩大(如从一块地逐步扩到 相邻地块)。不相交多边形的交集为空、模型整体不裁剪,此时应用替换语义(先clear再add)。
进阶示例
与 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的模型裁剪效果; - 坐标转换:
inverseTransform取root.transform(非单位阵)或Transforms.eastNorthUpToFixedFrame(boundingSphere.center),把世界坐标多边形转入本地系; - 判向:shoelace 面积
sum > 0判定顺时针并自动反转(与源案例turf.booleanClockwise逐位等价,不引入 turf 依赖); - 累计语义:
add向持久集合追加(不替换);clear用removeAll()清空且集合可复用; - 退化边防护:双击闭合产生的连续重复顶点会在
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。