04-ArcGIS For JavaScript的可视域分析功能

文章目录

综述

在数字孪生或者实景三维的项目中,视频融合和可视域分析,一直都是热点问题。Cesium中,支持对阴影的后处理操作,通过重新编写GLSL代码就能实现视域和视频融合的功能。ArcGIS之前支持的可视域分析只要是通过GP服务的方式去实现,并且只针对地形有相应的效果,并不能直接叠加到建模模型上。

ArcGIS for JavaScript最新发布了4.30版本的api,其中新增了对于模型场景的视域分析,并且提供了很好的交互功能,使其在项目应用中又有了更多的可能性。

代码实现

直接上代码,或者直接去官网看。

javascript 复制代码
<!doctype html>
<html lang="en">

<head>
  <meta charset="utf-8" />
  <meta name="viewport" content="initial-scale=1,maximum-scale=1,user-scalable=no" />
  <title>Interactive viewshed analysis | Sample | ArcGIS Maps SDK for JavaScript 4.30</title>
  <style>
    html,
    body,
    html,
    body,
    #viewDiv {
      width: 100%;
      height: 100%;
      margin: 0;
      padding: 0;
    }
    #viewshedComponent {
      width: 270px;
    }
    #viewshedComponent calcite-button {
      display: flex;
    }
    #promptText {
      margin-top: 0.4rem;
    }
  </style>
  <link rel="stylesheet" href="https://js.arcgis.com/4.30/esri/themes/light/main.css" />
  <script src="https://js.arcgis.com/4.30/"></script>
  <script type="module" src="https://js.arcgis.com/calcite-components/2.8.5/calcite.esm.js"></script>
  <link rel="stylesheet" type="text/css" href="https://js.arcgis.com/calcite-components/2.8.5/calcite.css" />
  <script>
    require([
      "esri/Map",
      "esri/views/SceneView",
      "esri/geometry/SpatialReference",
      "esri/core/promiseUtils",
      "esri/core/reactiveUtils",
      "esri/views/3d/environment/SunLighting",
      "esri/analysis/ViewshedAnalysis",
      "esri/analysis/Viewshed"
    ], function (
      Map,
      SceneView,
      SpatialReference,
      promiseUtils,
      reactiveUtils,
      SunLighting,
      ViewshedAnalysis,
      Viewshed
    ) {
      const view = new SceneView({
        container: "viewDiv",
        camera: {
          position: {
            spatialReference: SpatialReference.WebMercator,
            x: -9753837.742627423,
            y: 5140806.202422867,
            z: 995.4546383377165
          },
          heading: 1.2311944909542853,
          tilt: 70.07900968078631
        },
        map: new Map({
          basemap: "topo-3d",
          ground: "world-elevation"
        }),
        environment: {
          lighting: new SunLighting({
            date: new Date("January 18, 2024 12:50:00 UTC-6"),
            directShadowsEnabled: true
          })
        }
      });

      view.when(async () => {
        // Hide the 3D basemap's labels layer.
        const labelsLayer = view.map.basemap.referenceLayers.find(
          (layer) => layer.title === "Places and Labels"
        );
        labelsLayer.visible = false;

        // Create the viewshed shape.
        const viewshed = new Viewshed({
          observer: {
            spatialReference: SpatialReference.WebMercator,
            x: -9754426,
            y: 5143111,
            z: 330
          },
          farDistance: 900, // In meters
          tilt: 84, // Tilt of 0 looks down, tilt of 90 looks parallel to the ground, tilt of 180 looks up to the sky
          heading: 63, // Counted clockwise from North
          horizontalFieldOfView: 85,
          verticalFieldOfView: 52
        });
        // Initialize viewshed analysis with the created viewshed shape and add it to the view.
        const viewshedAnalysis = new ViewshedAnalysis({ viewsheds: [viewshed] });
        view.analyses.add(viewshedAnalysis);

        // Access the viewshed's analysis view.
        const analysisView = await view.whenAnalysisView(viewshedAnalysis);
        // Make the existing analysis interactive and select the created viewshed.
        analysisView.interactive = true;
        analysisView.selectedViewshed = viewshed;

        // Add interactivity to the custom UI component's buttons.
        const createButton = document.getElementById("createButton");
        const cancelButton = document.getElementById("cancelButton");
        const promptText = document.getElementById("promptText");

        // Controller which allows to cancel an ongoing viewshed creation operation.
        let abortController = null;

        createButton.addEventListener("click", () => {
          // Cancel any pending creation operation.
          stopCreating();

          // Create a new abort controller for the new operation.
          abortController = new AbortController();

          updateUI();

          // Save current number of viewsheds to track whenever a new one is created.
          const viewshedCounter = viewshedAnalysis.viewsheds.length;
          // Watch whenever the a new viewshed is created and selected and then stop the creation method.
          reactiveUtils.when(
            () => viewshedAnalysis.viewsheds.length > viewshedCounter && analysisView.selectedViewshed,
            () => {
              stopCreating();
              updateUI();
            }
          );

          // Pass the controller as an argument to the interactive creation method
          // and schedule the updateUI function after creating viewsheds is finished.
          analysisView
            .createViewsheds(abortController)
            .catch((e) => {
              // When the operation is cancelled, don't do anything. Any other errors are thrown.
              if (!promiseUtils.isAbortError(e)) {
                throw e;
              }
            })
            .finally(() => {
              // Update the UI to reflect the non-creating mode.
              updateUI();
            });
        });

        cancelButton.addEventListener("click", () => {
          // Pressing the Cancel button stops the viewshed creation process and updates the UI accordingly.
          stopCreating();
          updateUI();
        });
        // Cancel the creation process and updates the UI when ESC is pressed.
        view.on("key-down", (event) => {
          if ((event.key = "Escape")) {
            stopCreating();
            updateUI();
          }
        });

        // Cancel any pending viewshed creation operation.
        function stopCreating() {
          abortController?.abort();
          abortController = null;
        }

        // Update the UI component according to whether there is a pending operation.
        function updateUI() {
          const creating = abortController != null;
          createButton.style.display = !creating ? "flex" : "none";
          cancelButton.style.display = creating ? "flex" : "none";
          promptText.style.display = creating ? "flex" : "none";
        }

        // Add the component to the UI.
        view.ui.add("viewshedComponent", "top-right");
      });

    });
  </script>
