在 Cesium 中运用裁剪多边形来隐藏 3D 瓦片或地形区域

2,310 阅读3分钟

原文地址:Hide Regions of 3D Tiles or Terrain with Clipping Polygons – Cesium

裁剪多边形(ClippingPolygons)能够有针对性地将 3D 瓦片集或地形的特定区域进行隐藏。当需要在全球数据集中隔离感兴趣的区域,或者在现有数据集中添加重叠的设计模型时,该功能非常实用。

在本教程中,我们会在 Google Photorealistic 3D 瓦片中添加一个拟建的道路设计模型,为用户提供项目所需的额外地理空间背景。

在CesiumJS中使用裁剪多边形嵌入Google真实感3D瓦片中的设计模型

在本指南中,您将学会如何:

  • 在 Google Photorealistic 3D 瓦片中嵌入设计好的模型
  • 使用反向裁剪区域隔离一个区域

前提条件

第一步:加载 Google Photorealistic 3D 瓦片

首先,构建一个 Cesium Viewer 并添加来自 Cesium ion 的 Google Photorealistic 3D 瓦片数据集。

详细的教程请参考 使用 CesiumJS 加载 Google Maps Platform 的 Photorealistic 3D Tiles - 掘金 (juejin.cn)

const viewer = new Cesium.Viewer("cesiumContainer", {
  timeline: false,
  animation: false,
  sceneModePicker: false,
  baseLayerPicker: false,
  globe: false,
});

// 为感兴趣的区域设置最佳照明
viewer.scene.skyAtmosphere.show = true;
const currentTime = Cesium.JulianDate.fromIso8601(
  "2020-01-09T23:00:39.018261982600961346Z"
);
viewer.clock.currentTime = currentTime;

// 添加真实感3D瓦片
let globalTileset;
try {
  globalTileset = await Cesium.createGooglePhotorealistic3DTileset();
  viewer.scene.primitives.add(globalTileset);
} catch (error) {
  console.log(`加载真实感3D瓦片集时出错。
  ${error}`);
}

在CesiumJS中展示的Google Photorealistic 3D瓦片

第二步:定义设计模型的轮廓

接下来,我们要定义从 3D 瓦片集中裁剪出的区域,以便将其替换为我们的设计模型。为此,我们需要一个位置列表,这些位置将从托管在 Cesium ion 上的 GeoJSON 文件中获取。

外部应用程序通常会界定一个轮廓或大纲。在此,我们将使用托管的 GeoJSON 文件加载位置列表,以便于进行操作。不过,您也可以使用其他数据源,例如 KML 或 CZML,或者如步骤 3 所述,手动定义位置列表。

我们还将利用这些位置定义的多边形来设置相机指向相关位置。

添加以下代码:

// 加载一个包含项目轮廓位置的GeoJSON文件
let footprint;
try {
  const resource = await Cesium.IonResource.fromAssetId(2533131);
  const dataSource = await Cesium.GeoJsonDataSource.load(resource, {
    clampToGround: true,
  });

  viewer.dataSources.add(dataSource);

  footprint = dataSource.entities.values.find((entity) =>
    Cesium.defined(entity.polygon)
  );
  footprint.polygon.outline = false;

  // 缩放到数据位置,并设置默认视图
  const cameraOffset = new Cesium.HeadingPitchRange(
    Cesium.Math.toRadians(95.0),
    Cesium.Math.toRadians(-18.0),
    600.0
  );
  viewer.zoomTo(footprint, cameraOffset);
  viewer.homeButton.viewModel.command.beforeExecute.addEventListener(
    (e) => {
      e.cancel = true;
      viewer.zoomTo(footprint, cameraOffset);
    }
  );
} catch (error) {
  console.log(`加载GeoJSON时出错。${error}`);
}

在CesiumJS中展示的Google真实感3D瓦片上的设计模型轮廓

第三步:使用轮廓定义裁剪多边形

现在,我们可以确定我们的位置了。接下来,让我们提取这些位置,并利用它们来定义裁剪多边形。

添加以下代码:

// 隐藏轮廓
footprint.show = false;

// 基于加载的轮廓多边形添加裁剪多边形
const positions = footprint.polygon.hierarchy.getValue().positions;
const clippingPolygons = new Cesium.ClippingPolygonCollection({
  polygons: [
    new Cesium.ClippingPolygon({
      positions: positions,
    }),
  ],
});

// 将裁剪多边形集合添加到全局瓦片集
globalTileset.clippingPolygons = clippingPolygons;

在CesiumJS中使用裁剪多边形从Google真实感3D瓦片中隐藏设计模型轮廓

裁剪多边形也可以通过手动定义位置列表来实现。例如:

new Cesium.ClippingPolygon({
  positions: Cesium.Cartesian3.fromDegreesArray(
    [
      -105.0077102972673, 39.75198671798765,
      -105.0095858062031, 39.75049417970743,
      -105.00969000114443, 39.75035082687128,
      -105.00972838875393, 39.75013579705808,
      -105.00971742086537, 39.74997136204101,
      -105.00962967775735, 39.749768979944236,
      -105.00932806082336, 39.74928832007956,
    ]
  ),
}),

第四步:加载设计模型

最后,我们要从 Cesium ion 上加载一个最终设计模型的 3D Tiles,以填充我们在上一步中裁剪出的区域。

// 添加拟建新道路的瓦片集
let buildingTileset;
try {
  buildingTileset = await Cesium.Cesium3DTileset.fromIonAssetId(2533124);
  viewer.scene.primitives.add(buildingTileset);
} catch (error) {
  console.log(`加载建筑瓦片集时出错。
  ${error}`);
}

在CesiumJS中使用裁剪多边形嵌入Google真实感3D瓦片中的设计模型

第五步:使用反向裁剪

有时候,在运行时将单个区域进行隔离是非常有用的。例如,若要突出展示设计中的区域,我们可以对裁剪区域进行反转。

添加以下代码:

// 隐藏设计瓦片集
buildingTileset.show = false;

// 反转裁剪区域
clippingPolygons.inverse = true;

在CesiumJS中应用反向裁剪多边形以隔离Google真实感3D瓦片中的一个区域

下一步

完整的 Sandcastle 示例可参考 AEC裁剪,其中涵盖了上述每个步骤的相关代码。

此外,请查看 裁剪区域Sandcastle示例,了解如何动态添加或移除裁剪多边形,以及如何将它们应用于地形数据集。