ArcGIS Runtime API for .NET——Scenes (3D)
场景3D
可以使用场景和场景视图执行以下操作:
显示底图图层,例如街道或卫星图像。
基于文件或服务访问和显示数据层,包括你编写的数据。
显示带有高程图层的地形。
显示现实世界中的对象,例如建筑物,汽车和树木。
显示2D对象的3D可视化效果。
执行3D分析,例如视线,可见性和3D测量。
提供临时点,线,多边形或显示为图形的文本的上下文。
测量距离并探索几何之间的空间关系。
检查数据层并显示来自属性的信息。
一.场景如何运作
场景与场景视图一起使用,可以在三个维度上显示地理内容。 场景包含一个图层集合,其中包括来自在线或本地来源的多个数据层,提供地理环境的底图图层以及包含高程数据的底面。 场景还可以包含用于搜索地址或地名,用于求解路线的网络以及非空间表的数据集。
对于脱机工作流程(当您没有网络连接时),可以打开存储在移动场景包中的场景。 您可以使用ArcGIS Pro创建移动场景包,使用ArcGIS组织共享它们或通过复制到设备直接分发。 有关使用ArcGIS Runtime实施离线工作流的更多信息,请参见离线地图,场景和数据。
二.场景
场景包含图层的集合。 二维图层按添加顺序显示,而三维图层则按图层的高程信息显示。 可以使用场景更改二维图层的显示顺序以及控制可见的图层,并使用用户界面控件(如列表,复选框或开关)公开此功能。 场景通过引入包含高程源集合的基础表面来扩展基础图的概念。 可以将图层叠加在表面的顶部,相对于表面放置或根据其绝对值进行显示。
可以通过创建一个新场景并完全使用代码构建它来实例化一个新的Scene对象。 使用这种方法,通常首先要添加底图图层,然后再添加一个或多个数据图层。
Esri.ArcGISRuntime.ArcGISRuntimeEnvironment.ApiKey = "YOUR_API_KEY";
var scene = new Scene(Basemap.CreateTopographic());
const string elevationUrl = "https://elevation3d.arcgis.com/arcgis/rest/services/WorldElevation3D/Terrain3D/ImageServer";
var source = new ArcGISTiledElevationSource(new Uri(elevationUrl));
var surface = new Surface();
surface.ElevationSources.Add(source);
scene.BaseSurface = surface;
注意:
在当前版本中,场景不支持使用矢量切片图层的底图。
还可以使用场景ID或URL实例化存储在门户(例如ArcGIS Online)中的场景。
Scene scene = new Scene(new Uri("https://www.arcgis.com/home/item.html?id=31874da8a16d45bfbc1273422f772270"));
当场景首次出现在SceneView中时,可以通过设置Scene.InitialViewpoint属性将初始显示聚焦在指定的视点上。 如果未定义初始视点,则场景将首先以全局比例显示。
三.图层
场景中的每一层都引用来自在线服务或本地数据集的地理数据。可以将各种图层添加到场景中,每个图层都设计为显示特定类型的数据。一些图层显示图像,例如卫星照片或航拍照片,其他图层则由一组要素组成,这些要素使用点,线或面的几何形状表示真实世界的实体。除几何图形外,要素还具有提供有关其表示的实体的详细信息的属性。
场景还可以包含场景图层,可以创建高级3D可视化。 ArcGIS Runtime支持包含以下四种数据类型之一的场景图层:点,点云,3D对象或集成网格。要了解有关场景层的更多信息,请访问什么是场景层?在ArcGIS Pro文档中。
Layer类是ArcGIS Runtime API for .NET中使用的所有类型的层的基类。创建的图层类型取决于要显示的数据类型。例如,要显示要素数据,可以创建一个FeatureLayer,该FeatureLayer引用在线服务(例如要素服务)或受支持的本地数据集。某些图层无法显示在场景中,例如ArcGISVectorTiledLayer和AnnotationLayer。同样,3D图层也无法显示在地图中,例如ArcGISSceneLayer。
Esri.ArcGISRuntime.ArcGISRuntimeEnvironment.ApiKey = "YOUR_API_KEY";
var scene = new Scene(Basemap.CreateTopographic());
var trailheadsTable = new ServiceFeatureTable(new Uri("https://services3.arcgis.com/GVgbJbqm8hXASVYi/arcgis/rest/services/Trailheads_Styled/FeatureServer/0"));
var trailsTable = new ServiceFeatureTable(new Uri("https://services3.arcgis.com/GVgbJbqm8hXASVYi/arcgis/rest/services/Trails_Styled/FeatureServer/0"));
var openSpacesTable = new ServiceFeatureTable(new Uri("https://services3.arcgis.com/GVgbJbqm8hXASVYi/arcgis/rest/services/Parks_and_Open_Space_Styled/FeatureServer/0"));
scene.OperationalLayers.Add(new FeatureLayer(trailheadsTable));
scene.OperationalLayers.Add(new FeatureLayer(trailsTable));
scene.OperationalLayers.Add(new FeatureLayer(openSpacesTable));
MainSceneView.Scene = scene;
四.相机
场景和场景视图通过摄像头扩展了二维视点的概念,该摄像头代表了观察者在三个维度内的位置和视角。
以下属性定义了摄像机的位置:
地理位置(经度和纬度)
海拔高度(以米为单位,海拔高度)
航向(围绕相机旋转的z轴的角度,以度为单位)
螺距(以度为单位上下旋转相机的角度)
滚动(相机左右旋转角度,以度为单位)
// Define a longitude, latitude, and altitude for the camera location.
MapPoint cameraLocation = new MapPoint(-118.804, 33.909, 5330.0, SpatialReferences.Wgs84);
Camera sceneCamera = new Camera(locationPoint: cameraLocation,
heading: 355.0,
pitch: 72.0,
roll: 0.0);
场景视图具有关联的控制器,该控制器为场景管理相机。每种类型的相机控制器都旨在为与场景显示进行交互提供特定的用户体验。可以在运行时更改摄像机控制器及其属性,从而使您能够提供最适合当前上下文的场景视图交互体验。
当默认的GlobeCameraController以外的摄像机控制器处于活动状态时,无法分配场景视图的视点。尝试这样做不会引发异常,但是会被忽略。
ArcGIS Runtime SDK提供以下相机控制器:
GlobeCameraController(默认)—提供默认的场景视图相机行为。允许用户在场景中的任意位置自由移动和聚焦相机。
OrbitGeoElementCameraController-锁定场景视图的摄像机以相对于(可能是移动的)图形保持焦点。摄像机只能相对于目标图形移动。
OrbitLocationCameraController-锁定场景视图的摄影机以使其绕固定位置(地图点)旋转。相机只能相对于目标地图点移动。
TransformationMatrixCameraController-通过使用TransformationMatrix来控制相机的位置和旋转来提供导航。您需要将此对象传递给所有的TransformationMatrixCameraController函数。可以将其与ARKit(iOS)和ARCore(Android)等增强现实API生成的转换矩阵配合使用。
// Create a camera controller to follow a geoelement in the scene view.
// Pass a geoelement (graphic) and a distance (meters).
_orbitCameraController = new OrbitGeoElementCameraController(_plane3D, 20.0)
{
CameraPitchOffset = 75.0
};
MySceneView.CameraController = _orbitCameraController;
五.场景视图
场景视图是一个用户界面控件,可在您的应用程序中显示单个场景。 它包含内置功能,允许用户通过放大和缩小,平移和旋转或获取有关场景中元素的其他信息来浏览场景。 场景视图还可以在一个或多个图形叠加中包含图形。
创建场景视图后,通常需要设置场景和相机位置。 与地图不同,场景使用相机定义观察者的视角并确定可见区域。 透视图是通过设置相机的位置,位置,高度(高度),方向和倾斜度来定义的。
将场景添加到SceneView控件以显示它。 对场景所做的更改(例如添加,移除或排列图层)将立即反映在显示中。 Scene.InitialViewpoint属性将确定场景加载时显示的区域。
MainSceneView.Scene = scene;
MainSceneView.SetViewpointCamera(new Camera(
latitude: 33.961,
longitude: -118.808,
altitude: 2000,
heading: 0,
pitch: 75,
roll: 0
));
场景视图控件其他功能:
调整灯光,气氛和空间效果。
在场景表面上显示图像叠加层。
将相机锁定到某个位置或地理元素。
添加分析覆盖图以可视化分析结果。
使用鼠标或点击位置识别并选择功能。
导出当前显示的图像。
应用时间范围以过滤要素的显示。
六.示例:
显示场景
就像地图一样,场景包含地理数据层。 它包含底图图层以及一个或多个数据图层(可选)。 要提供逼真的地形视图,您还可以添加高程图层以定义整个场景中表面的高度。 场景的3D透视图由场景的摄像机控制,摄像机定义了场景观察者在3D空间中的位置。
在本教程中,您将使用影像底图图层创建并显示场景。 场景的表面定义有高程层,并且将摄像机定位为在场景视图中显示圣莫尼卡山脉的区域。
步骤:
1.创建一个新的Visual Studio项目。
2.设置API密钥
在Visual Studio的“解决方案资源管理器”中,单击App.xaml.cs。
在App类中,为OnStartup()函数添加一个替代,以在ArcGISRuntimeEnvironment上设置ApiKey属性。
// Copyright 2021 Esri
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
using System;
using System.Collections.Generic;
using System.Configuration;
using System.Data;
using System.Linq;
using System.Threading.Tasks;
using System.Windows;
namespace DisplayAMap
{
/// <summary>
/// Interaction logic for App.xaml
/// </summary>
public partial class App : Application
{
protected override void OnStartup(StartupEventArgs e)
{
base.OnStartup(e);
// Note: it is not best practice to store API keys in source code.
// The API key is referenced here for the convenience of this tutorial.
Esri.ArcGISRuntime.ArcGISRuntimeEnvironment.ApiKey = "YOUR_API_KEY";
}
}
}
3.创建一个视图模型来存储应用程序逻辑
(1)添加一个新类,为该项目定义一个视图模型。
单击项目>添加类…。
将新类命名为SceneViewModel.cs。
单击“添加”创建新类并将其添加到项目中。
新类将在Visual Studio中打开。
(2)添加必须的引用命名空间。
using System;
using System.Collections.Generic;
using System.Text;
using Esri.ArcGISRuntime.Geometry;
using Esri.ArcGISRuntime.Mapping;
using System.ComponentModel;
using System.Runtime.CompilerServices;
(3)在SceneViewModel类中实现INotifyPropertyChanged接口。
namespace DisplayAScene
{
class SceneViewModel : INotifyPropertyChanged
{
(4)在SceneViewModel类内部,添加代码以实现PropertyChanged事件。
class SceneViewModel : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
protected void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
(5)在名为Scene的视图模型上定义一个新属性,该属性公开Esri.ArcGISRuntime.Mapping.Scene对象。 设置属性后,调用OnPropertyChanged。
class SceneViewModel : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
protected void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
private Scene _scene;
public Scene Scene
{
get { return _scene; }
set
{
_scene = value;
OnPropertyChanged();
}
}
}
(6)向SceneViewModel类添加一个名为SetupScene的函数。 通过创建带有影像底图的新场景来启动该功能。
private void SetupScene()
{
// Create a new scene with an imagery basemap.
Scene scene = new Scene(Basemap.CreateImagery());
}
(7)创建一个ElevationSource来定义场景的基础表面。
// Create a new scene with an imagery basemap.
Scene scene = new Scene(Basemap.CreateImagery());
// Create an elevation source to show relief in the scene.
string elevationServiceUrl = "http://elevation3d.arcgis.com/arcgis/rest/services/WorldElevation3D/Terrain3D/ImageServer";
ArcGISTiledElevationSource elevationSource = new ArcGISTiledElevationSource(new Uri(elevationServiceUrl));
// Create a Surface with the elevation data.
Surface elevationSurface = new Surface();
elevationSurface.ElevationSources.Add(elevationSource);
// Add an exaggeration factor to increase the 3D effect of the elevation.
elevationSurface.ElevationExaggeration = 2.5;
// Apply the surface to the scene.
scene.BaseSurface = elevationSurface;
(8)使用摄像机和场景中的点定义场景的初始视点。
// Apply the surface to the scene.
scene.BaseSurface = elevationSurface;
// Create a point that defines the observer's (camera) initial location in the scene.
// The point defines a longitude, latitude, and altitude of the initial camera location.
MapPoint cameraLocation = new MapPoint(-118.804, 33.909, 5330.0, SpatialReferences.Wgs84);
// Create a Camera using the point, the direction the camera should face (heading), and its pitch and roll (rotation and tilt).
Camera sceneCamera = new Camera(locationPoint: cameraLocation,
heading: 355.0,
pitch: 72.0,
roll: 0.0);
// Create the initial point to center the camera on (the Santa Monica mountains in Southern California).
// Longitude=118.805 degrees West, Latitude=34.027 degrees North
MapPoint sceneCenterPoint = new MapPoint(-118.805, 34.027, SpatialReferences.Wgs84);
// Set an initial viewpoint for the scene using the camera and observation point.
Viewpoint initialViewpoint = new Viewpoint(sceneCenterPoint, sceneCamera);
scene.InitialViewpoint = initialViewpoint;
(9)使用创建的场景设置SceneViewModel.Scene属性。
// Set an initial viewpoint for the scene using the camera and observation point.
Viewpoint initialViewpoint = new Viewpoint(sceneCenterPoint, sceneCamera);
scene.InitialViewpoint = initialViewpoint;
// Set the view model "Scene" property.
this.Scene = scene;
(10)在创建新的SceneViewModel时,将一个构造函数添加到调用SetupScene的类中。
namespace DisplayAScene
{
class SceneViewModel : INotifyPropertyChanged
{
public SceneViewModel()
{
SetupScene();
}
完整的视图模型为:
// Copyright 2021 Esri
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
using System;
using System.Collections.Generic;
using System.Text;
using Esri.ArcGISRuntime.Geometry;
using Esri.ArcGISRuntime.Mapping;
using System.ComponentModel;
using System.Runtime.CompilerServices;
namespace DisplayAScene
{
class SceneViewModel : INotifyPropertyChanged
{
public SceneViewModel()
{
SetupScene();
}
public event PropertyChangedEventHandler PropertyChanged;
protected void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
private Scene _scene;
public Scene Scene
{
get { return _scene; }
set
{
_scene = value;
OnPropertyChanged();
}
}
private void SetupScene()
{
// Create a new scene with an imagery basemap.
Scene scene = new Scene(Basemap.CreateImagery());
// Create an elevation source to show relief in the scene.
string elevationServiceUrl = "http://elevation3d.arcgis.com/arcgis/rest/services/WorldElevation3D/Terrain3D/ImageServer";
ArcGISTiledElevationSource elevationSource = new ArcGISTiledElevationSource(new Uri(elevationServiceUrl));
// Create a Surface with the elevation data.
Surface elevationSurface = new Surface();
elevationSurface.ElevationSources.Add(elevationSource);
// Add an exaggeration factor to increase the 3D effect of the elevation.
elevationSurface.ElevationExaggeration = 2.5;
// Apply the surface to the scene.
scene.BaseSurface = elevationSurface;
// Create a point that defines the observer's (camera) initial location in the scene.
// The point defines a longitude, latitude, and altitude of the initial camera location.
MapPoint cameraLocation = new MapPoint(-118.804, 33.909, 5330.0, SpatialReferences.Wgs84);
// Create a Camera using the point, the direction the camera should face (heading), and its pitch and roll (rotation and tilt).
Camera sceneCamera = new Camera(locationPoint: cameraLocation,
heading: 355.0,
pitch: 72.0,
roll: 0.0);
// Create the initial point to center the camera on (the Santa Monica mountains in Southern California).
// Longitude=118.805 degrees West, Latitude=34.027 degrees North
MapPoint sceneCenterPoint = new MapPoint(-118.805, 34.027, SpatialReferences.Wgs84);
// Set an initial viewpoint for the scene using the camera and observation point.
Viewpoint initialViewpoint = new Viewpoint(sceneCenterPoint, sceneCamera);
scene.InitialViewpoint = initialViewpoint;
// Set the view model "Scene" property.
this.Scene = scene;
}
}
}
使用MVVM设计模式的优点是可以重用视图模型中的代码。 由于ArcGIS Runtime for .NET在各个平台上具有几乎标准的API表面,因此为一个ArcGIS Runtime for .NET应用程序编写的视图模型通常可在所有受支持的.NET平台上使用。
接下来,在项目中设置一个视图以使用该视图模型。
4.添加场景视图
SceneView控件用于显示场景。 将场景视图添加到项目UI并连接起来以使用SceneViewModel上定义的场景。
(1)添加所需的XML名称空间和资源声明。
<Window x:Class="DisplayAScene.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:DisplayAScene"
xmlns:esri="http://schemas.esri.com/arcgis/runtime/2013"
mc:Ignorable="d"
Title="MainWindow" Height="450" Width="800">
<Window.Resources>
<local:SceneViewModel x:Key="SceneViewModel" />
</Window.Resources>
(2)将一个SceneView控件添加到MainWindow.xaml并将其绑定到SceneViewModel。
<Grid>
<esri:SceneView x:Name="MainSceneView"
Scene="{Binding Scene, Source={StaticResource SceneViewModel}}" />
</Grid>
修改MainWindow.xaml中的内容。
(1)带高程的场景显示
using System;
using System.Windows;
using Esri.ArcGISRuntime.Geometry;
using Esri.ArcGISRuntime.Mapping;
using System.ComponentModel;
using System.Runtime.CompilerServices;
using Esri.ArcGISRuntime.UI.Controls;
namespace ArcGISApp1
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
}
(2)简单场景展示
using System;
using System.Windows;
using Esri.ArcGISRuntime.Geometry;
using Esri.ArcGISRuntime.Mapping;
using System.ComponentModel;
using System.Runtime.CompilerServices;
using Esri.ArcGISRuntime.UI.Controls;
namespace ArcGISApp1
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
Scene scene = new Scene(new Uri("https://www.arcgis.com/home/item.html?id=31874da8a16d45bfbc1273422f772270"));
MainSceneView.Scene = scene;
}
}
}