</head>

<body>
  <div id="viewDiv"></div>
  <calcite-card id="viewshedComponent">
    <calcite-button id="createButton">Create viewshed</calcite-button>
    <calcite-button id="cancelButton" style="display:none">Cancel </calcite-button>
    <div id="promptText" style="display: none">
      <em>Start the analysis by clicking in the scene to place the observer point and set the target.</em>
    </div>
  </calcite-card>
</body>

</html>

代码解析

ArcGIS for JavaScript提供了新的对象Viewshed和ViewshedAnalysis。

Viewshed定义了Viewshed分析的几何形状。视域由位置、距离、方向(由头部和倾斜定义)和视野角度决定。

ViewshedAnalysis允许在3D SceneView中创建和显示viewshed和view dome类型的可见性分析。该分析功能可以包含多个视图。它们可以以交互方式或编程方式创建,并且可以将分析直接添加到SceneView.analyses中。

javascript 复制代码
const viewshed = new Viewshed({
   observer: {
     spatialReference: {
       latestWkid: 3857,
       wkid: 102100
     },
     x: -9754426,
     y: 5143111,
     z: 330
   },
   farDistance: 900,
   heading: 64,
   tilt: 84,
   horizontalFieldOfView: 85,
   verticalFieldOfView: 52
 });
 const viewshedAnalysis = new ViewshedAnalysis({
   viewsheds: [viewshed],
 });

 view.analyses.add(viewshedAnalysis);
···

上面方法是直接去创建可视域的功能,当然也可以通过交互的方式去创建可视域。

```javascript
		const analysisView = await 		 view.whenAnalysisView(viewshedAnalysis);
        // Make the existing analysis interactive and select the created viewshed.
        analysisView.interactive = true;
        analysisView.selectedViewshed = viewshed;
analysisView
            .createViewsheds(abortController)
            .catch((e) => {
              // When the operation is cancelled, don't do anything. Any other errors are thrown.
              if (!promiseUtils.isAbortError(e)) {
                throw e;
              }
            })
            .finally(() => {
              // Update the UI to reflect the non-creating mode.
              updateUI();
            });

结果

相关推荐
wrx繁星点点9 分钟前
享元模式:高效管理共享对象的设计模式
java·开发语言·spring·设计模式·maven·intellij-idea·享元模式
真的想不出名儿13 分钟前
Java基础——反射
java·开发语言
努力编程的阿伟32 分钟前
【Java SE语法】抽象类(abstract class)和接口(interface)有什么异同?
java·开发语言
清灵xmf36 分钟前
在 Vue 中实现与优化轮询技术
前端·javascript·vue·轮询
包饭厅咸鱼1 小时前
QML----复制指定下标的ListModel数据
开发语言·数据库
bryant_meng1 小时前
【python】Distribution
开发语言·python·分布函数·常用分布
红黑色的圣西罗1 小时前
Lua 怎么解决闭包内存泄漏问题
开发语言·lua
yanlou2331 小时前
KMP算法,next数组详解(c++)
开发语言·c++·kmp算法
小林熬夜学编程1 小时前
【Linux系统编程】第四十一弹---线程深度解析:从地址空间到多线程实践
linux·c语言·开发语言·c++·算法
墨墨祺1 小时前
嵌入式之C语言(基础篇)
c语言·开发语言