框架

如何在停靠窗格可见或隐藏时订阅和取消订阅事件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
private SubscriptionToken _eventToken = null;
// Called when the visibility of the DockPane changes.
protected override void OnShow(bool isVisible)
{
if (isVisible && _eventToken == null) //Subscribe to event when dockpane is visible
{
_eventToken = MapSelectionChangedEvent.Subscribe(OnMapSelectionChangedEvent);
}

if (!isVisible && _eventToken != null) //Unsubscribe as the dockpane closes.
{
MapSelectionChangedEvent.Unsubscribe(_eventToken);
_eventToken = null;
}
}
//Event handler when the MapSelection event is triggered.
private void OnMapSelectionChangedEvent(MapSelectionChangedEventArgs obj)
{
MessageBox.Show("Selection has changed");
}

执行命令

1
2
3
4
5
IPlugInWrapper wrapper = FrameworkApplication.GetPlugInWrapper("esri_editing_ShowAttributes");
var command = wrapper as ICommand; // tool and command(Button) supports this

if ((command != null) && command.CanExecute(null))
command.Execute(null);

设置当前工具

1
2
3
4
5
6
7
// use SetCurrentToolAsync
FrameworkApplication.SetCurrentToolAsync("esri_mapping_selectByRectangleTool");

// or use ICommand.Execute
ICommand cmd = FrameworkApplication.GetPlugInWrapper("esri_mapping_selectByRectangleTool") as ICommand;
if ((cmd != null) && cmd.CanExecute(null))
cmd.Execute(null);

激活选项卡

1
FrameworkApplication.ActivateTab("esri_mapping_insertTab");

激活/停用状态 - 修改条件

1
2
3
4
5
// Define the condition in the DAML file based on the state 
if (activate)
FrameworkApplication.State.Activate("someState");
else
FrameworkApplication.State.Deactivate("someState");

确定应用程序是否繁忙

1
2
3
4
5
6
7
// The application is considered busy if a task is currently running on the main worker thread or any 
// pane or dock pane reports that it is busy or intiializing.

// Many Pro styles (such as Esri_SimpleButton) ensure that a button is disabled when FrameworkApplication.IsBusy is true
// You would use this property to bind to the IsEnabled property of a control (such as a listbox) on a dockpane or pane in order
// to disable it from user interaction while the application is busy.
bool isbusy = FrameworkApplication.IsBusy;

获取应用程序主窗口

1
2
3
4
5
6
System.Windows.Window window = FrameworkApplication.Current.MainWindow;

// center it
Rect rect = System.Windows.SystemParameters.WorkArea;
FrameworkApplication.Current.MainWindow.Left = rect.Left + (rect.Width - FrameworkApplication.Current.MainWindow.ActualWidth) / 2;
FrameworkApplication.Current.MainWindow.Top = rect.Top + (rect.Height - FrameworkApplication.Current.MainWindow.ActualHeight) / 2;

关闭 ArcGIS Pro

1
FrameworkApplication.Close();

获取 ArcGIS 专业版

1
2
3
//"GetEntryAssembly" should be ArcGISPro.exe 
string version = System.Reflection.Assembly.GetEntryAssembly()
.GetName().Version.ToString();

关闭特定窗格

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
string _viewPaneID = "my pane"; //DAML ID of your pane
//You could have multiple instances (InstanceIDs) of your pane.
//So you can iterate through the Panes to get "your" panes only
IList<uint> myPaneInstanceIDs = new List<uint>();
foreach (Pane pane in FrameworkApplication.Panes)
{
if (pane.ContentID == _viewPaneID)
{
myPaneInstanceIDs.Add(pane.InstanceID); //InstanceID of your pane, could be multiple, so build the collection
}
}
foreach (var instanceID in myPaneInstanceIDs) //close each of "your" panes.
{
FrameworkApplication.Panes.ClosePane(instanceID);
}

激活窗格

1
2
3
4
5
6
7
8
9
var mapPanes = ProApp.Panes.OfType<IMapPane>();
foreach (Pane pane in mapPanes)
{
if (pane.Caption == "MyMap")
{
pane.Activate();
break;
}
}

获取有关当前安装的加载项的信息

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
var addin_infos = FrameworkApplication.GetAddInInfos();
StringBuilder sb = new StringBuilder();

foreach (var info in addin_infos)
{
if (info == null)
break;//no addins probed

sb.AppendLine($"Addin: {info.Name}");
sb.AppendLine($"Description {info.Description}");
sb.AppendLine($"ImagePath {info.ImagePath}");
sb.AppendLine($"Author {info.Author}");
sb.AppendLine($"Company {info.Company}");
sb.AppendLine($"Date {info.Date}");
sb.AppendLine($"Version {info.Version}");
sb.AppendLine($"FullPath {info.FullPath}");
sb.AppendLine($"DigitalSignature {info.DigitalSignature}");
sb.AppendLine($"IsCompatible {info.IsCompatible}");
sb.AppendLine($"IsDeleted {info.IsDeleted}");
sb.AppendLine($"TargetVersion {info.TargetVersion}");
sb.AppendLine($"ErrorMsg {info.ErrorMsg}");
sb.AppendLine($"ID {info.ID}");
sb.AppendLine("");
}
System.Diagnostics.Debug.WriteLine(sb.ToString());
MessageBox.Show(sb.ToString(), "Addin Infos");

查找码头窗格

1
2
// in order to find a dockpane you need to know it's DAML id
var pane = FrameworkApplication.DockPaneManager.Find("esri_core_ProjectDockPane");

码头窗格属性和方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
// in order to find a dockpane you need to know it's DAML id
var pane = FrameworkApplication.DockPaneManager.Find("esri_core_ProjectDockPane");

// determine visibility
bool visible = pane.IsVisible;

// activate it
pane.Activate();

// determine dockpane state
DockPaneState state = pane.DockState;

// pin it
pane.Pin();

// hide it
pane.Hide();

码头窗格撤消/重做

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
// in order to find a dockpane you need to know it's DAML id
var pane = FrameworkApplication.DockPaneManager.Find("esri_core_contentsDockPane");

// get the undo stack
OperationManager manager = pane.OperationManager;
if (manager != null)
{
// undo an operation
if (manager.CanUndo)
await manager.UndoAsync();

// redo an operation
if (manager.CanRedo)
await manager.RedoAsync();

// clear the undo and redo stack of operations of a particular category
manager.ClearUndoCategory("Some category");
manager.ClearRedoCategory("Some category");
}

查找停靠窗格并获取其视图模型

1
2
3
4
5
6
7
8
9
10
11
12
// in order to find a dockpane you need to know it's DAML id.  

// Here is a DAML example with a dockpane defined. Once you have found the dockpane you can cast it
// to the dockpane viewModel which is defined by the className attribute.
//
//<dockPanes>
// <dockPane id="MySample_Dockpane" caption="Dockpane 1" className="Dockpane1ViewModel" dock="bottom" height="5">
// <content className="Dockpane1View" />
// </dockPane>
//</dockPanes>

Dockpane1ViewModel vm = FrameworkApplication.DockPaneManager.Find("MySample_Dockpane") as Dockpane1ViewModel;

打开“后台”选项卡

1
2
//Opens the Backstage to the "About ArcGIS Pro" tab.
FrameworkApplication.OpenBackstage("esri_core_aboutTab");

访问当前主题

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
//Gets the application's theme
var theme = FrameworkApplication.ApplicationTheme;
//ApplicationTheme enumeration
if (FrameworkApplication.ApplicationTheme == ApplicationTheme.Dark)
{
//Dark theme
}

if (FrameworkApplication.ApplicationTheme == ApplicationTheme.HighContrast)
{
//High Contrast
}
if (FrameworkApplication.ApplicationTheme == ApplicationTheme.Default)
{
//Light/Default theme
}

显示专业消息框

1
ArcGIS.Desktop.Framework.Dialogs.MessageBox.Show("Some Message", "Some title", MessageBoxButton.YesNo, MessageBoxImage.Information, MessageBoxResult.Yes);

添加吐司通知

1
2
3
4
5
6
Notification notification = new Notification();
notification.Title = FrameworkApplication.Title;
notification.Message = "Notification 1";
notification.ImageUrl = @"pack://application:,,,/ArcGIS.Desktop.Resources;component/Images/ToastLicensing32.png";

ArcGIS.Desktop.Framework.FrameworkApplication.AddNotification(notification);

更改按钮标题或图像

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
private void ChangeCaptionImage()
{
IPlugInWrapper wrapper = FrameworkApplication.GetPlugInWrapper("MyAddin_MyCustomButton");
if (wrapper != null)
{
wrapper.Caption = "new caption";

// ensure that T-Rex16 and T-Rex32 are included in your add-in under the images folder and have
// BuildAction = Resource and Copy to OutputDirectory = Do not copy
wrapper.SmallImage = BuildImage("T-Rex16.png");
wrapper.LargeImage = BuildImage("T-Rex32.png");
}
}

private ImageSource BuildImage(string imageName)
{
return new BitmapImage(PackUriForResource(imageName));
}

private Uri PackUriForResource(string resourceName)
{
string asm = System.IO.Path.GetFileNameWithoutExtension(
System.Reflection.Assembly.GetExecutingAssembly().Location);
return new Uri(string.Format("pack://application:,,,/{0};component/Images/{1}", asm, resourceName), UriKind.Absolute);
}

获取按钮的工具提示标题

1
2
3
//Pass in the daml id of your button. Or pass in any Pro button ID.
IPlugInWrapper wrapper = FrameworkApplication.GetPlugInWrapper("button_id_from daml");
var buttonTooltipHeading = wrapper.TooltipHeading;

订阅活动工具更改事件

1
2
3
4
5
6
7
8
9
10
11
12
13
private void SubscribeEvent()
{
ArcGIS.Desktop.Framework.Events.ActiveToolChangedEvent.Subscribe(OnActiveToolChanged);
}
private void UnSubscribeEvent()
{
ArcGIS.Desktop.Framework.Events.ActiveToolChangedEvent.Unsubscribe(OnActiveToolChanged);
}
private void OnActiveToolChanged(ArcGIS.Desktop.Framework.Events.ToolEventArgs args)
{
string prevTool = args.PreviousID;
string newTool = args.CurrentID;
}

进度器 - 简单且不可取消

1
2
3
4
5
6
7
8
public async Task Progressor_NonCancelable()
{
ArcGIS.Desktop.Framework.Threading.Tasks.ProgressorSource ps = new ArcGIS.Desktop.Framework.Threading.Tasks.ProgressorSource("Doing my thing...", false);

int numSecondsDelay = 5;
//If you run this in the DEBUGGER you will NOT see the dialog
await ArcGIS.Desktop.Framework.Threading.Tasks.QueuedTask.Run(() => Task.Delay(numSecondsDelay * 1000).Wait(), ps.Progressor);
}

进度器 - 可取消

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
public async Task Progressor_Cancelable()
{
ArcGIS.Desktop.Framework.Threading.Tasks.CancelableProgressorSource cps =
new ArcGIS.Desktop.Framework.Threading.Tasks.CancelableProgressorSource("Doing my thing - cancelable", "Canceled");

int numSecondsDelay = 5;
//If you run this in the DEBUGGER you will NOT see the dialog

//simulate doing some work which can be canceled
await ArcGIS.Desktop.Framework.Threading.Tasks.QueuedTask.Run(() =>
{
cps.Progressor.Max = (uint)numSecondsDelay;
//check every second
while (!cps.Progressor.CancellationToken.IsCancellationRequested)
{
cps.Progressor.Value += 1;
cps.Progressor.Status = "Status " + cps.Progressor.Value;
cps.Progressor.Message = "Message " + cps.Progressor.Value;

if (System.Diagnostics.Debugger.IsAttached)
{
System.Diagnostics.Debug.WriteLine(string.Format("RunCancelableProgress Loop{0}", cps.Progressor.Value));
}
//are we done?
if (cps.Progressor.Value == cps.Progressor.Max) break;
//block the CIM for a second
Task.Delay(1000).Wait();

}
System.Diagnostics.Debug.WriteLine(string.Format("RunCancelableProgress: Canceled {0}",
cps.Progressor.CancellationToken.IsCancellationRequested));

}, cps.Progressor);
}

自定义按钮或工具的 disabedText 属性

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
//Set the tool's loadOnClick attribute to "false" in the config.daml. 
//This will allow the tool to be created when Pro launches, so that the disabledText property can display customized text at startup.
//Remove the "condition" attribute from the tool. Use the OnUpdate method(below) to set the enable\disable state of the tool.
//Add the OnUpdate method to the tool.
//Note: since OnUpdate is called very frequently, you should avoid lengthy operations in this method
//as this would reduce the responsiveness of the application user interface.
internal class SnippetButton : ArcGIS.Desktop.Framework.Contracts.Button
{
protected override void OnUpdate()
{
bool enableSate = true; //TODO: Code your enabled state
bool criteria = true; //TODO: Evaluate criteria for disabledText

if (enableSate)
{
this.Enabled = true; //tool is enabled
}
else
{
this.Enabled = false; //tool is disabled
//customize your disabledText here
if (criteria)
this.DisabledTooltip = "Missing criteria 1";
}
}
}

从当前程序集获取图像资源

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
public static void ExampleUsage()
{
//Image 'Dino32.png' is added as Build Action: Resource, 'Do not copy'
var img = ForImage("Dino32.png");
//Use the image...
}

public static BitmapImage ForImage(string imageName)
{
return new BitmapImage(PackUriForResource(imageName));
}
public static Uri PackUriForResource(string resourceName, string folderName = "Images")
{
string asm = System.IO.Path.GetFileNameWithoutExtension(
System.Reflection.Assembly.GetExecutingAssembly().Location);
string uriString = folderName.Length > 0
? string.Format("pack://application:,,,/{0};component/{1}/{2}", asm, folderName, resourceName)
: string.Format("pack://application:,,,/{0};component/{1}", asm, resourceName);
return new Uri(uriString, UriKind.Absolute);
}

阻止 ArcGIS Pro 关闭

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
// There are two ways to prevent ArcGIS Pro from closing
// 1. Override the CanUnload method on your add-in's module and return false.
// 2. Subscribe to the ApplicationClosing event and cancel the event when you receive it

internal class Module1 : Module
{

// Called by Framework when ArcGIS Pro is closing
protected override bool CanUnload()
{
//return false to ~cancel~ Application close
return false;
}

internal class Module2 : Module
{
public Module2()
{
ArcGIS.Desktop.Framework.Events.ApplicationClosingEvent.Subscribe(OnApplicationClosing);
}
~Module2()
{
ArcGIS.Desktop.Framework.Events.ApplicationClosingEvent.Unsubscribe(OnApplicationClosing);
}

private Task OnApplicationClosing(System.ComponentModel.CancelEventArgs args)
{
args.Cancel = true;
return Task.FromResult(0);
}

// cref: ARCGIS.DESKTOP.CORE.EVENTS.PROJECTOPENEDEVENT
// cref: ARCGIS.DESKTOP.CORE.EVENTS.PROJECTOPENEDEVENT.SUBSCRIBE
// cref: ARCGIS.DESKTOP.CORE.EVENTS.PROJECTOPENEDEVENT.UNSUBSCRIBE
// cref: ARCGIS.DESKTOP.FRAMEWORK.CONTRACTS.MODULE.INITIALIZE
// cref: ARCGIS.DESKTOP.FRAMEWORK.CONTRACTS.MODULE.UNINITIALIZE
#region How to determine when a project is opened
protected override bool Initialize() //Called when the Module is initialized.
{
ProjectOpenedEvent.Subscribe(OnProjectOpened); //subscribe to Project opened event
return base.Initialize();
}

private void OnProjectOpened(ProjectEventArgs obj) //Project Opened event handler
{
MessageBox.Show($"{Project.Current} has opened"); //show your message box
}

protected override void Uninitialize() //unsubscribe to the project opened event
{
ProjectOpenedEvent.Unsubscribe(OnProjectOpened); //unsubscribe
return;
}

如何在 MapView 中定位可嵌入控件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
public ProSnippetMapTool()
{
//Set the MapTool base class' OverlayControlID to the DAML id of your embeddable control in the constructor
this.OverlayControlID = "ProAppModule1_EmbeddableControl1";
}

protected override void OnToolMouseDown(MapViewMouseButtonEventArgs e)
{
if (e.ChangedButton == System.Windows.Input.MouseButton.Left)
e.Handled = true;
}

protected override Task HandleMouseDownAsync(MapViewMouseButtonEventArgs e)
{
return QueuedTask.Run(() =>
{
//assign the screen coordinate clicked point to the MapTool base class' OverlayControlLocation property.
this.OverlayControlPositionRatio = e.ClientPoint;

});
}

激活选项卡时命令搜索中建议的命令选项。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
//In the module class..
public override string[] GetSuggestedCMDIDs(string activeTabID)
{
//Return the static list of daml ids you want to be the (suggested)
//defaults relevant to the given tab. It can be none, some, or all of the
//commands associated with the activeTabID.
//In this example, there are two tabs. This example arbitrarily
//identifies just one command on each tab to be a default to show in the
//command search list (when _that_ particular tab is active)
switch (activeTabID)
{
case "CommandSearch_Example_Tab1":
return new string[] { "CommandSearch_Example_Button2" };
case "CommandSearch_Example_Tab2":
return new string[] { "CommandSearch_Example_Button4" };
}
return new string[] { "" };
}

从命令行启动 ArcGIS Pro

1
C:\>"C:\Program Files\ArcGIS Pro\bin\ArcGISPro.exe"

获取命令行参数

如果您的外接程序需要使用自定义命令行参数,则参数的格式必须为“/argument” - 请注意正斜杠“/”。不能有空格。如果命令行包含要打开的项目(请参阅从命令行打开项目),则必须将自定义参数或开关放在项目文件名参数之前。

1
2
3
4
5
string[] args = System.Environment.GetCommandLineArgs();
foreach (var arg in args)
{
// look for your command line switches
}

应用程序加速器(快捷键)

可以使用加速器/插入加速器 DAML 元素将应用程序加速器添加到外接程序 config.daml 中,该元素具有要与加速器关联的元素的 refID(即快捷方式)。

1
2
3
4
5
<accelerators>
<insertAccelerator refID="esri_core_openProjectButton" flags="Ctrl" key="O" />
<insertAccelerator refID="esri_core_redoButton" flags="Ctrl" key="Y" />
<insertAccelerator refID="esri_core_undoButton" flags="Ctrl" key="Z" />
</accelerators>

注意:使用 updateModule 元素中的 deleteAccelerator 和 updateAccelerator DAML 元素分别删除或更改应用程序加速器。 标志可以是以下之一:Shift、Ctrl、Alt、Ctrl+Shift、Alt+Shift、Ctrl+Alt、Ctrl+Alt+Shift

使用专业样式在 DAML 中定义控件

定义了许多 ArcGIS Pro 样式,这些样式可应用于窗格和停靠窗格上的按钮、标注和其他控件,以使加载项的外观与 ArcGIS Pro 无缝衔接。下面列出了一些最常见的样式。有关更多样式和颜色,请参阅社区示例存储库中的使用 ArcGIS Pro 设置样式示例。

按钮样式

1
2
3
4
<Button Content="Button" Style="{StaticResource Esri_SimpleButton}" ToolTip="Button">
<Button Content="Button" Style="{StaticResource Esri_BackButton}" ToolTip="Button">
<Button Content="Button" Style="{StaticResource Esri_BackButtonSmall}" ToolTip="Button">
<Button Content="Button" Style="{StaticResource Esri_CloseButton}" ToolTip="Button">

码头窗格标题样式

1
2
<TextBlock Text="MyDockPane" Style="{StaticResource DockPaneHeading}" 
VerticalAlignment="Center" HorizontalAlignment="Center"/>

内容

项目

创建一个空项目

1
2
3
//Create an empty project. The project will be created in the default folder
//It will be named MyProject1, MyProject2, or similar...
await Project.CreateAsync();

创建具有指定名称的新项目

1
2
3
4
5
6
7
8
//Settings used to create a new project
CreateProjectSettings projectSettings = new CreateProjectSettings()
{
//Sets the name of the project that will be created
Name = @"C:\Data\MyProject1\MyProject1.aprx"
};
//Create the new project
await Project.CreateAsync(projectSettings);

使用 Pro 的默认设置创建新项目

1
2
3
4
//Get Pro's default project settings.
var defaultProjectSettings = Project.GetDefaultProjectSettings();
//Create a new project using the default project settings
await Project.CreateAsync(defaultProjectSettings);

使用自定义模板文件新建项目

1
2
3
4
5
6
7
8
9
10
11
12
//Settings used to create a new project
CreateProjectSettings projectSettings = new CreateProjectSettings()
{
//Sets the project's name
Name = "New Project",
//Path where new project will be stored in
LocationPath = @"C:\Data\NewProject",
//Sets the project template that will be used to create the new project
TemplatePath = @"C:\Data\MyProject1\CustomTemplate.aptx"
};
//Create the new project
await Project.CreateAsync(projectSettings);

使用 ArcGIS Pro 提供的模板创建工程

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
//Settings used to create a new project
CreateProjectSettings proTemplateSettings = new CreateProjectSettings()
{
//Sets the project's name
Name = "New Project",
//Path where new project will be stored in
LocationPath = @"C:\Data\NewProject",
//Select which Pro template you like to use
TemplateType = TemplateType.Catalog
//TemplateType = TemplateType.LocalScene
//TemplateType = TemplateType.GlobalScene
//TemplateType = TemplateType.Map
};
//Create the new project
await Project.CreateAsync(proTemplateSettings);

打开现有项目

1
2
//Opens an existing project or project package
await Project.OpenAsync(@"C:\Data\MyProject1\MyProject1.aprx");

获取当前项目

1
2
//Gets the current project
var project = Project.Current;

获取当前项目的位置

1
2
//Gets the location of the current project; that is, the path to the current project file (*.aprx)  
string projectPath = Project.Current.URI;

获取项目的默认 gdb 路径

1
var projGDBPath = Project.Current.DefaultGeodatabasePath;

保存项目

1
2
//Saves the project
await Project.Current.SaveAsync();

检查是否需要保存项目

1
2
//The project's dirty state indicates changes made to the project have not yet been saved. 
bool isProjectDirty = Project.Current.IsDirty;

另存为项目

1
2
3
//Saves a copy of the current project file (*.aprx) to the specified location with the specified file name, 
//then opens the new project file
await Project.Current.SaveAsAsync(@"C:\Data\MyProject1\MyNewProject1.aprx");

关闭项目

1
2
//A project cannot be closed using the ArcGIS Pro API. 
//A project is only closed when another project is opened, a new one is created, or the application is shutdown.

如何向工程添加新地图

1
2
3
4
5
6
await QueuedTask.Run(() =>
{
//Note: see also MapFactory in ArcGIS.Desktop.Mapping
var map = MapFactory.Instance.CreateMap("New Map", MapType.Map, MapViewingMode.Map, Basemap.Oceans);
ProApp.Panes.CreateMapPaneAsync(map);
});

项目项

将文件夹连接项添加到当前项目

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
//Adding a folder connection
string folderPath = "@C:\\myDataFolder";
var folder = await QueuedTask.Run(() =>
{
//Create the folder connection project item
var item = ItemFactory.Instance.Create(folderPath) as IProjectItem;
//If it is succesfully added to the project, return it otherwise null
return Project.Current.AddItem(item) ? item as FolderConnectionProjectItem : null;
});

//Adding a Geodatabase:
string gdbPath = "@C:\\myDataFolder\\myData.gdb";
var newlyAddedGDB = await QueuedTask.Run(() =>
{
//Create the File GDB project item
var item = ItemFactory.Instance.Create(gdbPath) as IProjectItem;
//If it is succesfully added to the project, return it otherwise null
return Project.Current.AddItem(item) ? item as GDBProjectItem : null;
});

获取所有项目项

1
2
3
4
5
IEnumerable<Item> allProjectItems = Project.Current.GetItems<Item>();
foreach (var pi in allProjectItems)
{
//Do Something
}

获取项目的所有“MapProjectItems”

1
2
3
4
5
6
7
8
9
10
IEnumerable<MapProjectItem> newMapItemsContainer = project.GetItems<MapProjectItem>();

await QueuedTask.Run(() =>
{
foreach (var mp in newMapItemsContainer)
{
//Do Something with the map. For Example:
Map myMap = mp.GetMap();
}
});

获取特定的“MapProjectItem”

1
MapProjectItem mapProjItem = Project.Current.GetItems<MapProjectItem>().FirstOrDefault(item => item.Name.Equals("EuropeMap"));

获取所有“样式项目项”

1
2
3
4
5
6
IEnumerable<StyleProjectItem> newStyleItemsContainer = null;
newStyleItemsContainer = Project.Current.GetItems<StyleProjectItem>();
foreach (var styleItem in newStyleItemsContainer)
{
//Do Something with the style.
}

获取特定的“样式项目项”

1
2
3
4
5
var container = Project.Current.GetItems<StyleProjectItem>();
StyleProjectItem testStyle = container.FirstOrDefault(style => (style.Name == "ArcGIS 3D"));
StyleItem cone = null;
if (testStyle != null)
cone = testStyle.LookupItem(StyleItemType.PointSymbol, "Cone_Volume_3");

获取“收藏夹”样式项目项

1
2
3
4
5
var fav_style_item = await QueuedTask.Run(() =>
{
var containerStyle = Project.Current.GetProjectItemContainer("Style");
return containerStyle.GetItems().OfType<StyleProjectItem>().First(item => item.TypeID == "personal_style");
});

获取所有“GDBProjectItems”

1
2
3
4
5
6
IEnumerable<GDBProjectItem> newGDBItemsContainer = null;
newGDBItemsContainer = Project.Current.GetItems<GDBProjectItem>();
foreach (var GDBItem in newGDBItemsContainer)
{
//Do Something with the GDB.
}

获取特定的“GDBProjectItem”

1
GDBProjectItem GDBProjItem = Project.Current.GetItems<GDBProjectItem>().FirstOrDefault(item => item.Name.Equals("myGDB"));

获取所有“服务器连接项目项”

1
2
3
4
5
6
IEnumerable<ServerConnectionProjectItem> newServerConnections = null;
newServerConnections = project.GetItems<ServerConnectionProjectItem>();
foreach (var serverItem in newServerConnections)
{
//Do Something with the server connection.
}

获取特定的“服务器连接项目项”

1
ServerConnectionProjectItem serverProjItem = Project.Current.GetItems<ServerConnectionProjectItem>().FirstOrDefault(item => item.Name.Equals("myServer"));

获取项目中的所有文件夹连接

1
2
3
4
5
6
//Gets all the folder connections in the current project
var projectFolders = Project.Current.GetItems<FolderConnectionProjectItem>();
foreach (var FolderItem in projectFolders)
{
//Do Something with the Folder connection.
}

获取特定文件夹连接

1
2
//Gets a specific folder connection in the current project
FolderConnectionProjectItem myProjectFolder = Project.Current.GetItems<FolderConnectionProjectItem>().FirstOrDefault(folderPI => folderPI.Name.Equals("myDataFolder"));

删除特定文件夹连接

1
2
3
4
// Remove a folder connection from a project; the folder stored on the local disk or the network is not deleted
FolderConnectionProjectItem folderToRemove = Project.Current.GetItems<FolderConnectionProjectItem>().FirstOrDefault(myfolder => myfolder.Name.Equals("PlantSpecies"));
if (folderToRemove != null)
Project.Current.RemoveItem(folderToRemove as IProjectItem);

获取特定的“布局项目项”

1
LayoutProjectItem layoutProjItem = Project.Current.GetItems<LayoutProjectItem>().FirstOrDefault(item => item.Name.Equals("myLayout"));

获取项目中的所有布局

1
2
3
4
5
6
//Gets all the layouts in the current project
var projectLayouts = Project.Current.GetItems<LayoutProjectItem>();
foreach (var layoutItem in projectLayouts)
{
//Do Something with the layout
}

获取特定的“地理处理项目项”

1
GeoprocessingProjectItem GPProjItem = Project.Current.GetItems<GeoprocessingProjectItem>().FirstOrDefault(item => item.Name.Equals("myToolbox"));

获取工程中的所有地理处理工程项

1
2
3
4
5
6
//Gets all the GeoprocessingProjectItem in the current project
var GPItems = Project.Current.GetItems<GeoprocessingProjectItem>();
foreach (var tbx in GPItems)
{
//Do Something with the toolbox
}

在项目中搜索特定项目

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
List<Item> _mxd = new List<Item>();
//Gets all the folder connections in the current project
var allFoldersItem = Project.Current.GetItems<FolderConnectionProjectItem>();
if (allFoldersItem != null)
{
//iterate through all the FolderConnectionProjectItems found
foreach (var folderItem in allFoldersItem)
{
//Search for mxd files in that folder connection and add it to the List<T>
//Note:ArcGIS Pro automatically creates and dynamically updates a searchable index as you build and work with projects.
//Items are indexed when they are added to a project.
//The first time a folder or database is indexed, indexing may take a while if it contains a large number of items.
//While the index is being created, searches will not return any results.
_mxd.AddRange(folderItem.GetItems());
}
}

获取默认项目文件夹

1
2
3
4
5
6
7
8
9
10
11
12
//Get Pro's default project settings.
var defaultSettings = Project.GetDefaultProjectSettings();
var defaultProjectPath = defaultSettings.LocationPath;
if (defaultProjectPath == null)
{
// If not set, projects are saved in the user's My Documents\ArcGIS\Projects folder;
// this folder is created if it doesn't already exist.
defaultProjectPath = System.IO.Path.Combine(
System.Environment.GetFolderPath(
Environment.SpecialFolder.MyDocuments),
@"ArcGIS\Projects");
}

刷新文件夹连接项的子项

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
var contentItem = Project.Current.GetItems<FolderConnectionProjectItem>().First();
//var contentItem = ...
//Check if the MCT is required for Refresh()
if (contentItem.IsMainThreadRequired)
{
//QueuedTask.Run must be used if item.IsMainThreadRequired
//returns true
QueuedTask.Run(() => contentItem.Refresh());
}
else
{
//if item.IsMainThreadRequired returns false, any
//thread can be used to invoke Refresh(), though
//BackgroundTask is preferred.
contentItem.Refresh();

//Or, via BackgroundTask
ArcGIS.Core.Threading.Tasks.BackgroundTask.Run(() =>
contentItem.Refresh(), ArcGIS.Core.Threading.Tasks.BackgroundProgressor.None);
}

获取项目类别

1
2
3
// Get the ItemCategories with which an item is associated
Item gdb = ItemFactory.Instance.Create(@"E:\CurrentProject\RegionalPolling\polldata.gdb");
List<ItemCategory> gdbItemCategories = gdb.ItemCategories;

使用项目类别

1
2
3
4
// Browse items using an ItemCategory as a filter
IEnumerable<Item> gdbContents = gdb.GetItems();
IEnumerable<Item> filteredGDBContents1 = gdbContents.Where(item => item.ItemCategories.OfType<ItemCategoryDataSet>().Any());
IEnumerable<Item> filteredGDBContents2 = new ItemCategoryDataSet().Items(gdbContents);

使用模板创建项目

1
2
3
4
5
6
7
8
9
10
11
12
13
var projectFolder = System.IO.Path.Combine(
System.Environment.GetFolderPath(
Environment.SpecialFolder.MyDocuments),
@"ArcGIS\Projects");

CreateProjectSettings ps = new CreateProjectSettings()
{
Name = "MyProject",
LocationPath = projectFolder,
TemplatePath = @"C:\data\my_templates\custom_template.aptx"
};

var project = await Project.CreateAsync(ps);

选择项目容器 - 用于 SelectItemAsync

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
//Use Project.Current.ProjectItemContainers
var folderContainer = Project.Current.ProjectItemContainers.First(c => c.Path == "FolderConnection");
var gdbContainer = Project.Current.ProjectItemContainers.First(c => c.Path == "GDB");
var mapContainer = Project.Current.ProjectItemContainers.First(c => c.Path == "Map");
var layoutContainer = Project.Current.ProjectItemContainers.First(c => c.Path == "Layout");
var toolboxContainer = Project.Current.ProjectItemContainers.First(c => c.Path == "GP");
//etc.

//or...use Project.Current.GetProjectItemContainer

folderContainer = Project.Current.GetProjectItemContainer("FolderConnection");
gdbContainer = Project.Current.GetProjectItemContainer("GDB");
mapContainer = Project.Current.GetProjectItemContainer("Map");
layoutContainer = Project.Current.GetProjectItemContainer("Layout");
toolboxContainer = Project.Current.GetProjectItemContainer("GP");
//etc.

项目项:获取项或查找项

1
2
3
4
5
6
7
8
9
10
11
12
13
14
//GetItems searches project content
var map = Project.Current.GetItems<MapProjectItem>().FirstOrDefault(m => m.Name == "Map1");
var layout = Project.Current.GetItems<LayoutProjectItem>().FirstOrDefault(m => m.Name == "Layout1");
var folders = Project.Current.GetItems<FolderConnectionProjectItem>();
var style = Project.Current.GetItems<StyleProjectItem>().FirstOrDefault(s => s.Name == "ArcGIS 3D");

//Find item uses a catalog path. The path can be to a file or dataset
var fcPath = @"C:\Pro\CommunitySampleData\Interacting with Maps\Interacting with Maps.gdb\Crimes";
var pdfPath = @"C:\Temp\Layout1.pdf";
var imgPath = @"C:\Temp\AddinDesktop16.png";

var fc = Project.Current.FindItem(fcPath);
var pdf = Project.Current.FindItem(pdfPath);
var img = Project.Current.FindItem(imgPath);

在目录窗格中选择一个项目

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
//Get the catalog pane
ArcGIS.Desktop.Core.IProjectWindow projectWindow = Project.GetCatalogPane();
//or get the active catalog view...
//ArcGIS.Desktop.Core.IProjectWindow projectWindow = Project.GetActiveCatalogWindow();

//eg Find a toolbox in the project
string gpName = "Interacting with Maps.tbx";
var toolbox = Project.Current.GetItems<GeoprocessingProjectItem>().FirstOrDefault(tbx => tbx.Name == gpName);
//Select it under Toolboxes
projectWindow.SelectItemAsync(toolbox, true, true, null);//null selects it in the first container - optionally await
//Note: Project.Current.GetProjectItemContainer("GP") would get toolbox container...

//assume toolbox is also under Folders container. Select it under Folders instead of Toolboxes
var foldersContainer = Project.Current.ProjectItemContainers.First(c => c.Path == "FolderConnection");
//We must specify the container because Folders comes second (after Toolboxes)
projectWindow.SelectItemAsync(toolbox, true, true, foldersContainer);//optionally await

//Find a map and select it
var mapItem = Project.Current.GetItems<MapProjectItem>().FirstOrDefault(m => m.Name == "Map");
//Map only occurs under "Maps" so the container need not be specified
projectWindow.SelectItemAsync(mapItem, true, false, null);

地理数据库内容

浏览对话框中的地理数据库内容

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
var openDlg = new OpenItemDialog
{
Title = "Select a Feature Class",
InitialLocation = @"C:\Data",
MultiSelect = false,
BrowseFilter = BrowseProjectFilter.GetFilter(ArcGIS.Desktop.Catalog.ItemFilters.GeodatabaseItems_All)
};

//show the browse dialog
bool? ok = openDlg.ShowDialog();
if (!ok.HasValue || openDlg.Items.Count() == 0)
return; //nothing selected

await QueuedTask.Run(() =>
{
// get the item
var item = openDlg.Items.First();

// see if the item has a dataset
if (ItemFactory.Instance.CanGetDataset(item))
{
// get it
using (var ds = ItemFactory.Instance.GetDataset(item))
{
// access some properties
var name = ds.GetName();
var path = ds.GetPath();

// if it's a featureclass
if (ds is ArcGIS.Core.Data.FeatureClass fc)
{
// create a layer
var featureLayerParams = new FeatureLayerCreationParams(fc)
{
MapMemberIndex = 0
};
var layer = LayerFactory.Instance.CreateLayer<FeatureLayer>(featureLayerParams, MapView.Active.Map);

// continue
}
}
}
});

目录中的地理数据库内容

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
// subscribe to event
ProjectWindowSelectedItemsChangedEvent.Subscribe(async (ProjectWindowSelectedItemsChangedEventArgs args) =>
{
if (args.IProjectWindow.SelectionCount > 0)
{
// get the first selected item
var selectedItem = args.IProjectWindow.SelectedItems.First();

await QueuedTask.Run(() =>
{
// datasetType
var dataType = ItemFactory.Instance.GetDatasetType(selectedItem);

// get the dataset Defintion
if (ItemFactory.Instance.CanGetDefinition(selectedItem))
{
using (var def = ItemFactory.Instance.GetDefinition(selectedItem))
{
if (def is ArcGIS.Core.Data.FeatureClassDefinition fcDef)
{
var oidField = fcDef.GetObjectIDField();
var shapeField = fcDef.GetShapeField();
var shapeType = fcDef.GetShapeType();
}
else if (def is ArcGIS.Core.Data.Parcels.ParcelFabricDefinition pfDef)
{
string ver = pfDef.GetSchemaVersion();
bool enabled = pfDef.GetTopologyEnabled();
}

// etc
}
}

// get the dataset
if (ItemFactory.Instance.CanGetDataset(selectedItem))
{
using (var ds = ItemFactory.Instance.GetDataset(selectedItem))
{
if (ds is ArcGIS.Core.Data.FeatureDataset fds)
{
// open featureclasses within the feature dataset
// var fcPoint = fds.OpenDataset<FeatureClass>("Point");
// var fcPolyline = fds.OpenDataset<FeatureClass>("Polyline");
}
else if (ds is FeatureClass fc)
{
var name = fc.GetName() + "_copy";

// create
var featureLayerParams = new FeatureLayerCreationParams(fc)
{
Name = name,
MapMemberIndex = 0
};
LayerFactory.Instance.CreateLayer<FeatureLayer>(featureLayerParams, MapView.Active.Map);
}
else if (ds is Table table)
{
var name = table.GetName() + "_copy";
var tableParams = new StandaloneTableCreationParams(table)
{
Name = name
};
// create
StandaloneTableFactory.Instance.CreateStandaloneTable(tableParams, MapView.Active.Map);
}
}
}
});
}
});

收藏 夹

添加收藏夹 - 文件夹

1
2
3
4
5
6
7
8
9
10
11
var itemFolder = ItemFactory.Instance.Create(@"d:\data");

// is the folder item already a favorite?
var fav = FavoritesManager.Current.GetFavorite(itemFolder);
if (fav == null)
{
if (FavoritesManager.Current.CanAddAsFavorite(itemFolder))
{
fav = FavoritesManager.Current.AddFavorite(itemFolder);
}
}

插入收藏夹 - 地理数据库路径

1
2
3
4
5
6
7
8
9
10
11
12
string gdbPath = "@C:\\myDataFolder\\myData.gdb";

var itemGDB = ItemFactory.Instance.Create(gdbPath);

// is the item already a favorite?
var fav = FavoritesManager.Current.GetFavorite(itemGDB);
// no; add it with IsAddedToAllNewProjects set to true
if (fav != null)
{
if (FavoritesManager.Current.CanAddAsFavorite(itemGDB))
FavoritesManager.Current.InsertFavorite(itemGDB, 1, true);
}

添加收藏夹 - 设置项目项的样式

1
2
3
4
5
6
7
8
StyleProjectItem styleItem = Project.Current.GetItems<StyleProjectItem>().
FirstOrDefault(style => (style.Name == "ArcGIS 3D"));

if (FavoritesManager.Current.CanAddAsFavorite(styleItem))
{
// add to favorites with IsAddedToAllNewProjects set to false
FavoritesManager.Current.AddFavorite(styleItem);
}

切换标志是添加到所有新项目为收藏夹

1
2
3
4
5
6
7
8
9
10
11
var itemFolder = ItemFactory.Instance.Create(@"d:\data");

// is the folder item already a favorite?
var fav = FavoritesManager.Current.GetFavorite(itemFolder);
if (fav != null)
{
if (fav.IsAddedToAllNewProjects)
FavoritesManager.Current.ClearIsAddedToAllNewProjects(fav.Item);
else
FavoritesManager.Current.SetIsAddedToAllNewProjects(fav.Item);
}

获取收藏夹集并迭代

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
var favorites = FavoritesManager.Current.GetFavorites();
foreach (var favorite in favorites)
{
bool isAddedToAllProjects = favorite.IsAddedToAllNewProjects;
// retrieve the underlying item of the favorite
Item item = favorite.Item;

// Item properties
var itemType = item.TypeID;
var path = item.Path;

// if it's a folder item
if (item is FolderConnectionProjectItem)
{
}
// if it's a goedatabase item
else if (item is GDBProjectItem)
{
}
// else
}

删除所有收藏夹

1
2
3
var favorites = FavoritesManager.Current.GetFavorites();
foreach (var favorite in favorites)
FavoritesManager.Current.RemoveFavorite(favorite.Item);

收藏夹更改事件

1
2
3
4
5
ArcGIS.Desktop.Core.Events.FavoritesChangedEvent.Subscribe((args) =>
{
// favorites have changed
int count = FavoritesManager.Current.GetFavorites().Count;
});

元数据

项目:获取其 IMetadata 接口

1
2
Item gdbItem = ItemFactory.Instance.Create(@"C:\projectAlpha\GDBs\regionFive.gdb");
IMetadata gdbMetadataItem = gdbItem as IMetadata;

项目:获取项目的元数据:获取XML

1
2
3
4
5
6
7
string gdbXMLMetadataXmlAsString = string.Empty;
gdbXMLMetadataXmlAsString = await QueuedTask.Run(() => gdbMetadataItem.GetXml());
//check metadata was returned
if (!string.IsNullOrEmpty(gdbXMLMetadataXmlAsString))
{
//use the metadata
}

项目:设置项目的元数据:设置XML项

1
2
3
4
5
6
7
8
await QueuedTask.Run(() =>
{
var xml = System.IO.File.ReadAllText(@"E:\Data\Metadata\MetadataForFeatClass.xml");
//Will throw InvalidOperationException if the metadata cannot be changed
//so check "CanEdit" first
if (featureClassMetadataItem.CanEdit())
featureClassMetadataItem.SetXml(xml);
});

项目:检查元数据是否可以编辑:可以编辑

1
2
3
bool canEdit1;
//Call CanEdit before calling SetXml
await QueuedTask.Run(() => canEdit1 = metadataItemToCheck.CanEdit());

项目:使用项目的当前属性更新元数据:同步

1
2
string syncedMetadataXml = string.Empty;
await QueuedTask.Run(() => syncedMetadataXml = metadataItemToSync.Synchronize());

项目:从源项目的元数据复制元数据:复制元数据从项目

1
2
Item featureClassItem = ItemFactory.Instance.Create(@"C:\projectAlpha\GDBs\regionFive.gdb\SourceFeatureClass");
await QueuedTask.Run(() => metadataItemImport.CopyMetadataFromItem(featureClassItem));

项目:从当前项目的元数据中删除某些内容:删除元数据内容

1
2
3
Item featureClassWithMetadataItem = ItemFactory.Instance.Create(@"C:\projectBeta\GDBs\regionFive.gdb\SourceFeatureClass");
//Delete thumbnail content from item's metadata
await QueuedTask.Run(() => featureClassWithMetadataItem.DeleteMetadataContent(MDDeleteContentOption.esriMDDeleteThumbnail));

项目:使用导入的元数据更新元数据 - 输入路径可以是包含元数据的项目的路径,也可以是 XML 文件的 URI:导入元数据

1
2
3
// the input path can be the path to an item with metadata, or a URI to an XML file
IMetadata metadataItemImport1 = null;
await QueuedTask.Run(() => metadataItemImport1.ImportMetadata(@"E:\YellowStone.gdb\MyDataset\MyFeatureClass", MDImportExportOption.esriCurrentMetadataStyle));

项目:使用导入的元数据更新元数据:导入元数据

1
2
3
// the input path can be the path to an item with metadata, or a URI to an XML file

await QueuedTask.Run(() => metadataItemImport2.ImportMetadata(@"E:\YellowStone.gdb\MyDataset\MyFeatureClass", MDImportExportOption.esriCustomizedStyleSheet, @"E:\StyleSheets\Import\MyImportStyleSheet.xslt"));

项目:导出当前选定项目的元数据:导出元数据

1
await QueuedTask.Run(() => metadataItemExport1.ExportMetadata(@"E:\Temp\OutputXML.xml", MDImportExportOption.esriCurrentMetadataStyle, MDExportRemovalOption.esriExportExactCopy));

项目:导出当前选定项目的元数据:导出元数据

1
await QueuedTask.Run(() => metadataItemExport2.ExportMetadata(@"E:\Temp\OutputXML.xml", MDImportExportOption.esriCustomizedStyleSheet, MDExportRemovalOption.esriExportExactCopy, @"E:\StyleSheets\Export\MyExportStyleSheet.xslt"));

项目:将当前项目的元数据另存为 XML:将元数据另存为 XML

1
await QueuedTask.Run(() => metadataItemToSaveAsXML.SaveMetadataAsXML(@"E:\Temp\OutputXML.xml", MDSaveAsXMLOption.esriExactCopy));

项目:将当前项目的元数据另存为 HTML:将元数据另存为HTML

1
await QueuedTask.Run(() => metadataItemToSaveAsHTML.SaveMetadataAsHTML(@"E:\Temp\OutputHTML.htm", MDSaveAsHTMLOption.esriCurrentMetadataStyle));

项目:使用自定义 XSLT 保存当前项目的元数据:保存元数据作为使用自定义 XSLT

1
await QueuedTask.Run(() => metadataItemToSaveAsUsingCustomXSLT.SaveMetadataAsUsingCustomXSLT(@"E:\Data\Metadata\CustomXSLT.xsl", @"E:\Temp\OutputXMLCustom.xml"));

项目:升级当前项目的元数据:升级元数据

1
2
var fgdcItem = ItemFactory.Instance.Create(@"C:\projectAlpha\GDBs\testData.gdb");
await QueuedTask.Run(() => fgdcItem.UpgradeMetadata(MDUpgradeOption.esriUpgradeFgdcCsdgm));

项目单位

获取所有可用单位格式的完整列表

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
//Must be on the QueuedTask.Run()

var unit_formats = Enum.GetValues(typeof(UnitFormatType))
.OfType<UnitFormatType>().ToList();
System.Diagnostics.Debug.WriteLine("All available units\r\n");

foreach (var unit_format in unit_formats)
{
var units = DisplayUnitFormats.Instance.GetPredefinedProjectUnitFormats(unit_format);
System.Diagnostics.Debug.WriteLine(unit_format.ToString());

foreach (var display_unit_format in units)
{
var line = $"{display_unit_format.DisplayName}, {display_unit_format.UnitCode}";
System.Diagnostics.Debug.WriteLine(line);
}
System.Diagnostics.Debug.WriteLine("");
}

获取当前项目的单位格式列表

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
//Must be on the QueuedTask.Run()

var unit_formats = Enum.GetValues(typeof(UnitFormatType))
.OfType<UnitFormatType>().ToList();
System.Diagnostics.Debug.WriteLine("Project units\r\n");

foreach (var unit_format in unit_formats)
{
var units = DisplayUnitFormats.Instance.GetProjectUnitFormats(unit_format);
System.Diagnostics.Debug.WriteLine(unit_format.ToString());

foreach (var display_unit_format in units)
{
var line = $"{display_unit_format.DisplayName}, {display_unit_format.UnitCode}";
System.Diagnostics.Debug.WriteLine(line);
}
System.Diagnostics.Debug.WriteLine("");
}

获取当前项目的特定单位格式列表

1
2
3
4
5
6
//Must be on the QueuedTask.Run()

//UnitFormatType.Angular, UnitFormatType.Area, UnitFormatType.Distance,
//UnitFormatType.Direction, UnitFormatType.Location, UnitFormatType.Page
//UnitFormatType.Symbol2D, UnitFormatType.Symbol3D
var units = DisplayUnitFormats.Instance.GetProjectUnitFormats(UnitFormatType.Distance);

获取当前项目的默认格式列表

1
2
3
4
5
6
7
8
9
10
11
12
13
//Must be on the QueuedTask.Run()

var unit_formats = Enum.GetValues(typeof(UnitFormatType))
.OfType<UnitFormatType>().ToList();
System.Diagnostics.Debug.WriteLine("Default project units\r\n");

foreach (var unit_format in unit_formats)
{
var default_unit = DisplayUnitFormats.Instance.GetDefaultProjectUnitFormat(unit_format);
var line = $"{unit_format.ToString()}: {default_unit.DisplayName}, {default_unit.UnitCode}";
System.Diagnostics.Debug.WriteLine(line);
}
System.Diagnostics.Debug.WriteLine("");

获取当前项目的特定默认单位格式

1
2
3
4
5
6
7
//Must be on the QueuedTask.Run()

//UnitFormatType.Angular, UnitFormatType.Area, UnitFormatType.Distance,
//UnitFormatType.Direction, UnitFormatType.Location, UnitFormatType.Page
//UnitFormatType.Symbol2D, UnitFormatType.Symbol3D
var default_unit = DisplayUnitFormats.Instance.GetDefaultProjectUnitFormat(
UnitFormatType.Distance);

为当前项目设置特定的单位格式列表

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
//Must be on the QueuedTask.Run()

//UnitFormatType.Angular, UnitFormatType.Area, UnitFormatType.Distance,
//UnitFormatType.Direction, UnitFormatType.Location

//Get the full list of all available location units
var all_units = DisplayUnitFormats.Instance.GetPredefinedProjectUnitFormats(
UnitFormatType.Location);
//keep units with an even factory code
var list_units = all_units.Where(du => du.UnitCode % 2 == 0).ToList();

//set them as the new location unit collection. A new default is not being specified...
DisplayUnitFormats.Instance.SetProjectUnitFormats(list_units);

//set them as the new location unit collection along with a new default
DisplayUnitFormats.Instance.SetProjectUnitFormats(
list_units, list_units.First());

//Note: UnitFormatType.Page, UnitFormatType.Symbol2D, UnitFormatType.Symbol3D
//cannot be set.

设置项目单位格式的默认值

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
//Must be on the QueuedTask.Run()

var unit_formats = Enum.GetValues(typeof(UnitFormatType)).OfType<UnitFormatType>().ToList();
foreach (var unit_type in unit_formats)
{
var current_default = DisplayUnitFormats.Instance.GetDefaultProjectUnitFormat(unit_type);
//Arbitrarily pick the last unit in each unit format list
var replacement = DisplayUnitFormats.Instance.GetProjectUnitFormats(unit_type).Last();
DisplayUnitFormats.Instance.SetDefaultProjectUnitFormat(replacement);

var line = $"{current_default.DisplayName}, {current_default.UnitName}, {current_default.UnitCode}";
var line2 = $"{replacement.DisplayName}, {replacement.UnitName}, {replacement.UnitCode}";

System.Diagnostics.Debug.WriteLine($"Format: {unit_type.ToString()}");
System.Diagnostics.Debug.WriteLine($" Current default: {line}");
System.Diagnostics.Debug.WriteLine($" Replacement default: {line2}");
}

更新项目的单位格式

1
2
3
4
5
6
7
8
9
10
11
12
13
//UnitFormatType.Angular, UnitFormatType.Area, UnitFormatType.Distance, 
//UnitFormatType.Direction, UnitFormatType.Location
var angle_units = DisplayUnitFormats.Instance.GetProjectUnitFormats(UnitFormatType.Angular);

//Edit the display name of each unit - append the abbreviation
foreach (var unit in angle_units)
{
unit.DisplayName = $"{unit.DisplayName} ({unit.Abbreviation})";
}
//apply the changes to the units and set the default to be the first entry
DisplayUnitFormats.Instance.SetProjectUnitFormats(angle_units, angle_units.First());

//The project must be saved to persist the changes...

应用选项

获取常规选项

1
2
3
4
5
6
7
8
9
10
11
12
13
var startMode = ApplicationOptions.GeneralOptions.StartupOption;
var aprx_path = ApplicationOptions.GeneralOptions.StartupProjectPath;

var hf_option = ApplicationOptions.GeneralOptions.HomeFolderOption;
var folder = ApplicationOptions.GeneralOptions.CustomHomeFolder;

var gdb_option = ApplicationOptions.GeneralOptions.DefaultGeodatabaseOption;
var def_gdb = ApplicationOptions.GeneralOptions.CustomDefaultGeodatabase;

var tbx_option = ApplicationOptions.GeneralOptions.DefaultToolboxOption;
var def_tbx = ApplicationOptions.GeneralOptions.CustomDefaultToolbox;

var create_in_folder = ApplicationOptions.GeneralOptions.ProjectCreateInFolder;

将“常规选项”设置为使用自定义设置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
//Set the application to use a custom project, home folder, gdb, and toolbox
//In each case, the custom _path_ must be set _first_ before
//setting the "option". This ensures the application remains
//in a consistent state. This is the same behavior as on the Pro UI.
if (string.IsNullOrEmpty(ApplicationOptions.GeneralOptions.StartupProjectPath))
ApplicationOptions.GeneralOptions.StartupProjectPath = @"D:\data\usa.aprx";//custom project path first
ApplicationOptions.GeneralOptions.StartupOption = StartProjectMode.WithDefaultProject;//option to use it second

if (string.IsNullOrEmpty(ApplicationOptions.GeneralOptions.CustomHomeFolder))
ApplicationOptions.GeneralOptions.CustomHomeFolder = @"D:\home_folder";//custom home folder first
ApplicationOptions.GeneralOptions.HomeFolderOption = OptionSetting.UseCustom;//option to use it second

if (string.IsNullOrEmpty(ApplicationOptions.GeneralOptions.CustomDefaultGeodatabase))
ApplicationOptions.GeneralOptions.CustomDefaultGeodatabase = @"D:\data\usa.gdb";//custom gdb path first
ApplicationOptions.GeneralOptions.DefaultGeodatabaseOption = OptionSetting.UseCustom;//option to use it second

if (string.IsNullOrEmpty(ApplicationOptions.GeneralOptions.CustomDefaultToolbox))
ApplicationOptions.GeneralOptions.CustomDefaultToolbox = @"D:\data\usa.tbx";//custom toolbox path first
ApplicationOptions.GeneralOptions.DefaultToolboxOption = OptionSetting.UseCustom;//option to use it second

设置常规选项以使用默认值

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
//Default options can be set regardless of the value of the "companion"
//path (to a project, folder, gdb, toolbox, etc.). The path value is ignored if
//the option setting does not use it. This is the same behavior as on the Pro UI.
ApplicationOptions.GeneralOptions.StartupOption = StartProjectMode.ShowStartPage;
ApplicationOptions.GeneralOptions.HomeFolderOption = OptionSetting.UseDefault;
ApplicationOptions.GeneralOptions.DefaultGeodatabaseOption = OptionSetting.UseDefault;
ApplicationOptions.GeneralOptions.DefaultToolboxOption = OptionSetting.UseDefault;//set default option first

//path values can (optionally) be set (back) to null if their
//"companion" option setting is the default option.
if (ApplicationOptions.GeneralOptions.StartupOption != StartProjectMode.WithDefaultProject)
ApplicationOptions.GeneralOptions.StartupProjectPath = null;
if (ApplicationOptions.GeneralOptions.HomeFolderOption == OptionSetting.UseDefault)
ApplicationOptions.GeneralOptions.CustomHomeFolder = null;
if (ApplicationOptions.GeneralOptions.DefaultGeodatabaseOption == OptionSetting.UseDefault)
ApplicationOptions.GeneralOptions.CustomDefaultGeodatabase = null;
if (ApplicationOptions.GeneralOptions.DefaultToolboxOption == OptionSetting.UseDefault)
ApplicationOptions.GeneralOptions.CustomDefaultToolbox = null;

获取下载选项

1
2
3
4
5
6
7
8
9
10
11
12
var staging = ApplicationOptions.DownloadOptions.StagingLocation;

var ppkx_loc = ApplicationOptions.DownloadOptions.UnpackPPKXLocation;
var ask_ppkx_loc = ApplicationOptions.DownloadOptions.AskForUnpackPPKXLocation;

var other_loc = ApplicationOptions.DownloadOptions.UnpackOtherLocation;
var ask_other_loc = ApplicationOptions.DownloadOptions.AskForUnpackOtherLocation;
var use_proj_folder = ApplicationOptions.DownloadOptions.UnpackOtherToProjectLocation;

var offline_loc = ApplicationOptions.DownloadOptions.OfflineMapsLocation;
var ask_offline_loc = ApplicationOptions.DownloadOptions.AskForOfflineMapsLocation;
var use_proj_folder_offline = ApplicationOptions.DownloadOptions.OfflineMapsToProjectLocation;

设置共享和发布的暂存位置

1
ApplicationOptions.DownloadOptions.StagingLocation = @"D:\data\staging";

设置 PPKX 的下载选项

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
//Options are mutually exclusive.

//Setting ApplicationOptions.DownloadOptions.AskForUnpackPPKXLocation = true
//superseeds any value in ApplicationOptions.DownloadOptions.UnpackPPKXLocation
//and will prompt the user on an unpack. The value of
//ApplicationOptions.DownloadOptions.UnpackPPKXLocation will be unaffected
//and is ignored. This is the same behavior as on the Pro UI.
ApplicationOptions.DownloadOptions.AskForUnpackPPKXLocation = true;//override location

//The default location is typically <My Documents>\ArcGIS\Packages
//Setting ApplicationOptions.DownloadOptions.UnpackPPKXLocation to any
//location overrides ApplicationOptions.DownloadOptions.AskForUnpackPPKXLocation
//and sets it to false. This is the same behavior as on the Pro UI.
ApplicationOptions.DownloadOptions.UnpackPPKXLocation = @"D:\data\for_ppkx";

//Or, if ApplicationOptions.DownloadOptions.UnpackPPKXLocation already
//contains a valid path, set ApplicationOptions.DownloadOptions.AskForUnpackPPKXLocation
//explicitly to false to use the UnpackPPKXLocation
if (!string.IsNullOrEmpty(ApplicationOptions.DownloadOptions.UnpackPPKXLocation))
ApplicationOptions.DownloadOptions.AskForUnpackPPKXLocation = false;

设置解压缩的下载选项其他

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
//UnpackOther settings control unpacking of anything _other than_
//a ppkx or aptx. Options are mutually exclusive.

//Set ApplicationOptions.DownloadOptions.UnpackOtherLocation explicitly to
//toggle ApplicationOptions.DownloadOptions.AskForUnpackOtherLocation and
//ApplicationOptions.DownloadOptions.UnpackOtherToProjectLocation to false
//Note: default is typically <My Documents>\ArcGIS\Packages, _not_ null.
//This is the same behavior as on the Pro UI.
ApplicationOptions.DownloadOptions.UnpackOtherLocation = @"D:\data\for_other";

//or...to use a location already stored in UnpackOtherLocation as the
//default without changing it,
//set ApplicationOptions.DownloadOptions.AskForUnpackOtherLocation and
//ApplicationOptions.DownloadOptions.UnpackOtherToProjectLocation to false
//explicitly. This is the same behavior as on the Pro UI.
if (!string.IsNullOrEmpty(ApplicationOptions.DownloadOptions.UnpackOtherLocation))
{
ApplicationOptions.DownloadOptions.AskForUnpackOtherLocation = false;
ApplicationOptions.DownloadOptions.UnpackOtherToProjectLocation = false;
}

//Setting ApplicationOptions.DownloadOptions.AskForUnpackOtherLocation to
//true overrides any UnpackOtherLocation value and sets
//ApplicationOptions.DownloadOptions.UnpackOtherToProjectLocation to false.
//This is the same behavior as on the Pro UI.
ApplicationOptions.DownloadOptions.AskForUnpackOtherLocation = true;

//Setting ApplicationOptions.DownloadOptions.UnpackOtherToProjectLocation to
//true overrides any UnpackOtherLocation value and sets
//ApplicationOptions.DownloadOptions.AskForUnpackOtherLocation to false.
//This is the same behavior as on the Pro UI.
ApplicationOptions.DownloadOptions.UnpackOtherToProjectLocation = false;

设置离线地图的下载选项

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
//OfflineMaps settings control where map content that is taken
//offline is copied to on the local machine. Options are mutually exclusive.

//Set ApplicationOptions.DownloadOptions.OfflineMapsLocation explicitly to
//toggle ApplicationOptions.DownloadOptions.AskForOfflineMapsLocation and
//ApplicationOptions.DownloadOptions.OfflineMapsToProjectLocation to false
//Note: default is typically <My Documents>\ArcGIS\OfflineMaps, _not_ null.
//This is the same behavior as on the Pro UI.
ApplicationOptions.DownloadOptions.OfflineMapsLocation = @"D:\data\for_offline";

//or...to use a location already stored in OfflineMapsLocation as the
//default without changing it,
//set ApplicationOptions.DownloadOptions.AskForOfflineMapsLocation and
//ApplicationOptions.DownloadOptions.OfflineMapsToProjectLocation to false
//explicitly.
if (!string.IsNullOrEmpty(ApplicationOptions.DownloadOptions.OfflineMapsLocation))
{
ApplicationOptions.DownloadOptions.AskForOfflineMapsLocation = false;
ApplicationOptions.DownloadOptions.OfflineMapsToProjectLocation = false;
}

//Setting ApplicationOptions.DownloadOptions.AskForOfflineMapsLocation to
//true overrides any OfflineMapsLocation value and sets
//ApplicationOptions.DownloadOptions.OfflineMapsToProjectLocation to false.
//This is the same behavior as on the Pro UI.
ApplicationOptions.DownloadOptions.AskForOfflineMapsLocation = true;

//Setting ApplicationOptions.DownloadOptions.OfflineMapsToProjectLocation to
//true overrides any OfflineMapsLocation value and sets
//ApplicationOptions.DownloadOptions.AskForOfflineMapsLocation to false.
//This is the same behavior as on the Pro UI.
ApplicationOptions.DownloadOptions.OfflineMapsToProjectLocation = true;

核心主机

初始化核心主机

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
using ArcGIS.Core.Data;
//There must be a reference to ArcGIS.CoreHost.dll
using ArcGIS.Core.Hosting;

class Program {
//[STAThread] must be present on the Application entry point
[STAThread]
static void Main(string[] args) {

//Call Host.Initialize before constructing any objects from ArcGIS.Core
try {
Host.Initialize();
}
catch (Exception e) {
// Error (missing installation, no license, 64 bit mismatch, etc.)
Console.WriteLine(string.Format("Initialization failed: {0}",e.Message));
return;
}

//if we are here, ArcGIS.Core is successfully initialized
Geodatabase gdb = new Geodatabase(new FileGeodatabaseConnectionPath(new Uri(@"C:\Data\SDK\GDB\MySampleData.gdb")));
IReadOnlyList<TableDefinition> definitions = gdb.GetDefinitions<FeatureClassDefinition>();

foreach (var fdsDef in definitions) {
Console.WriteLine(TableString(fdsDef as TableDefinition));
}
Console.Read();
}

private static string TableString(TableDefinition table) {
string alias = table.GetAliasName();
string name = table.GetName();
return string.Format("{0} ({1})", alias.Length > 0 ? alias : name, name);
}
}

编辑

编辑操作方法

编辑操作创建要素

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
var createFeatures = new EditOperation();
createFeatures.Name = "Create Features";
//Create a feature with a polygon
var token = createFeatures.Create(featureLayer, polygon);
if (createFeatures.IsSucceeded)
{
// token.ObjectID wll be populated with the objectID of the created feature after Execute has been successful
}
//Do a create features and set attributes
var attributes = new Dictionary<string, object>();
attributes.Add("SHAPE", polygon);
attributes.Add("NAME", "Corner Market");
attributes.Add("SIZE", 1200.5);
attributes.Add("DESCRIPTION", "Corner Market");

createFeatures.Create(featureLayer, attributes);

//Create features using the current template
//Must be within a MapTool
createFeatures.Create(this.CurrentTemplate, polygon);

//Execute to execute the operation
//Must be called within QueuedTask.Run
createFeatures.Execute();

//or use async flavor
//await createFeatures.ExecuteAsync();

使用当前模板创建要素

1
2
3
4
5
6
7
var myTemplate = ArcGIS.Desktop.Editing.Templates.EditingTemplate.Current;

//Create edit operation and execute
var op = new ArcGIS.Desktop.Editing.EditOperation();
op.Name = "Create my feature";
op.Create(myTemplate, geometry);
op.Execute();

从修改后的检查器创建要素

1
2
3
4
5
6
7
8
9
10
11
12
13
14
var insp = new ArcGIS.Desktop.Editing.Attributes.Inspector();
insp.Load(layer, 86);

ArcGIS.Desktop.Framework.Threading.Tasks.QueuedTask.Run(() =>
{
// modify attributes if necessary
// insp["Field1"] = newValue;

//Create new feature from an existing inspector (copying the feature)
var createOp = new ArcGIS.Desktop.Editing.EditOperation();
createOp.Name = "Create from insp";
createOp.Create(insp.MapMember, insp.ToDictionary(a => a.FieldName, a => a.CurrentValue));
createOp.Execute();
});

从 CSV 文件创建要素

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
//Run on MCT
ArcGIS.Desktop.Framework.Threading.Tasks.QueuedTask.Run(() =>
{
//Create the edit operation
var createOperation = new ArcGIS.Desktop.Editing.EditOperation();
createOperation.Name = "Generate points";
createOperation.SelectNewFeatures = false;

// determine the shape field name - it may not be 'Shape'
string shapeField = layer.GetFeatureClass().GetDefinition().GetShapeField();

//Loop through csv data
foreach (var item in csvData)
{

//Create the point geometry
ArcGIS.Core.Geometry.MapPoint newMapPoint =
ArcGIS.Core.Geometry.MapPointBuilderEx.CreateMapPoint(item.X, item.Y);

// include the attributes via a dictionary
var atts = new Dictionary<string, object>();
atts.Add("StopOrder", item.StopOrder);
atts.Add("FacilityID", item.FacilityID);
atts.Add(shapeField, newMapPoint);

// queue feature creation
createOperation.Create(layer, atts);
}

// execute the edit (feature creation) operation
return createOperation.Execute();
});

编辑操作 使用表模板在表中创建行

1
2
3
4
5
6
var tableTemplate = standaloneTable.GetTemplates().FirstOrDefault();
var createRow = new EditOperation();
createRow.Name = "Create a row in a table";
//Creating a new row in a standalone table using the table template of your choice
createRow.Create(tableTemplate);
createRow.Execute();

编辑操作剪辑特征

1
2
3
4
5
6
7
8
9
var clipFeatures = new EditOperation();
clipFeatures.Name = "Clip Features";
clipFeatures.Clip(featureLayer, oid, clipPoly, ClipMode.PreserveArea);
//Execute to execute the operation
//Must be called within QueuedTask.Run
clipFeatures.Execute();

//or use async flavor
//await clipFeatures.ExecuteAsync();

编辑操作切割要素

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
var select = MapView.Active.SelectFeatures(clipPoly);

var cutFeatures = new EditOperation();
cutFeatures.Name = "Cut Features";
cutFeatures.Split(featureLayer, oid, cutLine);

//Cut all the selected features in the active view
//Select using a polygon (for example)
//at 2.x - var kvps = MapView.Active.SelectFeatures(polygon).Select(
// k => new KeyValuePair<MapMember, List<long>>(k.Key as MapMember, k.Value));
//cutFeatures.Split(kvps, cutLine);
var sset = MapView.Active.SelectFeatures(polygon);
cutFeatures.Split(sset, cutLine);

//Execute to execute the operation
//Must be called within QueuedTask.Run
cutFeatures.Execute();

//or use async flavor
//await cutFeatures.ExecuteAsync();

编辑操作删除要素

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
var deleteFeatures = new EditOperation();
deleteFeatures.Name = "Delete Features";
var table = MapView.Active.Map.StandaloneTables[0];
//Delete a row in a standalone table
deleteFeatures.Delete(table, oid);

//Delete all the selected features in the active view
//Select using a polygon (for example)
//at 2.x - var selection = MapView.Active.SelectFeatures(polygon).Select(
// k => new KeyValuePair<MapMember, List<long>>(k.Key as MapMember, k.Value));
//deleteFeatures.Delete(selection);
var selection = MapView.Active.SelectFeatures(polygon);
deleteFeatures.Delete(selection);

//Execute to execute the operation
//Must be called within QueuedTask.Run
deleteFeatures.Execute();

//or use async flavor
//await deleteFeatures.ExecuteAsync();

编辑操作重复要素

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
{
var duplicateFeatures = new EditOperation();
duplicateFeatures.Name = "Duplicate Features";

//Duplicate with an X and Y offset of 500 map units
//At 2.x duplicateFeatures.Duplicate(featureLayer, oid, 500.0, 500.0, 0.0);

//Execute to execute the operation
//Must be called within QueuedTask.Run
var insp2 = new Inspector();
insp2.Load(featureLayer, oid);
var geom = insp2["SHAPE"] as Geometry;

var rtoken = duplicateFeatures.Create(insp2.MapMember, insp2.ToDictionary(a => a.FieldName, a => a.CurrentValue));
if (duplicateFeatures.Execute())
{
var modifyOp = duplicateFeatures.CreateChainedOperation();
modifyOp.Modify(featureLayer, (long)rtoken.ObjectID, GeometryEngine.Instance.Move(geom, 500.0, 500.0));
modifyOp.Execute();
}

}

编辑操作分解特征

1
2
3
4
5
6
7
8
9
10
11
12
13
var explodeFeatures = new EditOperation();
explodeFeatures.Name = "Explode Features";

//Take a multipart and convert it into one feature per part
//Provide a list of ids to convert multiple
explodeFeatures.Explode(featureLayer, new List<long>() { oid }, true);

//Execute to execute the operation
//Must be called within QueuedTask.Run
explodeFeatures.Execute();

//or use async flavor
//await explodeFeatures.ExecuteAsync();

编辑操作合并功能

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
var mergeFeatures = new EditOperation();
mergeFeatures.Name = "Merge Features";

//Merge three features into a new feature using defaults
//defined in the current template
//At 2.x -
//mergeFeatures.Merge(this.CurrentTemplate as EditingFeatureTemplate, featureLayer, new List<long>() { 10, 96, 12 });
mergeFeatures.Merge(this.CurrentTemplate as EditingRowTemplate, featureLayer, new List<long>() { 10, 96, 12 });

//Merge three features into a new feature in the destination layer
mergeFeatures.Merge(destinationLayer, featureLayer, new List<long>() { 10, 96, 12 });

//Use an inspector to set the new attributes of the merged feature
var inspector = new Inspector();
inspector.Load(featureLayer, oid);//base attributes on an existing feature
//change attributes for the new feature
inspector["NAME"] = "New name";
inspector["DESCRIPTION"] = "New description";

//Merge features into a new feature in the same layer using the
//defaults set in the inspector
mergeFeatures.Merge(featureLayer, new List<long>() { 10, 96, 12 }, inspector);

//Execute to execute the operation
//Must be called within QueuedTask.Run
mergeFeatures.Execute();

//or use async flavor
//await mergeFeatures.ExecuteAsync();

编辑操作 修改单个特征

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
var modifyFeature = new EditOperation();
modifyFeature.Name = "Modify a feature";

//use an inspector
var modifyInspector = new Inspector();
modifyInspector.Load(featureLayer, oid);//base attributes on an existing feature

//change attributes for the new feature
modifyInspector["SHAPE"] = polygon;//Update the geometry
modifyInspector["NAME"] = "Updated name";//Update attribute(s)

modifyFeature.Modify(modifyInspector);

//update geometry and attributes using overload
var featureAttributes = new Dictionary<string, object>();
featureAttributes["NAME"] = "Updated name";//Update attribute(s)
modifyFeature.Modify(featureLayer, oid, polygon, featureAttributes);

//Execute to execute the operation
//Must be called within QueuedTask.Run
modifyFeature.Execute();

//or use async flavor
//await modifyFeatures.ExecuteAsync();

编辑操作 修改多个要素

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
//Search by attribute
var queryFilter = new QueryFilter();
queryFilter.WhereClause = "OBJECTID < 1000000";
//Create list of oids to update
var oidSet = new List<long>();
using (var rc = featureLayer.Search(queryFilter))
{
while (rc.MoveNext())
{
using (var record = rc.Current)
{
oidSet.Add(record.GetObjectID());
}
}
}

//create and execute the edit operation
var modifyFeatures = new EditOperation();
modifyFeatures.Name = "Modify features";
modifyFeatures.ShowProgressor = true;

var muultipleFeaturesInsp = new Inspector();
muultipleFeaturesInsp.Load(featureLayer, oidSet);
muultipleFeaturesInsp["MOMC"] = 24;
modifyFeatures.Modify(muultipleFeaturesInsp);
modifyFeatures.ExecuteAsync();

搜索图层要素并更新字段

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
ArcGIS.Desktop.Framework.Threading.Tasks.QueuedTask.Run(() =>
{
//find layer
var disLayer = ArcGIS.Desktop.Mapping.MapView.Active.Map.FindLayers("Distribution mains").FirstOrDefault() as BasicFeatureLayer;

//Search by attribute
var filter = new ArcGIS.Core.Data.QueryFilter();
filter.WhereClause = "CONTRACTOR = 'KCGM'";

var oids = new List<long>();
using (var rc = disLayer.Search(filter))
{
//Create list of oids to update
while (rc.MoveNext())
{
using (var record = rc.Current)
{
oidSet.Add(record.GetObjectID());
}
}
}

//Create edit operation
var modifyOp = new ArcGIS.Desktop.Editing.EditOperation();
modifyOp.Name = "Update date";

// load features into inspector and update field
var dateInsp = new ArcGIS.Desktop.Editing.Attributes.Inspector();
dateInsp.Load(disLayer, oids);
dateInsp["InspDate"] = "9/21/2013";

// modify and execute
modifyOp.Modify(insp);
modifyOp.Execute();
});

移动要素

1
2
3
4
5
6
7
8
9
10
11
12
13
14
//Get all of the selected ObjectIDs from the layer.
var firstLayer = MapView.Active.Map.GetLayersAsFlattenedList().OfType<FeatureLayer>().FirstOrDefault();
var selectionfromMap = firstLayer.GetSelection();

// set up a dictionary to store the layer and the object IDs of the selected features
var selectionDictionary = new Dictionary<MapMember, List<long>>();
selectionDictionary.Add(firstLayer as MapMember, selectionfromMap.GetObjectIDs().ToList());

var moveFeature = new EditOperation();
moveFeature.Name = "Move features";
//at 2.x - moveFeature.Move(selectionDictionary, 10, 10); //specify your units along axis to move the geometry
moveFeature.Move(SelectionSet.FromDictionary(selectionDictionary), 10, 10); //specify your units along axis to move the geometry

moveFeature.Execute();

将要素移动到特定坐标

1
2
3
4
5
6
7
8
9
10
11
//Get all of the selected ObjectIDs from the layer.
var abLayer = MapView.Active.Map.GetLayersAsFlattenedList().OfType<FeatureLayer>().FirstOrDefault();
var mySelection = abLayer.GetSelection();
var selOid = mySelection.GetObjectIDs().FirstOrDefault();

var moveToPoint = new MapPointBuilderEx(1.0, 2.0, 3.0, 4.0, MapView.Active.Map.SpatialReference); //can pass in coordinates.

var modifyFeatureCoord = new EditOperation();
modifyFeatureCoord.Name = "Move features";
modifyFeatureCoord.Modify(abLayer, selOid, moveToPoint.ToGeometry()); //Modify the feature to the new geometry
modifyFeatureCoord.Execute();

编辑操作平面化要素

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// note - EditOperation.Planarize requires a standard license. 
// An exception will be thrown if Pro is running under a basic license.

var planarizeFeatures = new EditOperation();
planarizeFeatures.Name = "Planarize Features";

//Planarize one or more features
planarizeFeatures.Planarize(featureLayer, new List<long>() { oid });

//Execute to execute the operation
//Must be called within QueuedTask.Run
planarizeFeatures.Execute();

//or use async flavor
//await planarizeFeatures.ExecuteAsync();

编辑操作并行偏移

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
//Create parrallel features from the selected features

//find the roads layer
var roadsLayer = MapView.Active.Map.FindLayers("Roads").FirstOrDefault();

//instatiate paralleloffset builder and set parameters
var parOffsetBuilder = new ParallelOffset.Builder()
{
Selection = MapView.Active.Map.GetSelection(),
Template = roadsLayer.GetTemplate("Freeway"),
Distance = 200,
Side = ParallelOffset.SideType.Both,
Corner = ParallelOffset.CornerType.Mitered,
Iterations = 1,
AlignConnected = false,
CopyToSeparateFeatures = false,
RemoveSelfIntersectingLoops = true
};

//create editoperation and execute
var parrallelOp = new EditOperation();
parrallelOp.Create(parOffsetBuilder);
parrallelOp.Execute();

编辑操作重塑特征

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
var reshapeFeatures = new EditOperation();
reshapeFeatures.Name = "Reshape Features";

reshapeFeatures.Reshape(featureLayer, oid, modifyLine);

//Reshape a set of features that intersect some geometry....

//at 2.x - var selFeatures = MapView.Active.GetFeatures(modifyLine).Select(
// k => new KeyValuePair<MapMember, List<long>>(k.Key as MapMember, k.Value));
//reshapeFeatures.Reshape(selFeatures, modifyLine);

reshapeFeatures.Reshape(MapView.Active.GetFeatures(modifyLine), modifyLine);

//Execute to execute the operation
//Must be called within QueuedTask.Run
reshapeFeatures.Execute();

//or use async flavor
//await reshapeFeatures.ExecuteAsync();

编辑操作旋转要素

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
var rotateFeatures = new EditOperation();
rotateFeatures.Name = "Rotate Features";

//Rotate works on a selected set of features
//Get all features that intersect a polygon

//at 2.x - var rotateSelection = MapView.Active.GetFeatures(polygon).Select(
// k => new KeyValuePair<MapMember, List<long>>(k.Key as MapMember, k.Value));
//rotateFeatures.Rotate(rotateSelection, origin, Math.PI / 2);

//Rotate selected features 90 deg about "origin"
rotateFeatures.Rotate(MapView.Active.GetFeatures(polygon), origin, Math.PI / 2);

//Execute to execute the operation
//Must be called within QueuedTask.Run
rotateFeatures.Execute();

//or use async flavor
//await rotateFeatures.ExecuteAsync();

编辑操作比例要素

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
var scaleFeatures = new EditOperation();
scaleFeatures.Name = "Scale Features";

//Rotate works on a selected set of features

//var scaleSelection = MapView.Active.GetFeatures(polygon).Select(
// k => new KeyValuePair<MapMember, List<long>>(k.Key as MapMember, k.Value));
//scaleFeatures.Scale(scaleSelection, origin, 2.0, 2.0, 0.0);

//Scale the selected features by 2.0 in the X and Y direction
scaleFeatures.Scale(MapView.Active.GetFeatures(polygon), origin, 2.0, 2.0, 0.0);

//Execute to execute the operation
//Must be called within QueuedTask.Run
scaleFeatures.Execute();

//or use async flavor
//await scaleFeatures.ExecuteAsync();

编辑操作拆分要素

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
var splitFeatures = new EditOperation();
splitFeatures.Name = "Split Features";

var splitPoints = new List<MapPoint>() { mp1, mp2, mp3 };

//Split the feature at 3 points
splitFeatures.Split(featureLayer, oid, splitPoints);

// split using percentage
var splitByPercentage = new SplitByPercentage() { Percentage = 33, SplitFromStartPoint = true };
splitFeatures.Split(featureLayer, oid, splitByPercentage);

// split using equal parts
var splitByEqualParts = new SplitByEqualParts() { NumParts = 3 };
splitFeatures.Split(featureLayer, oid, splitByEqualParts);

// split using single distance
var splitByDistance = new SplitByDistance() { Distance = 27.3, SplitFromStartPoint = false };
splitFeatures.Split(featureLayer, oid, splitByDistance);

// split using varying distance
var distances = new List<double>() { 12.5, 38.2, 89.99 };
var splitByVaryingDistance = new SplitByVaryingDistance() { Distances = distances, SplitFromStartPoint = true, ProportionRemainder = true };
splitFeatures.Split(featureLayer, oid, splitByVaryingDistance);

//Execute to execute the operation
//Must be called within QueuedTask.Run
splitFeatures.Execute();

//or use async flavor
//await splitAtPointsFeatures.ExecuteAsync();

编辑操作变换特征

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
var transformFeatures = new EditOperation();
transformFeatures.Name = "Transform Features";

//Transform a selected set of features
//At 2.x - var transformSelection = MapView.Active.GetFeatures(polygon).Select(
// k => new KeyValuePair<MapMember, List<long>>(k.Key as MapMember, k.Value));
//transformFeatures.Transform(transformSelection, linkLayer);
////Transform just a layer
//transformFeatures.Transform(featureLayer, linkLayer);
////Perform an affine transformation
//transformFeatures.TransformAffine(featureLayer, linkLayer);

var affine_transform = new TransformByLinkLayer()
{
LinkLayer = linkLayer,
TransformType = TransformMethodType.Affine //TransformMethodType.Similarity
};
//Transform a selected set of features
transformFeatures.Transform(MapView.Active.GetFeatures(polygon), affine_transform);
//Perform an affine transformation
transformFeatures.Transform(featureLayer, affine_transform);

//Execute to execute the operation
//Must be called within QueuedTask.Run
transformFeatures.Execute();

//or use async flavor
//await transformFeatures.ExecuteAsync();

编辑操作橡皮板功能

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
//Perform rubbersheet by geometries
var rubbersheetMethod = new RubbersheetByGeometries()
{
RubbersheetType = RubbersheetMethodType.Linear, //The RubbersheetType can be Linear of NearestNeighbor
LinkLines = linkLines, //IEnumerable list of link lines (polylines)
AnchorPoints = anchorPoints, //IEnumerable list of anchor points (map points)
LimitedAdjustmentAreas = limitedAdjustmentAreas //IEnumerable list of limited adjustment areas (polygons)
};

var rubbersheetOp = new EditOperation();
//Performs linear rubbersheet transformation on the features belonging to "layer" that fall within the limited adjustment areas
rubbersheetOp.Rubbersheet(layer, rubbersheetMethod);
//Execute the operation
rubbersheetOp.Execute();

//Alternatively, you can also perform rubbersheet by layer
var rubbersheetMethod2 = new RubbersheetByLayers()
{
RubbersheetType = RubbersheetMethodType.NearestNeighbor, //The RubbersheetType can be Linear of NearestNeighbor
LinkLayer = linkLayer,
AnchorPointLayer = anchorPointsLayer,
LimitedAdjustmentAreaLayer = limitedAdjustmentAreaLayer
};

//Performs nearest neighbor rubbersheet transformation on the features belonging to "layer" that fall within the limited adjustment areas
rubbersheetOp.Rubbersheet(layer, rubbersheetMethod2);
//Execute the operation
rubbersheetOp.Execute();

编辑操作 执行剪辑、剪切和平坦化

1
2
3
4
5
6
7
8
9
10
11
12
13
14
//Multiple operations can be performed by a single
//edit operation.
var clipCutPlanarizeFeatures = new EditOperation();
clipCutPlanarizeFeatures.Name = "Clip, Cut, and Planarize Features";
clipCutPlanarizeFeatures.Clip(featureLayer, oid, clipPoly);
clipCutPlanarizeFeatures.Split(featureLayer, oid, cutLine);
clipCutPlanarizeFeatures.Planarize(featureLayer, oid);

//Note: An edit operation is a single transaction.
//Execute the operations (in the order they were declared)
clipCutPlanarizeFeatures.Execute();

//or use async flavor
//await clipCutPlanarizeFeatures.ExecuteAsync();

编辑操作链 编辑操作

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
//Chaining operations is a special case. Use "Chained Operations" when you require multiple transactions 
//to be undo-able with a single "Undo".

//The most common use case for operation chaining is creating a feature with an attachement.
//Adding an attachment requires the object id (of a new feature) has already been created.
var editOperation1 = new EditOperation();
editOperation1.Name = string.Format("Create point in '{0}'", CurrentTemplate.Layer.Name);

long newFeatureID = -1;
//The Create operation has to execute so we can get an object_id
var token2 = editOperation1.Create(this.CurrentTemplate, polygon);
if (editOperation1.IsSucceeded)
{
newFeatureID = (long)token2.ObjectID;
}
//Must be within a QueuedTask
editOperation1.Execute();

//or use async flavor
//await editOperation1.ExecuteAsync();

//Now, because we have the object id, we can add the attachment. As we are chaining it, adding the attachment
//can be undone as part of the "Undo Create" operation. In other words, only one undo operation will show on the
//Pro UI and not two.
var editOperation2 = editOperation1.CreateChainedOperation();
//Add the attachement using the new feature id
editOperation2.AddAttachment(this.CurrentTemplate.Layer, newFeatureID, @"C:\data\images\Hydrant.jpg");

//editOperation1 and editOperation2 show up as a single Undo operation on the UI even though
//we had two transactions
//Must be within a QueuedTask
editOperation2.Execute();

//or use async flavor
//await editOperation2.ExecuteAsync();

编辑操作通过行令牌添加附件

1
2
3
4
5
6
7
8
9
10
11
//ArcGIS Pro 2.5 extends the EditOperation.AddAttachment method to take a RowToken as a paramter.
//This allows you to create a feature, using EditOperation.CreateEx, and add an attachment in one transaction.

var editOpAttach = new EditOperation();
editOperation1.Name = string.Format("Create point in '{0}'", CurrentTemplate.Layer.Name);

var attachRowToken = editOpAttach.Create(this.CurrentTemplate, polygon);
editOpAttach.AddAttachment(attachRowToken, @"c:\temp\image.jpg");

//Must be within a QueuedTask
editOpAttach.Execute();

SetOnUndone, SetOnRedone, SetOnComitted

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
// SetOnUndone, SetOnRedone and SetOnComittedManage can be used to manage 
// external actions(such as writing to a log table) that are associated with
// each edit operation.

//get selected feature and update attribute
var selectedFeatures = MapView.Active.Map.GetSelection();
var testInspector = new Inspector();
testInspector.Load(selectedFeatures.ToDictionary().Keys.First(), selectedFeatures.ToDictionary().Values.First());
testInspector["Name"] = "test";

//create and execute the edit operation
var updateTestField = new EditOperation();
updateTestField.Name = "Update test field";
updateTestField.Modify(insp);

//actions for SetOn...
updateTestField.SetOnUndone(() =>
{
//Sets an action that will be called when this operation is undone.
Debug.WriteLine("Operation is undone");
});

updateTestField.SetOnRedone(() =>
{
//Sets an action that will be called when this editoperation is redone.
Debug.WriteLine("Operation is redone");
});

updateTestField.SetOnComitted((bool b) => //called on edit session save(true)/discard(false).
{
// Sets an action that will be called when this editoperation is committed.
Debug.WriteLine("Operation is committed");
});

updateTestField.Execute();
}

启用编辑

启用编辑

1
2
3
4
5
6
7
8
9
10
11
12
// if not editing
if (!Project.Current.IsEditingEnabled)
{
var res = MessageBox.Show("You must enable editing to use editing tools. Would you like to enable editing?",
"Enable Editing?", System.Windows.MessageBoxButton.YesNoCancel);
if (res == System.Windows.MessageBoxResult.No ||
res == System.Windows.MessageBoxResult.Cancel)
{
return;
}
Project.Current.SetIsEditingEnabledAsync(true);
}

禁用编辑

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
// if editing
if (Project.Current.IsEditingEnabled)
{
var res = MessageBox.Show("Do you want to disable editing? Editing tools will be disabled",
"Disable Editing?", System.Windows.MessageBoxButton.YesNoCancel);
if (res == System.Windows.MessageBoxResult.No ||
res == System.Windows.MessageBoxResult.Cancel)
{
return;
}

//we must check for edits
if (Project.Current.HasEdits)
{
res = MessageBox.Show("Save edits?", "Save Edits?", System.Windows.MessageBoxButton.YesNoCancel);
if (res == System.Windows.MessageBoxResult.Cancel)
return;
else if (res == System.Windows.MessageBoxResult.No)
Project.Current.DiscardEditsAsync();
else
{
Project.Current.SaveEditsAsync();
}
}
Project.Current.SetIsEditingEnabledAsync(false);
}

地图拓扑

构建地图拓扑

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
private async Task BuildGraphWithActiveView()
{
await QueuedTask.Run(() =>
{
//Build the map topology graph
MapView.Active.BuildMapTopologyGraph<TopologyDefinition>(async topologyGraph =>
{
//Getting the nodes and edges present in the graph
var topologyGraphNodes = topologyGraph.GetNodes();
var topologyGraphEdges = topologyGraph.GetEdges();

foreach (var node in topologyGraphNodes)
{
// do something with the node
}
foreach (var edge in topologyGraphEdges)
{
// do something with the edge
}

MessageBox.Show($"Number of topo graph nodes are: {topologyGraphNodes.Count}.\n Number of topo graph edges are {topologyGraphEdges.Count}.", "Map Topology Info");
});
});
}

行事件

订阅行事件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
protected void SubscribeRowEvent()
{
QueuedTask.Run(() =>
{
//Listen for row events on a layer
var featLayer = MapView.Active.GetSelectedLayers().First() as FeatureLayer;
var layerTable = featLayer.GetTable();

//subscribe to row events
var rowCreateToken = RowCreatedEvent.Subscribe(OnRowCreated, layerTable);
var rowChangeToken = RowChangedEvent.Subscribe(OnRowChanged, layerTable);
var rowDeleteToken = RowDeletedEvent.Subscribe(OnRowDeleted, layerTable);
});
}

protected void OnRowCreated(RowChangedEventArgs args)
{
}

protected void OnRowChanged(RowChangedEventArgs args)
{
}

protected void OnRowDeleted(RowChangedEventArgs args)
{
}

在行事件中的映射中的单独表中创建记录

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
// Use the EditOperation in the RowChangedEventArgs to append actions to be executed. 
// Your actions will become part of the operation and combined into one item on the undo stack

private void HookRowCreatedEvent()
{
// subscribe to the RowCreatedEvent
Table table = MapView.Active.Map.GetLayersAsFlattenedList().OfType<FeatureLayer>().FirstOrDefault().GetTable();
RowCreatedEvent.Subscribe(MyRowCreatedEvent, table);
}

private void MyRowCreatedEvent(RowChangedEventArgs args)
{
// RowEvent callbacks are always called on the QueuedTask so there is no need
// to wrap your code within a QueuedTask.Run lambda.

// get the edit operation
var parentEditOp = args.Operation;

// set up some attributes
var attribs = new Dictionary<string, object> { };
attribs.Add("Layer", "Parcels");
attribs.Add("Description", "OID: " + args.Row.GetObjectID().ToString() + " " + DateTime.Now.ToShortTimeString());

//create a record in an audit table
var sTable = MapView.Active.Map.FindStandaloneTables("EditHistory").First();
var table = sTable.GetTable();
parentEditOp.Create(table, attribs);
}

在行事件中的单独表中创建记录

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
// Use the EditOperation in the RowChangedEventArgs to append actions to be executed. 
// Your actions will become part of the operation and combined into one item on the undo stack

private void HookCreatedEvent()
{
// subscribe to the RowCreatedEvent
Table table = MapView.Active.Map.GetLayersAsFlattenedList().OfType<FeatureLayer>().FirstOrDefault().GetTable();
RowCreatedEvent.Subscribe(OnRowCreatedEvent, table);
}

private void OnRowCreatedEvent(RowChangedEventArgs args)
{
// RowEvent callbacks are always called on the QueuedTask so there is no need
// to wrap your code within a QueuedTask.Run lambda.

// update a separate table not in the map when a row is created
// You MUST use the ArcGIS.Core.Data API to edit the table. Do NOT
// use a new edit operation in the RowEvent callbacks
try
{
// get the edit operation
var parentEditOp = args.Operation;

// set up some attributes
var attribs = new Dictionary<string, object> { };
attribs.Add("Description", "OID: " + args.Row.GetObjectID().ToString() + " " + DateTime.Now.ToShortTimeString());

// update Notes table with information about the new feature
using (var geoDatabase = new Geodatabase(new FileGeodatabaseConnectionPath(new Uri(Project.Current.DefaultGeodatabasePath))))
{
using (var table = geoDatabase.OpenDataset<Table>("Notes"))
{
parentEditOp.Create(table, attribs);
}
}
}
catch (Exception e)
{
MessageBox.Show($@"Error in OnRowCreated for OID: {args.Row.GetObjectID()} : {e.ToString()}");
}
}

修改行事件中的记录 - 使用 Row.Store

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
private void HookRowChangedEvent()
{
// subscribe to the RowChangedEvent
Table table = MapView.Active.Map.GetLayersAsFlattenedList().OfType<FeatureLayer>().FirstOrDefault().GetTable();
RowChangedEvent.Subscribe(OnRowChangedEvent, table);
}

private Guid _currentRowChangedGuid = Guid.Empty;
protected void OnRowChangedEvent(RowChangedEventArgs args)
{
// RowEvent callbacks are always called on the QueuedTask so there is no need
// to wrap your code within a QueuedTask.Run lambda.

var row = args.Row;

// check for re-entry (only if row.Store is called)
if (_currentRowChangedGuid == args.Guid)
return;

var fldIdx = row.FindField("POLICE_DISTRICT");
if (fldIdx != -1)
{
//Validate any change to �police district�
// cancel the edit if validation on the field fails
if (row.HasValueChanged(fldIdx))
{
// cancel edit with invalid district (5)
var value = row["POLICE_DISTRICT"].ToString();
if (value == "5")
{
//Cancel edits with invalid �police district� values
args.CancelEdit($"Police district {row["POLICE_DISTRICT"]} is invalid");
}
}

// update the description field
row["Description"] = "Row Changed";

// this update with cause another OnRowChanged event to occur
// keep track of the row guid to avoid recursion
_currentRowChangedGuid = args.Guid;
row.Store();
_currentRowChangedGuid = Guid.Empty;
}
}

修改行事件中的记录 - 使用 EditOperation.Modify

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
private void HookChangedEvent()
{
// subscribe to the RowChangedEvent
Table table = MapView.Active.Map.GetLayersAsFlattenedList().OfType<FeatureLayer>().FirstOrDefault().GetTable();
RowChangedEvent.Subscribe(MyRowChangedEvent, table);
}

private void MyRowChangedEvent(RowChangedEventArgs args)
{
// RowEvent callbacks are always called on the QueuedTask so there is no need
// to wrap your code within a QueuedTask.Run lambda.

//example of modifying a field on a row that has been created
var parentEditOp = args.Operation;

// avoid recursion
if (_lastEdit != args.Guid)
{
//update field on change
parentEditOp.Modify(args.Row, "ZONING", "New");

_lastEdit = args.Guid;
}
}

确定编辑时几何图形是否更改

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
private static FeatureLayer featureLayer;
private static void DetermineGeometryChange()
{
featureLayer = MapView.Active?.Map.GetLayersAsFlattenedList().OfType<FeatureLayer>().FirstOrDefault();
if (featureLayer == null)
return;

QueuedTask.Run(() =>
{
//Listen to the RowChangedEvent that occurs when a Row is changed.
ArcGIS.Desktop.Editing.Events.RowChangedEvent.Subscribe(OnRowChangedEvent2, featureLayer.GetTable());
});
}
private static void OnRowChangedEvent2(RowChangedEventArgs args)
{
// RowEvent callbacks are always called on the QueuedTask so there is no need
// to wrap your code within a QueuedTask.Run lambda.

//Get the layer's definition
var lyrDefn = featureLayer.GetFeatureClass().GetDefinition();
//Get the shape field of the feature class
string shapeField = lyrDefn.GetShapeField();
//Index of the shape field
var shapeIndex = lyrDefn.FindField(shapeField);
//Original geometry of the modified row
var geomOrig = args.Row.GetOriginalValue(shapeIndex) as Geometry;
//New geometry of the modified row
var geomNew = args.Row[shapeIndex] as Geometry;
//Compare the two
bool shapeChanged = geomOrig.IsEqual(geomNew);
}

取消删除

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
public static void StopADelete()
{
// subscribe to the RowDeletedEvent for the appropriate table
Table table = MapView.Active.Map.GetLayersAsFlattenedList().OfType<FeatureLayer>().FirstOrDefault().GetTable();
RowDeletedEvent.Subscribe(OnRowDeletedEvent, table);
}

private static void OnRowDeletedEvent(RowChangedEventArgs args)
{
// RowEvent callbacks are always called on the QueuedTask so there is no need
// to wrap your code within a QueuedTask.Run lambda.

var row = args.Row;

// cancel the delete if the feature is in Police District 5

var fldIdx = row.FindField("POLICE_DISTRICT");
if (fldIdx != -1)
{
var value = row[fldIdx].ToString();
if (value == "5")
{
//cancel with dialog
// Note - feature edits on Hosted and Standard Feature Services cannot be cancelled.
args.CancelEdit("Delete Event\nAre you sure", true);

// or cancel without a dialog
// args.CancelEdit();
}
}
}

编辑已完成事件

订阅编辑已完成事件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
protected void subEditEvents()
{
//subscribe to editcompleted
var eceToken = EditCompletedEvent.Subscribe(onEce);
}

protected Task onEce(EditCompletedEventArgs args)
{
//show number of edits
Console.WriteLine("Creates: " + args.Creates.ToDictionary().Values.Sum(list => list.Count).ToString());
Console.WriteLine("Modifies: " + args.Modifies.ToDictionary().Values.Sum(list => list.Count).ToString());
Console.WriteLine("Deletes: " + args.Deletes.ToDictionary().Values.Sum(list => list.Count).ToString());
return Task.FromResult(0);
}

检查员

将要素从图层加载到检查器中

1
2
3
4
5
6
7
8
// get the first feature layer in the map
var firstFeatureLayer = ArcGIS.Desktop.Mapping.MapView.Active.Map.GetLayersAsFlattenedList().
OfType<ArcGIS.Desktop.Mapping.FeatureLayer>().FirstOrDefault();

// create an instance of the inspector class
var inspector = new ArcGIS.Desktop.Editing.Attributes.Inspector();
// load the feature with ObjectID 'oid' into the inspector
await inspector.LoadAsync(firstFeatureLayer, oid);

将地图选择加载到检查器中

1
2
3
4
5
6
7
8
9
// get the currently selected features in the map
var selectedFeatures = ArcGIS.Desktop.Mapping.MapView.Active.Map.GetSelection();
// get the first layer and its corresponding selected feature OIDs
var firstSelectionSet = selectedFeatures.ToDictionary().First();

// create an instance of the inspector class
var inspector = new ArcGIS.Desktop.Editing.Attributes.Inspector();
// load the selected features into the inspector using a list of object IDs
await inspector.LoadAsync(firstSelectionSet.Key, firstSelectionSet.Value);

获取所选要素的属性值

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
QueuedTask.Run(() =>
{

// get the currently selected features in the map
var selectedFeatures = ArcGIS.Desktop.Mapping.MapView.Active.Map.GetSelection();

// get the first layer and its corresponding selected feature OIDs
var firstSelectionSet = selectedFeatures.ToDictionary().First();

// create an instance of the inspector class
var inspector = new ArcGIS.Desktop.Editing.Attributes.Inspector();

// load the selected features into the inspector using a list of object IDs
inspector.Load(firstSelectionSet.Key, firstSelectionSet.Value);

//get the value of
var pscode = inspector["STATE_NAME"];
var myGeometry = inspector.Shape;
});

将地图选择加载到检查器并更改属性

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// get the currently selected features in the map
var selectedFeatures = ArcGIS.Desktop.Mapping.MapView.Active.Map.GetSelection();
// get the first layer and its corresponding selected feature OIDs
var firstSelectionSet = selectedFeatures.ToDictionary().First();

// create an instance of the inspector class
var inspector = new ArcGIS.Desktop.Editing.Attributes.Inspector();
// load the selected features into the inspector using a list of object IDs
await inspector.LoadAsync(firstSelectionSet.Key, firstSelectionSet.Value);

// assign the new attribute value to the field "Description"
// if more than one features are loaded, the change applies to all features
inspector["Description"] = "The new value.";
// apply the changes as an edit operation - but with no undo/redo
await inspector.ApplyAsync();

使用检查器获取图层方案

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
QueuedTask.Run(() =>
{
var firstFeatureLayer = MapView.Active.Map.GetLayersAsFlattenedList().OfType<ArcGIS.Desktop.Mapping.FeatureLayer>().FirstOrDefault();

// create an instance of the inspector class
var inspector = new ArcGIS.Desktop.Editing.Attributes.Inspector();

// load the layer
inspector.LoadSchema(firstFeatureLayer);

// iterate through the attributes, looking at properties
foreach (var attribute in inspector)
{
var fldName = attribute.FieldName;
var fldAlias = attribute.FieldAlias;
var fldType = attribute.FieldType;
int idxFld = attribute.FieldIndex;
var fld = attribute.GetField();
var isNullable = attribute.IsNullable;
var isEditable = attribute.IsEditable;
var isVisible = attribute.IsVisible;
var isSystemField = attribute.IsSystemField;
var isGeometryField = attribute.IsGeometryField;
}
});

检查器.添加验证

1
2
3
4
5
6
7
8
9
10
var insp = new Inspector();
insp.LoadSchema(featLayer);
var attrib = insp.Where(a => a.FieldName == "Mineral").First();

attrib.AddValidate(() =>
{
if (attrib.CurrentValue.ToString() == "Salt")
return Enumerable.Empty<ArcGIS.Desktop.Editing.Attributes.Attribute.ValidationError>();
else return new[] { ArcGIS.Desktop.Editing.Attributes.Attribute.ValidationError.Create("Error", ArcGIS.Desktop.Editing.Attributes.Severity.Low) };
});

访问 Blob 字段

使用属性检查器读取和写入 Blob 字段

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
QueuedTask.Run(() =>
{
//get selected feature into inspector
var selectedFeatures = MapView.Active.Map.GetSelection();

var insp = new Inspector();
insp.Load(selectedFeatures.ToDictionary().Keys.First(), selectedFeatures.ToDictionary().Values.First());

//read a blob field and save to a file
var msw = new MemoryStream();
msw = insp["Blobfield"] as MemoryStream;
using (FileStream file = new FileStream(@"d:\temp\blob.jpg", FileMode.Create, FileAccess.Write))
{
msw.WriteTo(file);
}

//read file into memory stream
var msr = new MemoryStream();
using (FileStream file = new FileStream(@"d:\images\Hydrant.jpg", FileMode.Open, FileAccess.Read))
{
file.CopyTo(msr);
}

//put the memory stream in the blob field and save to feature
var op = new EditOperation();
op.Name = "Blob Inspector";
insp["Blobfield"] = msr;
op.Modify(insp);
op.Execute();
});

在回调中使用行游标读取和写入 Blob 字段

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
QueuedTask.Run(() =>
{
var editOp = new EditOperation();
editOp.Name = "Blob Cursor";
var featLayer = MapView.Active.Map.FindLayers("Hydrant").First() as FeatureLayer;

editOp.Callback((context) =>
{
using (var rc = featLayer.GetTable().Search(null, false))
{
while (rc.MoveNext())
{
using (var record = rc.Current)
{
//read the blob field and save to a file
var msw = new MemoryStream();
msw = record["BlobField"] as MemoryStream;
using (FileStream file = new FileStream(@"d:\temp\blob.jpg", FileMode.Create, FileAccess.Write))
{
msw.WriteTo(file);
}

//read file into memory stream
var msr = new MemoryStream();
using (FileStream file = new FileStream(@"d:\images\Hydrant.jpg", FileMode.Open, FileAccess.Read))
{
file.CopyTo(msr);
}

//put the memory stream in the blob field and save to feature
record["BlobField"] = msr;
record.Store();

}
}
}
}, featLayer.GetTable());
editOp.Execute();
});

访问栅格字段

从栅格字段读取

1
2
3
4
5
6
7
8
9
10
QueuedTask.Run(() =>
{
var sel = MapView.Active.Map.GetSelection();

//Read a raster from a raster field as an InteropBitmap
//the bitmap can then be used as an imagesource or written to disk
var insp = new ArcGIS.Desktop.Editing.Attributes.Inspector();
insp.Load(sel.ToDictionary().Keys.First(), sel.ToDictionary().Values.First());
var ibmp = insp["Photo"] as System.Windows.Interop.InteropBitmap;
});

将图像写入栅格字段

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
QueuedTask.Run(() =>
{
var sel = MapView.Active.Map.GetSelection();

//Insert an image into a raster field
//Image will be written with no compression
var insp = new ArcGIS.Desktop.Editing.Attributes.Inspector();
insp.Load(sel.ToDictionary().Keys.First(), sel.ToDictionary().Values.First());
insp["Photo"] = @"e:\temp\Hydrant.jpg";

var op = new EditOperation();
op.Name = "Raster Inspector";
op.Modify(insp);
op.Execute();
});

将压缩图像写入栅格字段

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
QueuedTask.Run(() =>
{
//Open the raster dataset on disk and create a compressed raster value dataset object
var dataStore = new ArcGIS.Core.Data.FileSystemDatastore(new ArcGIS.Core.Data.FileSystemConnectionPath(new System.Uri(@"e:\temp"), ArcGIS.Core.Data.FileSystemDatastoreType.Raster));
using (var fileRasterDataset = dataStore.OpenDataset<ArcGIS.Core.Data.Raster.RasterDataset>("Hydrant.jpg"))
{
var storageDef = new ArcGIS.Core.Data.Raster.RasterStorageDef();
storageDef.SetCompressionType(ArcGIS.Core.Data.Raster.RasterCompressionType.JPEG);
storageDef.SetCompressionQuality(90);

var rv = new ArcGIS.Core.Data.Raster.RasterValue();
rv.SetRasterDataset(fileRasterDataset);
rv.SetRasterStorageDef(storageDef);

var sel = MapView.Active.Map.GetSelection();

//insert a raster value object into the raster field
var insp = new ArcGIS.Desktop.Editing.Attributes.Inspector();
insp.Load(sel.ToDictionary().Keys.First(), sel.ToDictionary().Values.First());
insp["Photo"] = rv;

var op = new EditOperation();
op.Name = "Raster Inspector";
op.Modify(insp);
op.Execute();
}
});

使用草图

切换草图选择模式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
//UseSelection = true; (UseSelection must be set to true in the tool constructor or tool activate)
private bool _inSelMode = false;

public bool IsShiftKey(MapViewKeyEventArgs k)
{
return (k.Key == System.Windows.Input.Key.LeftShift ||
k.Key == System.Windows.Input.Key.RightShift);
}

protected override async void OnToolKeyDown(MapViewKeyEventArgs k)
{
//toggle sketch selection mode with a custom key
if (k.Key == System.Windows.Input.Key.W)
{
if (!_inSelMode)
{
k.Handled = true;

// Toggle the tool to select mode.
// The sketch is saved if UseSelection = true;
if (await ActivateSelectAsync(true))
_inSelMode = true;
}
}
else if (!_inSelMode)
{
//disable effect of Shift in the base class.
//Mark the key event as handled to prevent further processing
k.Handled = IsShiftKey(k);
}
}
protected override void OnToolKeyUp(MapViewKeyEventArgs k)
{
if (k.Key == System.Windows.Input.Key.W)
{
if (_inSelMode)
{
_inSelMode = false;
k.Handled = true;//process this one

// Toggle back to sketch mode. If UseSelection = true
// the sketch will be restored
ActivateSelectAsync(false);
}
}
else if (_inSelMode)
{
//disable effect of Shift in the base class.
//Mark the key event as handled to prevent further processing
k.Handled = IsShiftKey(k);
}
}

聆听草图修改事件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
// SketchModified event is fired by 
// - COTS construction tools (except annotation, dimension geometry types),
// - Edit Vertices, Reshape, Align Features
// - 3rd party tools with FireSketchEvents = true


//Subscribe the sketch modified event
//ArcGIS.Desktop.Mapping.Events.SketchModifiedEvent.Subscribe(OnSketchModified);

private void OnSketchModified(ArcGIS.Desktop.Mapping.Events.SketchModifiedEventArgs args)
{
// if not an undo operation
if (!args.IsUndo)
{
// what was the sketch before the change?
var prevSketch = args.PreviousSketch;
// what is the current sketch?
var currentSketch = args.CurrentSketch;
if (currentSketch is Polyline polyline)
{
// Examine the current (last) vertex in the line sketch
var lastSketchPoint = polyline.Points.Last();

// do something with the last point
}
}
}

收听草图完成前事件并修改草图

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// BeforeSketchCompleted event is fired by 
// - COTS construction tools (except annotation, dimension geometry types),
// - Edit Vertices, Reshape, Align Features
// - 3rd party tools with FireSketchEvents = true


//Subscribe to the before sketch completed event
//ArcGIS.Desktop.Mapping.Events.BeforeSketchCompletedEvent.Subscribe(OnBeforeSketchCompleted);

private Task OnBeforeSketchCompleted(BeforeSketchCompletedEventArgs args)
{
//assign sketch Z values from default surface and set the sketch geometry
var modifiedSketch = args.MapView.Map.GetZsFromSurfaceAsync(args.Sketch).Result;
args.SetSketchGeometry(modifiedSketch.Geometry);
return Task.CompletedTask;
}

收听草图完成事件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// SketchCompleted event is fired by 
// - COTS construction tools (except annotation, dimension geometry types),
// - Edit Vertices, Reshape, Align Features
// - 3rd party tools with FireSketchEvents = true


//Subscribe to the sketch completed event
//ArcGIS.Desktop.Mapping.Events.SketchCompletedEvent.Subscribe(OnSketchCompleted);

private void OnSketchCompleted(SketchCompletedEventArgs args)
{
// get the sketch
var finalSketch = args.Sketch;

// do something with the sketch - audit trail perhaps
}

触发草图事件的自定义构造工具

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
internal class ConstructionTool1 : MapTool
{
public ConstructionTool1()
{
IsSketchTool = true;
UseSnapping = true;
// Select the type of construction tool you wish to implement.
// Make sure that the tool is correctly registered with the correct component category type in the daml
SketchType = SketchGeometryType.Line;
//Gets or sets whether the sketch is for creating a feature and should use the CurrentTemplate.
UsesCurrentTemplate = true;

// set FireSketchEvents property to true
FireSketchEvents = true;
}

// ...
}

自定义自定义草图工具的草图符号

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
//Custom tools have the ability to change the symbology used when sketching a new feature. 
//Both the Sketch Segment Symbol and the Vertex Symbol can be modified using the correct set method.
//This is set in the activate method for the tool.
protected override Task OnToolActivateAsync(bool active)
{
QueuedTask.Run(() =>
{
//Getting the current symbology options of the segment
var segmentOptions = GetSketchSegmentSymbolOptions();
//Modifying the primary and secondary color and the width of the segment symbology options
var deepPurple = new CIMRGBColor();
deepPurple.R = 75;
deepPurple.G = 0;
deepPurple.B = 110;
segmentOptions.PrimaryColor = deepPurple;
segmentOptions.Width = 4;
segmentOptions.HasSecondaryColor = true;
var pink = new CIMRGBColor();
pink.R = 219;
pink.G = 48;
pink.B = 130;
segmentOptions.SecondaryColor = pink;
//Creating a new vertex symbol options instance with the values you want
var vertexOptions = new VertexSymbolOptions(VertexSymbolType.RegularUnselected);
var yellow = new CIMRGBColor();
yellow.R = 255;
yellow.G = 215;
yellow.B = 0;
var purple = new CIMRGBColor();
purple.R = 148;
purple.G = 0;
purple.B = 211;
vertexOptions.AngleRotation = 45;
vertexOptions.Color = yellow;
vertexOptions.MarkerType = VertexMarkerType.Star;
vertexOptions.OutlineColor = purple;
vertexOptions.OutlineWidth = 3;
vertexOptions.Size = 5;

//Setting the value of the segment symbol options
SetSketchSegmentSymbolOptions(segmentOptions);
//Setting the value of the vertex symbol options of the regular unselected vertices using the vertexOptions instance created above.
SetSketchVertexSymbolOptions(VertexSymbolType.RegularUnselected, vertexOptions);
});

return base.OnToolActivateAsync(active);
}

捕捉

配置捕捉 - 打开或关闭捕捉

1
2
3
4
5
//enable snapping
ArcGIS.Desktop.Mapping.Snapping.IsEnabled = true;

// disable snapping
ArcGIS.Desktop.Mapping.Snapping.IsEnabled = false;

配置捕捉 - 应用程序捕捉模式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
// set only Point and Edge snapping modes, clear everything else
//At 2.x - ArcGIS.Desktop.Mapping.Snapping.SetSnapModes(SnapMode.Point, SnapMode.Edge);
ArcGIS.Desktop.Mapping.Snapping.SetSnapModes(
new List<SnapMode>() { SnapMode.Point, SnapMode.Edge });

// clear all snap modes
//At 2.x - ArcGIS.Desktop.Mapping.Snapping.SetSnapModes();
ArcGIS.Desktop.Mapping.Snapping.SetSnapModes(null);


// set snap modes one at a time
ArcGIS.Desktop.Mapping.Snapping.SetSnapMode(SnapMode.Edge, true);
ArcGIS.Desktop.Mapping.Snapping.SetSnapMode(SnapMode.End, true);
ArcGIS.Desktop.Mapping.Snapping.SetSnapMode(SnapMode.Intersection, true);

// get current snap modes
var snapModes = ArcGIS.Desktop.Mapping.Snapping.SnapModes;

// get state of a specific snap mode
bool isOn = ArcGIS.Desktop.Mapping.Snapping.GetSnapMode(SnapMode.Vertex);

配置捕捉 - 图层捕捉可捕捉性

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
// is the layer snappable?
bool isSnappable = fLayer.IsSnappable;

// set snappability for a specific layer - needs to run on the MCT
await QueuedTask.Run(() =>
{
// use an extension method
fLayer.SetSnappable(true);

// or use the CIM directly
//var layerDef = fLayer.GetDefinition() as ArcGIS.Core.CIM.CIMGeoFeatureLayerBase;
//layerDef.Snappable = true;
//fLayer.SetDefinition(layerDef);
});


// turn all layers snappability off
layerList = MapView.Active.Map.GetLayersAsFlattenedList().OfType<FeatureLayer>();
await QueuedTask.Run(() =>
{
foreach (var layer in layerList)
{
layer.SetSnappable(false);
}
});

配置捕捉 - 图层捕捉模式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
layerList = MapView.Active.Map.GetLayersAsFlattenedList().OfType<FeatureLayer>();

// configure by layer
foreach (var layer in layerList)
{
// find the state of the snapModes for the layer
var lsm = ArcGIS.Desktop.Mapping.Snapping.GetLayerSnapModes(layer);
bool vertexOn = lsm.Vertex;
// or use
vertexOn = lsm.GetSnapMode(SnapMode.Vertex);

bool edgeOn = lsm.Edge;
// or use
edgeOn = lsm.GetSnapMode(SnapMode.Edge);

bool endOn = lsm.End;
// or use
endOn = lsm.GetSnapMode(SnapMode.End);

// update a few snapModes
// turn Vertex off
lsm.SetSnapMode(SnapMode.Vertex, false);
// intersections on
lsm.SetSnapMode(SnapMode.Intersection, true);

// and set back to the layer
ArcGIS.Desktop.Mapping.Snapping.SetLayerSnapModes(layer, lsm);


// assign a single snap mode at once
ArcGIS.Desktop.Mapping.Snapping.SetLayerSnapModes(layer, SnapMode.Vertex, false);


// turn ALL snapModes on
ArcGIS.Desktop.Mapping.Snapping.SetLayerSnapModes(layer, true);
// turn ALL snapModes off
ArcGIS.Desktop.Mapping.Snapping.SetLayerSnapModes(layer, false);
}


// configure for a set of layers

// set Vertex, edge, end on for a set of layers, other snapModes false
var vee = new LayerSnapModes(false);
vee.Vertex = true;
vee.Edge = true;
vee.End = true;
ArcGIS.Desktop.Mapping.Snapping.SetLayerSnapModes(layerList, vee);


// ensure intersection is on for a set of layers without changing any other snapModes

// get the layer snapModes for the set of layers
var dictLSM = ArcGIS.Desktop.Mapping.Snapping.GetLayerSnapModes(layerList);
foreach (var layer in dictLSM.Keys)
{
var lsm = dictLSM[layer];
lsm.Intersection = true;
}
ArcGIS.Desktop.Mapping.Snapping.SetLayerSnapModes(dictLSM);


// set all snapModes off for a list of layers
ArcGIS.Desktop.Mapping.Snapping.SetLayerSnapModes(layerList, false);

配置捕捉 - 组合示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
// interested in only snapping to the vertices of a specific layer of interest and not the vertices of other layers
// all other snapModes should be off.

// snapping must be on
ArcGIS.Desktop.Mapping.Snapping.IsEnabled = true;

// turn all application snapModes off
//At 2.x - ArcGIS.Desktop.Mapping.Snapping.SetSnapModes();
ArcGIS.Desktop.Mapping.Snapping.SetSnapModes(null);

// set application snapMode vertex on
ArcGIS.Desktop.Mapping.Snapping.SetSnapMode(SnapMode.Vertex, true);

// ensure layer snapping is on
await QueuedTask.Run(() =>
{
fLayer.SetSnappable(true);
});

// set vertex snapping only
var vertexOnly = new LayerSnapModes(false);
vertexOnly.Vertex = true;

// set vertex only for the specific layer, clearing all others
var dict = new Dictionary<Layer, LayerSnapModes>();
dict.Add(fLayer, vertexOnly);
ArcGIS.Desktop.Mapping.Snapping.SetLayerSnapModes(dict, true); // true = reset other layers

捕捉选项

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
//Set snapping options via get/set options
var snapOptions = ArcGIS.Desktop.Mapping.Snapping.GetOptions(myMap);
//At 2.x - snapOptions.SnapToSketchEnabled = true;
snapOptions.IsSnapToSketchEnabled = true;
snapOptions.XYTolerance = 100;
//At 2.x - snapOptions.ZToleranceEnabled = true;
snapOptions.IsZToleranceEnabled = true;
snapOptions.ZTolerance = 0.6;

//turn on snap tip display parts
snapOptions.SnapTipDisplayParts = (int)SnapTipDisplayPart.SnapTipDisplayLayer + (int)SnapTipDisplayPart.SnapTipDisplayType;

//turn off all snaptips
//snapOptions.SnapTipDisplayParts = (int)SnapTipDisplayPart.SnapTipDisplayNone;

//turn on layer display only
//snapOptions.SnapTipDisplayParts = (int)SnapTipDisplayPart.SnapTipDisplayLayer;

//At 2.x - snapOptions.GeometricFeedbackColor = ColorFactory.Instance.RedRGB;
snapOptions.SnapTipColor = ColorFactory.Instance.RedRGB;

ArcGIS.Desktop.Mapping.Snapping.SetOptions(myMap, snapOptions);

撤消/重做

撤消/重做最近的操作

1
2
3
4
5
6
7
//undo
if (MapView.Active.Map.OperationManager.CanUndo)
MapView.Active.Map.OperationManager.UndoAsync();//await as needed

//redo
if (MapView.Active.Map.OperationManager.CanRedo)
MapView.Active.Map.OperationManager.RedoAsync();//await as needed

编辑模板

在图层上按名称查找编辑模板

1
2
3
4
5
6
7
8
9
10
ArcGIS.Desktop.Framework.Threading.Tasks.QueuedTask.Run(() =>
{
//get the templates
var map = ArcGIS.Desktop.Mapping.MapView.Active.Map;
if (map == null)
return;

var mainTemplate = map.FindLayers("main").FirstOrDefault()?.GetTemplate("Distribution");
var mhTemplate = map.FindLayers("Manhole").FirstOrDefault()?.GetTemplate("Active");
});

查找属于独立表的表模板

1
2
3
4
5
6
7
8
9
10
11
ArcGIS.Desktop.Framework.Threading.Tasks.QueuedTask.Run(() =>
{
var map = ArcGIS.Desktop.Mapping.MapView.Active.Map;
if (map == null)
return;
//Get a particular table template
var tableTemplate = map.FindStandaloneTables("Address Points").FirstOrDefault()?.GetTemplate("Residences");
//Get all the templates of a standalone table
var ownersTableTemplates = map.FindStandaloneTables("Owners").FirstOrDefault()?.GetTemplates();
var statisticsTableTemplates = MapView.Active.Map.GetStandaloneTablesAsFlattenedList().First(l => l.Name.Equals("Trading Statistics")).GetTemplates();
});

当前模板

1
EditingTemplate template = EditingTemplate.Current;

更改模板的默认编辑工具

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
public Task ChangeTemplateDefaultToolAsync(ArcGIS.Desktop.Mapping.FeatureLayer flayer,
string toolContentGUID, string templateName)
{
return ArcGIS.Desktop.Framework.Threading.Tasks.QueuedTask.Run(() =>
{

// retrieve the edit template form the layer by name
var template = flayer?.GetTemplate(templateName) as ArcGIS.Desktop.Editing.Templates.EditingTemplate;
// get the definition of the layer
var layerDef = flayer?.GetDefinition() as ArcGIS.Core.CIM.CIMFeatureLayer;
if ((template == null) || (layerDef == null))
return;

if (template.DefaultToolID != this.ID)
{
bool updateLayerDef = false;
if (layerDef.AutoGenerateFeatureTemplates)
{
layerDef.AutoGenerateFeatureTemplates = false;
updateLayerDef = true;
}

// retrieve the CIM edit template definition
var templateDef = template.GetDefinition();

// assign the GUID from the tool DAML definition, for example
// <tool id="TestConstructionTool_SampleSDKTool" categoryRefID="esri_editing_construction_polyline" ….>
// <tooltip heading="">Tooltip text<disabledText /></tooltip>
// <content guid="e58239b3-9c69-49e5-ad4d-bb2ba29ff3ea" />
// </tool>
// then the toolContentGUID would be "e58239b3-9c69-49e5-ad4d-bb2ba29ff3ea"

//At 2.x -
//templateDef.ToolProgID = toolContentGUID;
templateDef.DefaultToolGUID = toolContentGUID;

// set the definition back to
template.SetDefinition(templateDef);

// update the layer definition too
if (updateLayerDef)
flayer.SetDefinition(layerDef);
}
});
}

隐藏或显示模板上的编辑工具

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
QueuedTask.Run(() =>
{
//hide all tools except line tool on layer
var featLayer = MapView.Active.Map.FindLayers("Roads").First();

var editTemplates = featLayer.GetTemplates();
var newCIMEditingTemplates = new List<CIMEditingTemplate>();

foreach (var et in editTemplates)
{
//initialize template by activating default tool
et.ActivateDefaultToolAsync();
var cimEditTemplate = et.GetDefinition();
//get the visible tools on this template
var allTools = et.ToolIDs.ToList();
//add the hidden tools on this template
allTools.AddRange(cimEditTemplate.GetExcludedToolIDs().ToList());
//hide all the tools then allow the line tool

//At 2.x -
//allTools.AddRange(cimEditTemplate.GetExcludedToolDamlIds().ToList());
allTools.AddRange(cimEditTemplate.GetExcludedToolIDs().ToList());

//At 2.x -
//cimEditTemplate.SetExcludedToolDamlIds(allTools.ToArray());
//cimEditTemplate.AllowToolDamlID("esri_editing_SketchLineTool");

cimEditTemplate.SetExcludedToolIDs(allTools.ToArray());
cimEditTemplate.AllowToolID("esri_editing_SketchLineTool");
newCIMEditingTemplates.Add(cimEditTemplate);
}
//update the layer templates
var layerDef = featLayer.GetDefinition() as CIMFeatureLayer;
// Set AutoGenerateFeatureTemplates to false for template changes to stick
layerDef.AutoGenerateFeatureTemplates = false;
layerDef.FeatureTemplates = newCIMEditingTemplates.ToArray();
featLayer.SetDefinition(layerDef);
});

使用图层创建新模板。创建模板

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
var layer = MapView.Active.Map.GetLayersAsFlattenedList().OfType<FeatureLayer>().FirstOrDefault();
if (layer == null)
return;
QueuedTask.Run(() =>
{
var insp = new Inspector();
insp.LoadSchema(layer);

insp["Field1"] = value1;
insp["Field2"] = value2;
insp["Field3"] = value3;

var tags = new[] { "Polygon", "tag1", "tag2" };

// set defaultTool using a daml-id
string defaultTool = "esri_editing_SketchCirclePolygonTool";

// tool filter is the tools to filter OUT
var toolFilter = new[] { "esri_editing_SketchTracePolygonTool" };

// create a new template
var newTemplate = layer.CreateTemplate("My new template", "description", insp, defaultTool, tags, toolFilter);
});

使用表创建新表模板。创建模板

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
var table = MapView.Active.Map.GetStandaloneTablesAsFlattenedList().FirstOrDefault();
if (table == null)
return;
QueuedTask.Run(() =>
{
var tableTemplate = table.GetTemplate("Template1");

var definition = tableTemplate.GetDefinition();
definition.Description = "New definition";
definition.Name = "New name";
//Create new table template using this definition
table.CreateTemplate(definition);

//You can also create a new table template using this extension method. You can use this method the same way you use the layer.CreateTemplate method.
table.CreateTemplate("New template name", "Template description", tags: new string[] { "tag 1", "tag 2" });
});

更新表模板

1
2
3
4
5
6
7
8
9
10
QueuedTask.Run(() =>
{
var tableTemplate = table.GetTemplate("Template1");

var definition = tableTemplate.GetDefinition();
definition.Description = "New definition";
definition.Name = "New name";
// update the definition
tableTemplate.SetDefinition(definition);
});

创建注释模板

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
// get an anno layer
AnnotationLayer annoLayer = MapView.Active.Map.GetLayersAsFlattenedList().OfType<AnnotationLayer>().FirstOrDefault();
if (annoLayer == null)
return;

QueuedTask.Run(() =>
{
Inspector insp = null;
// get the anno feature class
var fc = annoLayer.GetFeatureClass() as ArcGIS.Core.Data.Mapping.AnnotationFeatureClass;

// get the featureclass CIM definition which contains the labels, symbols
var cimDefinition = fc.GetDefinition() as ArcGIS.Core.Data.Mapping.AnnotationFeatureClassDefinition;
var labels = cimDefinition.GetLabelClassCollection();
var symbols = cimDefinition.GetSymbolCollection();

// make sure there are labels, symbols
if ((labels.Count == 0) || (symbols.Count == 0))
return;

// find the label class required
// typically you would use a subtype name or some other characteristic
// in this case lets just use the first one

var label = labels[0];

// each label has a textSymbol
// the symbolName *should* be the symbolID to be used
var symbolName = label.TextSymbol.SymbolName;
int symbolID = -1;
if (!int.TryParse(symbolName, out symbolID))
{
// int.TryParse fails - attempt to find the symbolName in the symbol collection
foreach (var symbol in symbols)
{
if (symbol.Name == symbolName)
{
symbolID = symbol.ID;
break;
}
}
}
// no symbol?
if (symbolID == -1)
return;

// load the schema
insp = new Inspector();
insp.LoadSchema(annoLayer);

// ok to assign these fields using the inspector[fieldName] methodology
// these fields are guaranteed to exist in the annotation schema
insp["AnnotationClassID"] = label.ID;
insp["SymbolID"] = symbolID;

// set up some additional annotation properties
AnnotationProperties annoProperties = insp.GetAnnotationProperties();
annoProperties.FontSize = 36;
annoProperties.TextString = "My Annotation feature";
annoProperties.VerticalAlignment = VerticalAlignment.Top;
annoProperties.HorizontalAlignment = HorizontalAlignment.Justify;

insp.SetAnnotationProperties(annoProperties);

var tags = new[] { "Annotation", "tag1", "tag2" };

// use daml-id rather than guid
string defaultTool = "esri_editing_SketchStraightAnnoTool";

// tool filter is the tools to filter OUT
var toolFilter = new[] { "esri_editing_SketchCurvedAnnoTool" };

// create a new template
var newTemplate = annoLayer.CreateTemplate("new anno template", "description", insp, defaultTool, tags, toolFilter);
});

删除表模板

1
2
3
4
5
6
7
8
9
10
11
var table = MapView.Active.Map.GetStandaloneTablesAsFlattenedList().FirstOrDefault();
if (table == null)
return;
QueuedTask.Run(() =>
{
var tableTemplate = table.GetTemplate("Template1");
//Removing a table template
table.RemoveTemplate(tableTemplate);
//Removing a template by name
table.RemoveTemplate("Template2");
});

活动模板已更改

1
2
3
4
5
6
7
8
9
10
11
12
ArcGIS.Desktop.Editing.Events.ActiveTemplateChangedEvent.Subscribe(OnActiveTemplateChanged);

async void OnActiveTemplateChanged(ArcGIS.Desktop.Editing.Events.ActiveTemplateChangedEventArgs args)
{
// return if incoming template is null
if (args.IncomingTemplate == null)
return;

// Activate two-point line tool for Freeway template in the Layers map
if (args.IncomingTemplate.Name == "Freeway" && args.IncomingMapView.Map.Name == "Layers")
await args.IncomingTemplate.ActivateToolAsync("esri_editing_SketchTwoPointLineTool");
}

注解

注释构建工具

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
//In your config.daml...set the categoryRefID
//<tool id="..." categoryRefID="esri_editing_construction_annotation" caption="Create Anno" ...>

//Sketch type Point or Line or BezierLine in the constructor...
//internal class AnnoConstructionTool : MapTool {
// public AnnoConstructionTool() {
// IsSketchTool = true;
// UseSnapping = true;
// SketchType = SketchGeometryType.Point;
//

protected async override Task<bool> OnSketchCompleteAsync(Geometry geometry)
{
if (CurrentTemplate == null || geometry == null)
return false;

// Create an edit operation
var createOperation = new EditOperation();
createOperation.Name = string.Format("Create {0}", CurrentTemplate.Layer.Name);
createOperation.SelectNewFeatures = true;

var insp = CurrentTemplate.Inspector;
var result = await QueuedTask.Run(() =>
{
// get the annotation properties class
AnnotationProperties annoProperties = insp.GetAnnotationProperties();
// set custom annotation properties
annoProperties.TextString = "my custom text";
annoProperties.Color = ColorFactory.Instance.RedRGB;
annoProperties.FontSize = 24;
annoProperties.FontName = "Arial";
annoProperties.HorizontalAlignment = ArcGIS.Core.CIM.HorizontalAlignment.Right;
annoProperties.Shape = geometry;
// assign annotation properties back to the inspector
insp.SetAnnotationProperties(annoProperties);

// Queue feature creation
createOperation.Create(CurrentTemplate.Layer, insp);

// Execute the operation
return createOperation.Execute();
});
return result;
}

以编程方式启动编辑批注

1
2
3
var plugin = FrameworkApplication.GetPlugInWrapper("esri_editing_EditVerticesText");
if (plugin.Enabled)
((ICommand)plugin).Execute(null);

更新批注文本

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
await QueuedTask.Run(() =>
{
//annoLayer is ~your~ Annotation layer...

// use the inspector methodology
//at 2.x - var insp = new Inspector(true);
var insp = new Inspector();
insp.Load(annoLayer, oid);

// get the annotation properties
AnnotationProperties annoProperties = insp.GetAnnotationProperties();
// set the attribute
annoProperties.TextString = "Hello World";
// assign the annotation proeprties back to the inspector
insp.SetAnnotationProperties(annoProperties);

//create and execute the edit operation
EditOperation op = new EditOperation();
op.Name = "Update annotation";
op.Modify(insp);
op.Execute();
});

修改批注形状

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
await QueuedTask.Run(() =>
{
//Don't use 'Shape'....Shape is the bounding box of the annotation text. This is NOT what you want...
//
//var insp = new Inspector();
//insp.Load(annoLayer, oid);
//var shape = insp["SHAPE"] as Polygon;
//...wrong shape...

//Instead, we must use the AnnotationProperties

//annoLayer is ~your~ Annotation layer
//at 2.x - var insp = new Inspector(true);
var insp = new Inspector();
insp.Load(annoLayer, oid);

AnnotationProperties annoProperties = insp.GetAnnotationProperties();
var shape = annoProperties.Shape;
if (shape.GeometryType != GeometryType.GeometryBag)
{
var newGeometry = GeometryEngine.Instance.Move(shape, 10, 10);
annoProperties.Shape = newGeometry;
insp.SetAnnotationProperties(annoProperties);

EditOperation op = new EditOperation();
op.Name = "Change annotation angle";
op.Modify(insp);
op.Execute();
}
});

修改批注文本图形

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
await QueuedTask.Run(() =>
{

var selection = annoLayer.GetSelection();
if (selection.GetCount() == 0)
return;

// use the first selelcted feature
//at 2.x - var insp = new Inspector(true);
var insp = new Inspector();
insp.Load(annoLayer, selection.GetObjectIDs().FirstOrDefault());

// getAnnoProperties should return null if not an annotation feature
AnnotationProperties annoProperties = insp.GetAnnotationProperties();
// get the textGraphic
CIMTextGraphic textGraphic = annoProperties.TextGraphic;

// change text
textGraphic.Text = "Hello world";

// set x,y offset via the symbol
var symbol = textGraphic.Symbol.Symbol;
var textSymbol = symbol as CIMTextSymbol;
textSymbol.OffsetX = 2;
textSymbol.OffsetY = 3;

textSymbol.HorizontalAlignment = HorizontalAlignment.Center;

// load the updated textGraphic
annoProperties.LoadFromTextGraphic(textGraphic);
// assign the annotation properties back
insp.SetAnnotationProperties(annoProperties);

EditOperation op = new EditOperation();
op.Name = "modify symbol";
op.Modify(insp);
bool result = op.Execute();
});

ProSnippet 组 : 接地到网格

G2G 设置

1
2
3
4
5
6
7
8
CIMGroundToGridCorrection correction = null;
bool isCorecting = correction.IsCorrecting(); // equivalent to correction != null && correction.Enabled;
bool UsingOffset = correction.UsingDirectionOffset(); // equivalent to correction.IsCorrecting() && correction.UseDirection;
double dOffset = correction.GetDirectionOffset(); // equivalent to correction.UsingDirectionOffset() ? correction.Direction : DefaultDirectionOffset;
bool usingDistanceFactor = correction.UsingDistanceFactor(); // equivalent to correction.IsCorrecting() && correction.UseScale;
bool usingElevation = correction.UsingElevationMode(); // equivalent to correction.UsingDistanceFactor() && c.ScaleType == GroundToGridScaleType.ComputeUsingElevation;
bool usingSFactor = correction.UsingConstantScaleFactor(); //; equivalent to correction.UsingDistanceFactor() && correction.ScaleType == GroundToGridScaleType.ConstantFactor;
double dSFactor = correction.GetConstantScaleFactor(); // equivalent to correctionc.UsingDistanceFactor() ? correction.ConstantScaleFactor : DefaultConstantScaleFactor;

编辑选项

获取/设置编辑选项

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
//toggle, switch option values
var options = ApplicationOptions.EditingOptions;

options.EnforceAttributeValidation = !options.EnforceAttributeValidation;
options.WarnOnSubtypeChange = !options.WarnOnSubtypeChange;
options.InitializeDefaultValuesOnSubtypeChange = !options.InitializeDefaultValuesOnSubtypeChange;
options.UncommitedAttributeEdits = (options.UncommitedAttributeEdits ==
UncommitedEditMode.AlwaysPrompt) ? UncommitedEditMode.Apply : UncommitedEditMode.AlwaysPrompt;

options.StretchGeometry = !options.StretchGeometry;
options.StretchTopology = !options.StretchTopology;
options.UncommitedGeometryEdits = (options.UncommitedGeometryEdits ==
UncommitedEditMode.AlwaysPrompt) ? UncommitedEditMode.Apply : UncommitedEditMode.AlwaysPrompt;

options.ActivateMoveAfterPaste = !options.ActivateMoveAfterPaste;
options.ShowFeatureSketchSymbology = !options.ShowFeatureSketchSymbology;
options.FinishSketchOnDoubleClick = !options.FinishSketchOnDoubleClick;
options.AllowVertexEditingWhileSketching = !options.AllowVertexEditingWhileSketching;
options.ShowDeleteDialog = !options.ShowDeleteDialog;
options.EnableStereoEscape = !options.EnableStereoEscape;
options.DragSketch = !options.DragSketch;
options.ShowDynamicConstraints = !options.ShowDynamicConstraints;
options.IsDeflectionDefaultDirectionConstraint =
!options.IsDeflectionDefaultDirectionConstraint;
options.IsDirectionDefaultInputConstraint = !options.IsDirectionDefaultInputConstraint;
options.ShowEditingToolbar = !options.ShowEditingToolbar;
options.ToolbarPosition = (options.ToolbarPosition == ToolbarPosition.Bottom) ?
ToolbarPosition.Right : ToolbarPosition.Bottom;
options.ToolbarSize = (options.ToolbarSize == ToolbarSize.Medium) ?
ToolbarSize.Small : ToolbarSize.Medium;
options.MagnifyToolbar = !options.MagnifyToolbar;

options.EnableEditingFromEditTab = !options.EnableEditingFromEditTab;
options.AutomaticallySaveEdits = !options.AutomaticallySaveEdits;
options.AutoSaveByTime = !options.AutoSaveByTime;
options.SaveEditsInterval = (options.AutomaticallySaveEdits) ? 20 : 10;
options.SaveEditsOperations = (options.AutomaticallySaveEdits) ? 60 : 30;
options.SaveEditsOnProjectSave = !options.SaveEditsOnProjectSave;
options.ShowSaveEditsDialog = !options.ShowSaveEditsDialog;
options.ShowDiscardEditsDialog = !options.ShowDiscardEditsDialog;
options.DeactivateToolOnSaveOrDiscard = !options.DeactivateToolOnSaveOrDiscard;
options.NewLayersEditable = !options.NewLayersEditable;

获取草图折点符号系统选项

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
var options = ApplicationOptions.EditingOptions;

//Must use QueuedTask
QueuedTask.Run(() =>
{
//There are 4 vertex symbol settings - selected, unselected and the
//current vertex selected and unselected.
var reg_select = options.GetVertexSymbolOptions(VertexSymbolType.RegularSelected);
var reg_unsel = options.GetVertexSymbolOptions(VertexSymbolType.RegularUnselected);
var curr_sel = options.GetVertexSymbolOptions(VertexSymbolType.CurrentSelected);
var curr_unsel = options.GetVertexSymbolOptions(VertexSymbolType.CurrentUnselected);

//to convert the options to a symbol use
//GetPointSymbol
var reg_sel_pt_symbol = reg_select.GetPointSymbol();
//ditto for reg_unsel, curr_sel, curr_unsel
});

获取草图线段符号系统选项

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
//var options = ApplicationOptions.EditingOptions;
QueuedTask.Run(() =>
{
var seg_options = options.GetSegmentSymbolOptions();
//to convert the options to a symbol use
//SymbolFactory. Note: this is approximate....sketch isn't using the
//CIM directly for segments
var layers = new List<CIMSymbolLayer>();
var stroke0 = SymbolFactory.Instance.ConstructStroke(seg_options.PrimaryColor,
seg_options.Width, SimpleLineStyle.Dash);
layers.Add(stroke0);
if (seg_options.HasSecondaryColor) {
var stroke1 = SymbolFactory.Instance.ConstructStroke(
seg_options.SecondaryColor, seg_options.Width, SimpleLineStyle.Solid);
layers.Add(stroke1);
}
//segment symbology only
var sketch_line = new CIMLineSymbol() {
SymbolLayers = layers.ToArray()
};
});

设置草图顶点符号选项

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
//var options = ApplicationOptions.EditingOptions;
QueuedTask.Run(() =>
{
//change the regular unselected vertex symbol
//default is a green, hollow, square, 5pts. Change to
//Blue outline diamond, 10 pts
var vertexSymbol = new VertexSymbolOptions(VertexSymbolType.RegularUnselected);
vertexSymbol.OutlineColor = ColorFactory.Instance.BlueRGB;
vertexSymbol.MarkerType = VertexMarkerType.Diamond;
vertexSymbol.Size = 10;

//Are these valid?
if (options.CanSetVertexSymbolOptions(
VertexSymbolType.RegularUnselected, vertexSymbol)) {
//apply them
options.SetVertexSymbolOptions(VertexSymbolType.RegularUnselected, vertexSymbol);
}
});

设置草图线段符号选项

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
//var options = ApplicationOptions.EditingOptions;
QueuedTask.Run(() =>
{
//change the segment symbol primary color to green and
//width to 1 pt
var segSymbol = options.GetSegmentSymbolOptions();
segSymbol.PrimaryColor = ColorFactory.Instance.GreenRGB;
segSymbol.Width = 1;

//Are these valid?
if (options.CanSetSegmentSymbolOptions(segSymbol)) {
//apply them
options.SetSegmentSymbolOptions(segSymbol);
}
});

将草图顶点符号设置回默认值

1
2
3
4
5
6
7
8
9
10
//var options = ApplicationOptions.EditingOptions;
QueuedTask.Run(() =>
{
//ditto for reg selected and current selected, unselected
var def_reg_unsel =
options.GetDefaultVertexSymbolOptions(VertexSymbolType.RegularUnselected);
//apply default
options.SetVertexSymbolOptions(
VertexSymbolType.RegularUnselected, def_reg_unsel);
});

将草图线段符号设置回默认值

1
2
3
4
5
6
//var options = ApplicationOptions.EditingOptions;
QueuedTask.Run(() =>
{
var def_seg = options.GetDefaultSegmentSymbolOptions();
options.SetSegmentSymbolOptions(def_seg);
});

版本控制选项

获取和设置版本控制选项

1
2
3
4
5
6
7
8
9
var vOptions = ApplicationOptions.VersioningOptions;

vOptions.DefineConflicts = (vOptions.DefineConflicts == ConflictDetectionType.ByRow) ?
ConflictDetectionType.ByColumn : ConflictDetectionType.ByRow;
vOptions.ConflictResolution = (
vOptions.ConflictResolution == ConflictResolutionType.FavorEditVersion) ?
ConflictResolutionType.FavorTargetVersion : ConflictResolutionType.FavorEditVersion;
vOptions.ShowConflictsDialog = !vOptions.ShowConflictsDialog;
vOptions.ShowReconcileDialog = !vOptions.ShowReconcileDialog;

创建注记构造工具

通过属性更新批注文本。警告:TEXTSTRING Anno 属性必须存在

旋转或移动批注

更改批注文本图形

公共设施网络

创建公共设施网络关联

在单个编辑操作中创建公共设施网络要素和关联

地理数据库

地理数据库和数据存储

打开给定路径的文件地理数据库

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
public async Task OpenFileGDB()
{
try
{
await ArcGIS.Desktop.Framework.Threading.Tasks.QueuedTask.Run(() =>
{
// Opens a file geodatabase. This will open the geodatabase if the folder exists and contains a valid geodatabase.
using (
Geodatabase geodatabase =
new Geodatabase(new FileGeodatabaseConnectionPath(new Uri(@"C:\Data\LocalGovernment.gdb"))))
{
// Use the geodatabase.
}
});
}
catch (GeodatabaseNotFoundOrOpenedException exception)
{
// Handle Exception.
}

}

使用连接属性打开企业级地理数据库

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
public async Task OpenEnterpriseGeodatabase()
{
await ArcGIS.Desktop.Framework.Threading.Tasks.QueuedTask.Run(() =>
{
// Opening a Non-Versioned SQL Server instance.
DatabaseConnectionProperties connectionProperties = new DatabaseConnectionProperties(EnterpriseDatabaseType.SQLServer)
{
AuthenticationMode = AuthenticationMode.DBMS,

// Where testMachine is the machine where the instance is running and testInstance is the name of the SqlServer instance.
Instance = @"testMachine\testInstance",

// Provided that a database called LocalGovernment has been created on the testInstance and geodatabase has been enabled on the database.
Database = "LocalGovernment",

// Provided that a login called gdb has been created and corresponding schema has been created with the required permissions.
User = "gdb",
Password = "password",
Version = "dbo.DEFAULT"
};

using (Geodatabase geodatabase = new Geodatabase(connectionProperties))
{
// Use the geodatabase
}
});
}

使用 sde 文件路径打开企业级地理数据库

1
2
3
4
5
6
7
8
9
10
public async Task OpenEnterpriseGeodatabaseUsingSDEFilePath()
{
await ArcGIS.Desktop.Framework.Threading.Tasks.QueuedTask.Run(() =>
{
using (Geodatabase geodatabase = new Geodatabase(new DatabaseConnectionFile(new Uri("path\\to\\sde\\file\\sdefile.sde"))))
{
// Use the geodatabase.
}
});
}

从工程项获取地理数据库

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
public async Task ObtainingGeodatabaseFromProjectItem()
{
IEnumerable<GDBProjectItem> gdbProjectItems = Project.Current.GetItems<GDBProjectItem>();

await ArcGIS.Desktop.Framework.Threading.Tasks.QueuedTask.Run(() =>
{
foreach (GDBProjectItem gdbProjectItem in gdbProjectItems)
{
using (Datastore datastore = gdbProjectItem.GetDatastore())
{
//Unsupported datastores (non File GDB and non Enterprise GDB) will be of type UnknownDatastore
if (datastore is UnknownDatastore)
continue;

Geodatabase geodatabase = datastore as Geodatabase;
// Use the geodatabase.
}
}
});
}

从连接文件获取数据库连接属性

1
2
3
4
DatabaseConnectionFile connectionFile = new DatabaseConnectionFile(new Uri("path\\to\\sde\\file\\sdefile.sde"));
DatabaseConnectionProperties connectionProperties = DatabaseClient.GetDatabaseConnectionProperties(connectionFile);

// Now you could, for example, change the user name and password in the connection properties prior to use them to open a geodatabase

从要素图层获取地理数据库

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
public async Task ObtainingGeodatabaseFromFeatureLayer()
{
IEnumerable<Layer> layers = MapView.Active.Map.Layers.Where(layer => layer is FeatureLayer);

await ArcGIS.Desktop.Framework.Threading.Tasks.QueuedTask.Run(() =>
{
foreach (FeatureLayer featureLayer in layers)
{
using (Table table = featureLayer.GetTable())
using (Datastore datastore = table.GetDatastore())
{
if (datastore is UnknownDatastore)
continue;

Geodatabase geodatabase = datastore as Geodatabase;
}
}
});
}

执行 SQL 语句

1
2
3
4
5
6
7
8
9
// Executes raw SQL on the underlying database management system.
// Any SQL is permitted (DDL or DML), but no results can be returned
public void ExecuteSQLOnGeodatabase(Geodatabase geodatabase, string statement)
{
QueuedTask.Run(() =>
{
DatabaseClient.ExecuteStatement(geodatabase, statement);
});
}

定义

从地理数据库获取定义

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
public async Task ObtainingDefinitionFromGeodatabase()
{
await ArcGIS.Desktop.Framework.Threading.Tasks.QueuedTask.Run(() =>
{
using (Geodatabase geodatabase = new Geodatabase(new DatabaseConnectionFile(new Uri("path\\to\\sde\\file\\sdefile.sde"))))
{
// Remember that for Enterprise databases you have to qualify your dataset names with the DatabaseName and UserName.
TableDefinition enterpriseTableDefinition = geodatabase.GetDefinition<TableDefinition>("LocalGovernment.GDB.CitizenContactInfo");

// It does not matter if the dataset is within a FeatureDataset or not.
FeatureClassDefinition featureClassDefinition = geodatabase.GetDefinition<FeatureClassDefinition>("LocalGovernment.GDB.FireStation");

// GetDefinition For a RelationshipClass.
RelationshipClassDefinition relationshipClassDefinition = geodatabase.GetDefinition<RelationshipClassDefinition>("LocalGovernment.GDB.AddressPointHasSiteAddresses");

// GetDefinition For a FeatureDataset.
FeatureDatasetDefinition featureDatasetDefinition = geodatabase.GetDefinition<FeatureDatasetDefinition>("LocalGovernment.GDB.Address");
}
});
}

从地理数据库获取定义列表

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
public async Task ObtainingDefinitionsFromGeodatabase()
{
await ArcGIS.Desktop.Framework.Threading.Tasks.QueuedTask.Run(() =>
{
using (Geodatabase geodatabase = new Geodatabase(
new DatabaseConnectionFile(new Uri("path\\to\\sde\\file\\sdefile.sde"))))
{
var enterpriseDefinitions =
geodatabase.GetDefinitions<FeatureClassDefinition>();
IEnumerable<Definition> featureClassesHavingGlobalID =
enterpriseDefinitions.Where(definition => definition.HasGlobalID());

var featureDatasetDefinitions =
geodatabase.GetDefinitions<FeatureDatasetDefinition>();
bool electionRelatedFeatureDatasets =
featureDatasetDefinitions.Any(
definition => definition.GetName().Contains("Election"));

var attributedRelationshipClassDefinitions =
geodatabase.GetDefinitions<AttributedRelationshipClassDefinition>();

var relationshipClassDefinitions =
geodatabase.GetDefinitions<RelationshipClassDefinition>();
}
});
}

从地理数据库获取相关定义

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
public async Task ObtainingRelatedDefinitionsFromGeodatabase()
{
await ArcGIS.Desktop.Framework.Threading.Tasks.QueuedTask.Run(() =>
{
using (Geodatabase geodatabase = new Geodatabase(new DatabaseConnectionFile(new Uri("path\\to\\sde\\file\\sdefile.sde"))))
{
// Remember the qualification of DatabaseName. for the RelationshipClass.

RelationshipClassDefinition enterpriseDefinition =
geodatabase.GetDefinition<RelationshipClassDefinition>("LocalGovernment.GDB.AddressPointHasSiteAddresses");
IReadOnlyList<Definition> enterpriseDefinitions =
geodatabase.GetRelatedDefinitions(enterpriseDefinition, DefinitionRelationshipType.DatasetsRelatedThrough);
FeatureClassDefinition enterpriseAddressPointDefinition =
enterpriseDefinitions.First(
defn => defn.GetName().Equals("LocalGovernment.GDB.AddressPoint")) as FeatureClassDefinition;

FeatureDatasetDefinition featureDatasetDefinition =
geodatabase.GetDefinition<FeatureDatasetDefinition>("LocalGovernment.GDB.Address");
IReadOnlyList<Definition> datasetsInAddressDataset =
geodatabase.GetRelatedDefinitions(featureDatasetDefinition, DefinitionRelationshipType.DatasetInFeatureDataset);
FeatureClassDefinition addressPointInAddressDataset =
datasetsInAddressDataset.First(
defn => defn.GetName().Equals("LocalGovernment.GDB.AddressPoint")) as FeatureClassDefinition;

RelationshipClassDefinition addressPointHasSiteAddressInAddressDataset = datasetsInAddressDataset.First(
defn => defn.GetName().Equals("LocalGovernment.GDB.AddressPointHasSiteAddresses")) as RelationshipClassDefinition;
}
});
}

从层获取表定义

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
// GetDefinitionFromLayer - This code works even if the layer has a join to another table
private TableDefinition GetDefinitionFromLayer(FeatureLayer featureLayer)
{
// Get feature class from the layer
FeatureClass featureClass = featureLayer.GetFeatureClass();

// Determine if feature class is a join
if (featureClass.IsJoinedTable())
{
// Get join from feature class
Join join = featureClass.GetJoin();

// Get origin table from join
Table originTable = join.GetOriginTable();

// Return feature class definition from the join's origin table
return originTable.GetDefinition();
}
else
{
return featureClass.GetDefinition();
}
}

数据

从地理数据库打开数据集

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
public async Task OpeningDatasetsFromGeodatabase()
{
await ArcGIS.Desktop.Framework.Threading.Tasks.QueuedTask.Run(() =>
{
using (Geodatabase geodatabase = new Geodatabase(new DatabaseConnectionFile(new Uri("path\\to\\sde\\file\\sdefile.sde"))))
{
using (Table table =
geodatabase.OpenDataset<Table>("LocalGovernment.GDB.EmployeeInfo"))
{
}

// Open a featureClass (within a feature dataset or outside a feature dataset).
using (FeatureClass featureClass =
geodatabase.OpenDataset<FeatureClass>("LocalGovernment.GDB.AddressPoint"))
{
}

// You can open a FeatureClass as a Table which will give you a Table Reference.
using (Table featureClassAsTable = geodatabase.OpenDataset<Table>("LocalGovernment.GDB.AddressPoint"))
{
// But it is really a FeatureClass object.
FeatureClass featureClassOpenedAsTable = featureClassAsTable as FeatureClass;
}

// Open a FeatureDataset.
using (FeatureDataset featureDataset = geodatabase.OpenDataset<FeatureDataset>("LocalGovernment.GDB.Address"))
{
}

// Open a RelationsipClass. Just as you can open a FeatureClass as a Table, you can also open an AttributedRelationshipClass as a RelationshipClass.
using (RelationshipClass relationshipClass = geodatabase.OpenDataset<RelationshipClass>("LocalGovernment.GDB.AddressPointHasSiteAddresses"))
{
}
}
});
}

检查表是否存在

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// Must be called within QueuedTask.Run9)
public bool TableExists(Geodatabase geodatabase, string tableName)
{
try
{
TableDefinition tableDefinition = geodatabase.GetDefinition<TableDefinition>(tableName);
tableDefinition.Dispose();
return true;
}
catch
{
// GetDefinition throws an exception if the definition doesn't exist
return false;
}
}

检查要素类是否存在

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// Must be called within QueuedTask.Run()
public bool FeatureClassExists(Geodatabase geodatabase, string featureClassName)
{
try
{
FeatureClassDefinition featureClassDefinition = geodatabase.GetDefinition<FeatureClassDefinition>(featureClassName);
featureClassDefinition.Dispose();
return true;
}
catch
{
// GetDefinition throws an exception if the definition doesn't exist
return false;
}
}

打开关系两个表之间的类

1
2
3
4
5
6
7
// Must be called within QueuedTask.Run().  
// When used with file or enterprise geodatabases, this routine takes two table names.
// When used with feature services, this routine takes layer IDs, or the names of the tables as they are exposed through the service (e.g., "L0States")
public IReadOnlyList<RelationshipClass> OpenRelationshipClassFeatureServices(Geodatabase geodatabase, string originClass, string destinationClass)
{
return geodatabase.OpenRelationshipClasses(originClass, destinationClass);
}

从关系类获取相关要素类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
public async Task GetFeatureClassesInRelationshipClassAsync()
{
await ArcGIS.Desktop.Framework.Threading.Tasks.QueuedTask.Run(() =>
{
using (Geodatabase geodatabase = new Geodatabase(new FileGeodatabaseConnectionPath(new Uri(@"C:\Data\LocalGovernment.gdb"))))
{
IReadOnlyList<RelationshipClassDefinition> relationshipClassDefinitions =
geodatabase.GetDefinitions<RelationshipClassDefinition>();

foreach (var relationshipClassDefinition in relationshipClassDefinitions)
{
IReadOnlyList<Definition> definitions =
geodatabase.GetRelatedDefinitions(relationshipClassDefinition,
DefinitionRelationshipType.DatasetsRelatedThrough);

foreach (var definition in definitions)
{
System.Diagnostics.Debug.WriteLine(
$"Feature class in the RelationshipClass is:{definition.GetName()}");
}
}
}
});
}

从 shapefile 数据存储打开要素类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
public async Task OpenShapefileFeatureClass()
{
await ArcGIS.Desktop.Framework.Threading.Tasks.QueuedTask.Run(() =>
{
var fileConnection = new FileSystemConnectionPath(new Uri("path\\to\\folder\\containing\\shapefiles"), FileSystemDatastoreType.Shapefile);
using (FileSystemDatastore shapefile = new FileSystemDatastore(fileConnection))
{
FeatureClass taxLotsFeatureClass = shapefile.OpenDataset<FeatureClass>("TaxLots");
FeatureClass manHolesFeatureClass = shapefile.OpenDataset<FeatureClass>("ManHoles.shp"); // Can use the .shp extension, but its not needed.
Table taxDetailsTableWithoutExtension = shapefile.OpenDataset<Table>("TaxDetails");
Table taxDetailsTable = shapefile.OpenDataset<Table>("TaxDetails.dbf");
}
});
}

打开 CAD 数据存储

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
public async Task OpenCADFeatureClass()
{
await ArcGIS.Desktop.Framework.Threading.Tasks.QueuedTask.Run(() =>
{
var fileConnection = new FileSystemConnectionPath(new Uri("path\\to\\folder\\containing\\CAD"), FileSystemDatastoreType.Cad);
using (FileSystemDatastore cadDatastore = new FileSystemDatastore(fileConnection))
{
// note - extension is required
var cadDataset = cadDatastore.OpenDataset<FeatureClass>("hatchplayboundaries.dwg");
// take note of the pattern for referencing a feature class.
var cadfeatureClass = cadDatastore.OpenDataset<FeatureClass>("hatchplayboundaries.dwg:Polyline");

int numRows = 0;
using (var cursor = cadfeatureClass.Search())
{
while (cursor.MoveNext())
numRows++;
}
}
});
}

查询

使用查询筛选器搜索表

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
public async Task SearchingATable()
{
try
{
await ArcGIS.Desktop.Framework.Threading.Tasks.QueuedTask.Run(() =>
{
using (Geodatabase geodatabase = new Geodatabase(new DatabaseConnectionFile(new Uri("path\\to\\sde\\file\\sdefile.sde"))))
using (Table table = geodatabase.OpenDataset<Table>("EmployeeInfo"))
{

QueryFilter queryFilter = new QueryFilter
{
WhereClause = "COSTCTRN = 'Information Technology'",
SubFields = "KNOWNAS, OFFICE, LOCATION",
PostfixClause = "ORDER BY OFFICE"
};

using (RowCursor rowCursor = table.Search(queryFilter, false))
{
while (rowCursor.MoveNext())
{
using (Row row = rowCursor.Current)
{
string location = Convert.ToString(row["LOCATION"]);
string knownAs = Convert.ToString(row["KNOWNAS"]);
}
}
}
}
});
}
catch (GeodatabaseFieldException fieldException)
{
// One of the fields in the where clause might not exist. There are multiple ways this can be handled:
// Handle error appropriately
}
catch (Exception exception)
{
// logger.Error(exception.Message);
}
}

在表中搜索非拉丁字符

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
using (Geodatabase geodatabase = new Geodatabase(new DatabaseConnectionFile(new Uri("path\\to\\sde\\file\\sdefile.sde"))))
using (Table table = geodatabase.OpenDataset<Table>("TableWithChineseCharacters"))
{
// This will fail with many database systems that expect Latin characters by default
string incorrectWhereClause = "颜色 = '绿'";

// Correct solution is to prepend the 'National String Prefix' to the attribute value
// For example, with SQL Server this value is 'N'
// This value is obtained using the SQLSyntax class
string nationalStringPrefix = "";
SQLSyntax sqlSyntax = geodatabase.GetSQLSyntax();
nationalStringPrefix = sqlSyntax.GetSupportedStrings(SQLStringType.NationalStringPrefix).First();

// This Where clause will work
QueryFilter queryFilter = new QueryFilter()
{
WhereClause = "颜色 = " + nationalStringPrefix + "'绿'"
};
}

使用一组对象 ID 搜索表

1
2
3
4
5
6
7
8
9
public RowCursor SearchingATable(Table table, IReadOnlyList<long> objectIDs)
{
QueryFilter queryFilter = new QueryFilter()
{
ObjectIDs = objectIDs
};

return table.Search(queryFilter);
}

使用空间查询过滤器搜索要素类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
public async Task SearchingAFeatureClass()
{
await ArcGIS.Desktop.Framework.Threading.Tasks.QueuedTask.Run(() =>
{
using (Geodatabase geodatabase = new Geodatabase(new DatabaseConnectionFile(new Uri("path\\to\\sde\\file\\sdefile.sde"))))
using (FeatureClass schoolBoundaryFeatureClass = geodatabase.OpenDataset<FeatureClass>("LocalGovernment.GDB.SchoolBoundary"))
{
// Using a spatial query filter to find all features which have a certain district name and lying within a given Polygon.
SpatialQueryFilter spatialQueryFilter = new SpatialQueryFilter
{
WhereClause = "DISTRCTNAME = 'Indian Prairie School District 204'",
FilterGeometry = new PolygonBuilderEx(new List<Coordinate2D>
{
new Coordinate2D(1021880, 1867396),
new Coordinate2D(1028223, 1870705),
new Coordinate2D(1031165, 1866844),
new Coordinate2D(1025373, 1860501),
new Coordinate2D(1021788, 1863810)
}).ToGeometry(),

SpatialRelationship = SpatialRelationship.Within
};

using (RowCursor indianPrairieCursor = schoolBoundaryFeatureClass.Search(spatialQueryFilter, false))
{
while (indianPrairieCursor.MoveNext())
{
using (Feature feature = (Feature)indianPrairieCursor.Current)
{
// Process the feature. For example...
Console.WriteLine(feature.GetObjectID());
}
}
}
}
});
}

从表中选择行

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
public async Task SelectingRowsFromATable()
{
await ArcGIS.Desktop.Framework.Threading.Tasks.QueuedTask.Run(() =>
{
using (Geodatabase geodatabase = new Geodatabase(new DatabaseConnectionFile(new Uri("path\\to\\sde\\file\\sdefile.sde"))))
using (Table enterpriseTable = geodatabase.OpenDataset<Table>("LocalGovernment.GDB.piCIPCost"))
{
QueryFilter anotherQueryFilter = new QueryFilter { WhereClause = "FLOOR = 1 AND WING = 'E'" };

// For Selecting all matching entries.
using (Selection anotherSelection = enterpriseTable.Select(anotherQueryFilter, SelectionType.ObjectID, SelectionOption.Normal))
{
}

// This can be used to get one record which matches the criteria. No assumptions can be made about which record satisfying the criteria is selected.
using (Selection onlyOneSelection = enterpriseTable.Select(anotherQueryFilter, SelectionType.ObjectID, SelectionOption.OnlyOne))
{
}

// This can be used to obtain a empty selction which can be used as a container to combine results from different selections.
using (Selection emptySelection = enterpriseTable.Select(anotherQueryFilter, SelectionType.ObjectID, SelectionOption.Empty))
{
}

// If you want to select all the records in a table.
using (Selection allRecordSelection = enterpriseTable.Select(null, SelectionType.ObjectID, SelectionOption.Normal))
{
}
}
});
}

从要素类中选择要素

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
public async Task SelectingFeaturesFromAFeatureClass()
{
await ArcGIS.Desktop.Framework.Threading.Tasks.QueuedTask.Run(() =>
{
using (Geodatabase geodatabase = new Geodatabase(new DatabaseConnectionFile(new Uri("path\\to\\sde\\file\\sdefile.sde"))))
using (FeatureClass enterpriseFeatureClass = geodatabase.OpenDataset<FeatureClass>("LocalGovernment.GDB.FacilitySite"))
{
List<Coordinate2D> newCoordinates = new List<Coordinate2D>
{
new Coordinate2D(1021570, 1880583),
new Coordinate2D(1028730, 1880994),
new Coordinate2D(1029718, 1875644),
new Coordinate2D(1021405, 1875397)
};

SpatialQueryFilter spatialFilter = new SpatialQueryFilter
{
WhereClause = "FCODE = 'Park'",
FilterGeometry = new PolygonBuilderEx(newCoordinates).ToGeometry(),
SpatialRelationship = SpatialRelationship.Crosses
};

// For Selecting all matching entries.
using (Selection anotherSelection = enterpriseFeatureClass.Select(spatialFilter, SelectionType.ObjectID, SelectionOption.Normal))
{
}

// This can be used to get one record which matches the criteria. No assumptions can be made about which record satisfying the
// criteria is selected.
using (Selection onlyOneSelection = enterpriseFeatureClass.Select(spatialFilter, SelectionType.ObjectID, SelectionOption.OnlyOne))
{
}

// This can be used to obtain a empty selction which can be used as a container to combine results from different selections.
using (Selection emptySelection = enterpriseFeatureClass.Select(spatialFilter, SelectionType.ObjectID, SelectionOption.Empty))
{
}

// If you want to select all the records in a table.
using (Selection allRecordSelection = enterpriseFeatureClass.Select(null, SelectionType.ObjectID, SelectionOption.Normal))
{
}
}
});
}

获取表中当前有多少行的计数

1
2
3
//Note: call within QueuedTask.Run()
var table = featureLayer.GetTable();
var count = table.GetCount();

获取图层的特征计数

1
2
3
4
5
6
var lyr = MapView.Active.Map.GetLayersAsFlattenedList().OfType<FeatureLayer>().FirstOrDefault();
QueuedTask.Run(() =>
{
FeatureClass featureClass = lyr.GetFeatureClass();
long nCount = featureClass.GetCount();
});

对表进行排序

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
public RowCursor SortWorldCities(FeatureClass worldCitiesTable)
{
using (FeatureClassDefinition featureClassDefinition = worldCitiesTable.GetDefinition())
{
Field countryField = featureClassDefinition.GetFields()
.First(x => x.Name.Equals("COUNTRY_NAME"));
Field cityNameField = featureClassDefinition.GetFields()
.First(x => x.Name.Equals("CITY_NAME"));

// Create SortDescription for Country field
SortDescription countrySortDescription = new SortDescription(countryField);
countrySortDescription.CaseSensitivity = CaseSensitivity.Insensitive;
countrySortDescription.SortOrder = SortOrder.Ascending;

// Create SortDescription for City field
SortDescription citySortDescription = new SortDescription(cityNameField);
citySortDescription.CaseSensitivity = CaseSensitivity.Insensitive;
citySortDescription.SortOrder = SortOrder.Ascending;

// Create our TableSortDescription
TableSortDescription tableSortDescription = new TableSortDescription(
new List<SortDescription>() { countrySortDescription, citySortDescription });

return worldCitiesTable.Sort(tableSortDescription);
}
}

计算表的统计信息

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
// Calculate the Sum and Average of the Population_1990 and Population_2000 fields, grouped and ordered by Region
public void CalculateStatistics(FeatureClass countryFeatureClass)
{
using (FeatureClassDefinition featureClassDefinition =
countryFeatureClass.GetDefinition())
{
// Get fields
Field regionField = featureClassDefinition.GetFields()
.First(x => x.Name.Equals("Region"));
Field pop1990Field = featureClassDefinition.GetFields()
.First(x => x.Name.Equals("Population_1990"));
Field pop2000Field = featureClassDefinition.GetFields()
.First(x => x.Name.Equals("Population_2000"));

// Create StatisticsDescriptions
StatisticsDescription pop1990StatisticsDescription =
new StatisticsDescription(pop1990Field,
new List<StatisticsFunction>() { StatisticsFunction.Sum,
StatisticsFunction.Average });
StatisticsDescription pop2000StatisticsDescription =
new StatisticsDescription(pop2000Field,
new List<StatisticsFunction>() { StatisticsFunction.Sum,
StatisticsFunction.Average });

// Create TableStatisticsDescription
TableStatisticsDescription tableStatisticsDescription =
new TableStatisticsDescription(new List<StatisticsDescription>() {
pop1990StatisticsDescription, pop2000StatisticsDescription });
tableStatisticsDescription.GroupBy = new List<Field>() { regionField };
tableStatisticsDescription.OrderBy =
new List<SortDescription>() { new SortDescription(regionField) };

// Calculate Statistics
IReadOnlyList<TableStatisticsResult> tableStatisticsResults =
countryFeatureClass.CalculateStatistics(tableStatisticsDescription);

foreach (TableStatisticsResult tableStatisticsResult in tableStatisticsResults)
{
// Get the Region name
// If multiple fields had been passed into TableStatisticsDescription.GroupBy, there would be multiple values in TableStatisticsResult.GroupBy
string regionName = tableStatisticsResult.GroupBy.First().Value.ToString();

// Get the statistics results for the Population_1990 field
StatisticsResult pop1990Statistics = tableStatisticsResult.StatisticsResults[0];
double population1990Sum = pop1990Statistics.Sum;
double population1990Average = pop1990Statistics.Average;

// Get the statistics results for the Population_2000 field
StatisticsResult pop2000Statistics = tableStatisticsResult.StatisticsResults[1];
double population2000Sum = pop2000Statistics.Sum;
double population2000Average = pop2000Statistics.Average;

// Do something with the results here...

}
}
}

在单个表上评估 QueryDef

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
public async Task SimpleQueryDef()
{
await ArcGIS.Desktop.Framework.Threading.Tasks.QueuedTask.Run(() =>
{
using (Geodatabase geodatabase = new Geodatabase(new DatabaseConnectionFile(new Uri("path\\to\\sde\\file"))))
{
QueryDef adaCompilantParksQueryDef = new QueryDef
{
Tables = "Park",
WhereClause = "ADACOMPLY = 'Yes'",
};

using (RowCursor rowCursor = geodatabase.Evaluate(adaCompilantParksQueryDef, false))
{
while (rowCursor.MoveNext())
{
using (Row row = rowCursor.Current)
{
Feature feature = row as Feature;
Geometry shape = feature.GetShape();

String type = Convert.ToString(row["ADACOMPLY"]); // will be "Yes" for each row.

try
{
Table table = row.GetTable(); // Will always throw exception.
}
catch (NotSupportedException exception)
{
// Handle not supported exception.
}
}
}
}
}
});
}

使用 WHERE 子句计算连接上的 QueryDef

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
public async Task JoiningWithWhereQueryDef()
{
await ArcGIS.Desktop.Framework.Threading.Tasks.QueuedTask.Run(() =>
{
using (Geodatabase geodatabase = new Geodatabase(new DatabaseConnectionFile(new Uri("path\\to\\sde\\file"))))
{
QueryDef municipalEmergencyFacilitiesQueryDef = new QueryDef
{
SubFields = "EmergencyFacility.OBJECTID, EmergencyFacility.Shape, EmergencyFacility.FACILITYID, FacilitySite.FACILITYID, FacilitySite.FCODE",
Tables = "EmergencyFacility, FacilitySite",
WhereClause = "EmergencyFacility.FACNAME = FacilitySite.NAME AND EmergencyFacility.JURISDICT = 'Municipal'",
};

using (RowCursor rowCursor = geodatabase.Evaluate(municipalEmergencyFacilitiesQueryDef, false))
{
while (rowCursor.MoveNext())
{
using (Row row = rowCursor.Current)
{
Feature feature = row as Feature;
Geometry shape = feature.GetShape();

long objectID = Convert.ToInt64(row["EmergencyFacility.OBJECTID"]);
String featureCode = Convert.ToString(row["FacilitySite.FCODE"]);

IReadOnlyList<Field> fields = feature.GetFields(); //Contains one ArcGIS.Core.Data.Field objects for every subfield
}
}
}
}
});
}

在外部连接上计算 QueryDef

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
public async Task EvaluatingQueryDefWithOuterJoin()
{
await ArcGIS.Desktop.Framework.Threading.Tasks.QueuedTask.Run(() =>
{
using (Geodatabase geodatabase = new Geodatabase(new DatabaseConnectionFile(new Uri("path\\to\\sde\\file"))))
{
QueryDef queryDefWithLeftOuterJoin = new QueryDef
{
Tables = "CommunityAddress LEFT OUTER JOIN MunicipalBoundary on CommunityAddress.Municipality = MunicipalBoundary.Name",
SubFields = "CommunityAddress.OBJECTID, CommunityAddress.Shape, CommunityAddress.SITEADDID, CommunityAddress.ADDRNUM, CommunityAddress.FULLNAME, CommunityAddress.FULLADDR, CommunityAddress.MUNICIPALITY, MunicipalBoundary.Name, MunicipalBoundary.MUNITYP, MunicipalBoundary.LOCALFIPS",
};

using (RowCursor rowCursor = geodatabase.Evaluate(queryDefWithLeftOuterJoin, false))
{
while (rowCursor.MoveNext())
{
using (Row row = rowCursor.Current)
{
Feature feature = row as Feature;
Geometry shape = feature.GetShape();

int siteAddressId = Convert.ToInt32(row["CommunityAddress.SITEADDID"]);
String stateName = Convert.ToString(row["MunicipalBoundary.name"]);
}
}
}
}
});
}

在内部连接上评估 QueryDef

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
public async Task EvaluatingQueryDefWithInnerJoin()
{
await ArcGIS.Desktop.Framework.Threading.Tasks.QueuedTask.Run(() =>
{
using (Geodatabase geodatabase = new Geodatabase(new DatabaseConnectionFile(new Uri("path\\to\\sde\\file"))))
{
QueryDef queryDef = new QueryDef()
{
Tables = "People INNER JOIN States ON People.FK_STATE_ID = States.OBJECTID",
SubFields = "People.OBJECTID, People.First_Name, People.Last_Name, People.City, States.State_Name"
};

using (RowCursor cursor = geodatabase.Evaluate(queryDef))
{
while (cursor.MoveNext())
{
using (Row row = cursor.Current)
{
// Handle row
}
}
}
}
});
}

在嵌套 - INNER 和 OUTER 连接上评估 QueryDef

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
public async Task EvaluatingQueryDefWithNestedJoin()
{
await ArcGIS.Desktop.Framework.Threading.Tasks.QueuedTask.Run(() =>
{
using (Geodatabase geodatabase = new Geodatabase(
new DatabaseConnectionFile(new Uri("path\\to\\sde\\file"))))
{
QueryDef queryDef = new QueryDef()
{
Tables = "((People INNER JOIN States ON People.FK_STATE_ID = States.OBJECTID) LEFT OUTER JOIN Homes ON People.OBJECTID = Homes.FK_People_ID)",
SubFields = "People.OBJECTID, People.First_Name, People.Last_Name, States.State_Name, Homes.Address"
};

using (RowCursor cursor = geodatabase.Evaluate(queryDef, false))
{
while (cursor.MoveNext())
{
using (Row row = cursor.Current)
{
// Handle row
}
}
}
}
});
}

为数据库表创建默认查询描述并获取查询描述的 ArcGIS.Core.Data.Table

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
public async Task DefaultQueryDescription()
{
await ArcGIS.Desktop.Framework.Threading.Tasks.QueuedTask.Run(() =>
{
DatabaseConnectionProperties databaseConnectionProperties =
new DatabaseConnectionProperties(EnterpriseDatabaseType.SQLServer)
{
AuthenticationMode = AuthenticationMode.DBMS,
Instance = "instance",
Database = "database",
User = "user",
Password = "password"
};

using (Database database = new Database(databaseConnectionProperties))
{
QueryDescription queryDescription = database.GetQueryDescription("CUSTOMERS");

using (Table table = database.OpenTable(queryDescription))
{
//use table
}
}
});
}

从数据库表的自定义查询创建查询说明

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
public async Task CustomQueryDescription()
{
await ArcGIS.Desktop.Framework.Threading.Tasks.QueuedTask.Run(() =>
{
DatabaseConnectionProperties databaseConnectionProperties =
new DatabaseConnectionProperties(EnterpriseDatabaseType.SQLServer)
{
AuthenticationMode = AuthenticationMode.DBMS,
Instance = "instance",
Database = "database",
User = "user",
Password = "password"
};

using (Database database = new Database(databaseConnectionProperties))
{
QueryDescription queryDescription = database.GetQueryDescription("SELECT OBJECTID, Shape, FACILITYID FROM EmergencyFacility WHERE JURISDICT = 'Municipal'", "MunicipalEmergencyFacilities");

using (Table table = database.OpenTable(queryDescription))
{
// Use the table.
}
}
});
}

从没有不可为空的唯一 id 列的联接查询创建查询说明

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
public async Task JoinQueryDescription()
{
await ArcGIS.Desktop.Framework.Threading.Tasks.QueuedTask.Run(() =>
{
DatabaseConnectionProperties databaseConnectionProperties =
new DatabaseConnectionProperties(EnterpriseDatabaseType.SQLServer)
{
AuthenticationMode = AuthenticationMode.DBMS,
Instance = "instance",
Database = "database",
User = "user",
Password = "password"
};

using (Database database = new Database(databaseConnectionProperties))
{
QueryDescription queryDescription = database.GetQueryDescription("SELECT BUSLINES.ID as BUSLINESID, BUSSTOPS.ID as BUSSTOPSID, BUSLINES.RTE_DESC, BUSLINES.DIR, BUSSTOPS.JURISDIC, BUSSTOPS.LOCATION, BUSSTOPS.ROUTE,BUSSTOPS.SHAPE from demosql.dbo.BUSSTOPS JOIN demosql.dbo.BUSLINES ON BUSSTOPS.ROUTE = BUSLINES.ROUTE", "BusInfo");

queryDescription.SetObjectIDFields("BUSLINESID,BUSSTOPSID");

using (Table table = database.OpenTable(queryDescription))
{
// Use the table.
}
}
});
}

从具有多个形状类型的数据库表的查询创建查询说明

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
public async Task MultiGeometryQueryDescription()
{
await ArcGIS.Desktop.Framework.Threading.Tasks.QueuedTask.Run(() =>
{
DatabaseConnectionProperties databaseConnectionProperties = new DatabaseConnectionProperties(EnterpriseDatabaseType.SQLServer)
{
AuthenticationMode = AuthenticationMode.DBMS,
Instance = "instance",
Database = "database",
User = "user",
Password = "password"
};

using (Database database = new Database(databaseConnectionProperties))
{
QueryDescription pointQueryDescription = database.GetQueryDescription("select Description, SHAPE, UniqueID from MULTIGEOMETRYTEST", "MultiGeometryPoint");
pointQueryDescription.SetShapeType(GeometryType.Point);
using (Table pointTable = database.OpenTable(pointQueryDescription))
{
//use pointTable
}

QueryDescription polygonQueryDescription = database.GetQueryDescription("select Description, SHAPE, UniqueID from MULTIGEOMETRYTEST", "MultiGeometryPolygon");
polygonQueryDescription.SetShapeType(GeometryType.Polygon);
using (Table polygonTable = database.OpenTable(polygonQueryDescription))
{
//use polygonTable
}
}
});
}

从 SQLite 数据库表的查询创建查询说明

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public async Task SqliteQueryDescription()
{
await ArcGIS.Desktop.Framework.Threading.Tasks.QueuedTask.Run(() =>
{
using (Database database = new Database(new SQLiteConnectionPath(new Uri("Path\\To\\Sqlite\\Database\\USA.sqlite"))))
{
QueryDescription washingtonCitiesQueryDescription = database.GetQueryDescription("select OBJECTID, Shape, CITY_FIPS, CITY_NAME, STATE_FIPS, STATE_CITY, TYPE, CAPITAL from main.cities where STATE_NAME='Washington'", "WashingtonCities");

using (Table washingtonTable = database.OpenTable(washingtonCitiesQueryDescription))
{
// Use washingtonTable.
}
}
});
}

使用 SQLSyntax 形成与平台无关的查询

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
public async Task UsingSqlSyntaxToFormPlatformAgnosticQueries()
{
await ArcGIS.Desktop.Framework.Threading.Tasks.QueuedTask.Run(() =>
{
using (Geodatabase geodatabase = new Geodatabase(new FileGeodatabaseConnectionPath(new Uri("C:\\Data\\LocalGovernment.gdb"))))
using (FeatureClass featureClass = geodatabase.OpenDataset<FeatureClass>("FacilitySite"))
{
SQLSyntax sqlSyntax = geodatabase.GetSQLSyntax();
string substringFunctionName = sqlSyntax.GetFunctionName(SQLFunction.Substring);
string upperFunctionName = sqlSyntax.GetFunctionName(SQLFunction.Upper);
string substringfunction = string.Format("{0}({1}(FCODE, 1, 6)) = 'SCHOOL'", upperFunctionName, substringFunctionName);

QueryFilter queryFilter = new QueryFilter
{
WhereClause = substringfunction
};
using (Selection selection = featureClass.Select(queryFilter, SelectionType.ObjectID, SelectionOption.Normal))
{
// work with the selection.
}
}
});
}

将文件地理数据库要素类连接到具有虚拟关系类的 Oracle 数据库查询图层要素类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
public async Task JoiningFileGeodatabaseFeatureClassToOracleQueryLayer()
{
await ArcGIS.Desktop.Framework.Threading.Tasks.QueuedTask.Run(() =>
{
using (Geodatabase geodatabase = new Geodatabase(new FileGeodatabaseConnectionPath(new Uri("C:\\Data\\LocalGovernment.gdb"))))
using (Database database = new Database(
new DatabaseConnectionProperties(EnterpriseDatabaseType.Oracle)
{
AuthenticationMode = AuthenticationMode.DBMS,
Instance = "instance",
User = "user",
Password = "password",
Database = "database"
}))

using (FeatureClass leftFeatureClass = geodatabase.OpenDataset<FeatureClass>("Hospital"))
using (Table rightTable = database.OpenTable(database.GetQueryDescription("FacilitySite")))
{
Field originPrimaryKey = leftFeatureClass.GetDefinition().GetFields().FirstOrDefault(field => field.Name.Equals("facilityId"));
Field destinationForeignKey = rightTable.GetDefinition().GetFields().FirstOrDefault(field => field.Name.Equals("hospitalID"));

VirtualRelationshipClassDescription description =
new VirtualRelationshipClassDescription(
originPrimaryKey, destinationForeignKey, RelationshipCardinality.OneToOne);

using (RelationshipClass relationshipClass = leftFeatureClass.RelateTo(rightTable, description))
{
JoinDescription joinDescription = new JoinDescription(relationshipClass)
{
JoinDirection = JoinDirection.Forward,
JoinType = JoinType.LeftOuterJoin
};

Join join = new Join(joinDescription);

using (Table joinedTable = join.GetJoinedTable())
{
// Perform operation on joined table.
}
}
}
});
}

连接来自不同地理数据库的两个表

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
public async Task JoinTablesFromDifferentGeodatabases()
{
await ArcGIS.Desktop.Framework.Threading.Tasks.QueuedTask.Run(() =>
{
using (Geodatabase sourceGeodatabase = new Geodatabase(new FileGeodatabaseConnectionPath(new Uri("Path \\ to \\Geodatabase \\ one"))))
using (Geodatabase destinationGeodatabase = new Geodatabase(new FileGeodatabaseConnectionPath(new Uri("Path \\ to \\Geodatabase \\ two"))))
using (Table sourceTable = sourceGeodatabase.OpenDataset<Table>("State"))
using (Table destinationTable = destinationGeodatabase.OpenDataset<Table>("Cities"))
{
Field primaryKeyField = sourceTable.GetDefinition().GetFields().FirstOrDefault(field => field.Name.Equals("State.State_Abbreviation"));
Field foreignKeyField = destinationTable.GetDefinition().GetFields().FirstOrDefault(field => field.Name.Equals("Cities.State"));

VirtualRelationshipClassDescription virtualRelationshipClassDescription = new VirtualRelationshipClassDescription(primaryKeyField, foreignKeyField, RelationshipCardinality.OneToMany);

using (RelationshipClass relationshipClass = sourceTable.RelateTo(destinationTable, virtualRelationshipClassDescription))
{
JoinDescription joinDescription = new JoinDescription(relationshipClass)
{
JoinDirection = JoinDirection.Forward,
JoinType = JoinType.InnerJoin,
TargetFields = sourceTable.GetDefinition().GetFields()
};

using (Join join = new Join(joinDescription))
{
Table joinedTable = join.GetJoinedTable();

//Process the joined table. For example ..
using (RowCursor cursor = joinedTable.Search())
{
while (cursor.MoveNext())
{
using (Row row = cursor.Current)
{
// Use Row
}
}
}
}
}
}
});
}

使用在地理数据库中连接两个版本化表的查询创建查询表

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
public async Task QueryTableJoinWithVersionedData()
{
await ArcGIS.Desktop.Framework.Threading.Tasks.QueuedTask.Run(() =>
{
QueryDef queryDef = new QueryDef
{
Tables = "CommunityAddress JOIN MunicipalBoundary on CommunityAddress.Municipality = MunicipalBoundary.Name",
SubFields = "CommunityAddress.OBJECTID, CommunityAddress.Shape, CommunityAddress.SITEADDID, CommunityAddress.ADDRNUM, CommunityAddress.FULLNAME, CommunityAddress.FULLADDR, CommunityAddress.MUNICIPALITY, MunicipalBoundary.Name, MunicipalBoundary.MUNITYP, MunicipalBoundary.LOCALFIPS",
};

using (Geodatabase testVersion1Geodatabase = new Geodatabase(new DatabaseConnectionProperties(EnterpriseDatabaseType.Oracle)
{
AuthenticationMode = AuthenticationMode.DBMS,
Instance = "instance",
User = "user",
Password = "password",
Database = "database",
Version = "user.testVersion1"
}))
{
QueryTableDescription queryTableDescription = new QueryTableDescription(queryDef)
{
Name = "CommunityAddrJounMunicipalBoundr",
PrimaryKeys = testVersion1Geodatabase.GetSQLSyntax().QualifyColumnName("CommunityAddress", "OBJECTID")
};

// Will be based on testVersion1.
using (Table queryTable = testVersion1Geodatabase.OpenQueryTable(queryTableDescription))
{
// Use queryTable.
}
}

using (Geodatabase testVersion2Geodatabase = new Geodatabase(new DatabaseConnectionProperties(EnterpriseDatabaseType.Oracle)
{
AuthenticationMode = AuthenticationMode.DBMS,
Instance = "instance",
User = "user",
Password = "password",
Database = "database",
Version = "user.testVersion2"
}))
{
QueryTableDescription queryTableDescription = new QueryTableDescription(queryDef)
{
Name = "CommunityAddrJounMunicipalBoundr",
PrimaryKeys = testVersion2Geodatabase.GetSQLSyntax().QualifyColumnName("CommunityAddress", "OBJECTID")
};

// Will be based on testVersion2.
using (Table queryTable = testVersion2Geodatabase.OpenQueryTable(queryTableDescription))
{
// Use queryTable.
}
}
});
}

检查字段值是否为空

1
2
3
4
5
6
7
8
9
var val = row[field.Name];
if (val is DBNull || val == null)
{
// field value is null
}
else
{
// field value is not null
}

从字段中获取域字符串

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
public string GetDomainStringFromField(Row row, Field field)
{
// Get the table and table definition from the Row
using (Table table = row.GetTable())
using (TableDefinition tableDefinition = table.GetDefinition())
{
// Get name of subtype field
string subtypeFieldName = tableDefinition.GetSubtypeField();

// Get subtype, if any
Subtype subtype = null;

if (subtypeFieldName.Length != 0)
{
// Get value of subtype field for this row
var varSubtypeCode = row[subtypeFieldName];
long subtypeCode = (long)varSubtypeCode;

// Get subtype for this row
subtype = tableDefinition.GetSubtypes().First(x => x.GetCode() == subtypeCode);
}

// Get the coded value domain for this field
CodedValueDomain domain = field.GetDomain(subtype) as CodedValueDomain;

// Return the text string for this field
if (domain != null)
{
return domain.GetName(row[field.Name]);
}
else
{
return row[field.Name].ToString();
}
}
}

编辑

创建行

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
public async Task CreatingARow()
{
string message = String.Empty;
bool creationResult = false;
EditOperation editOperation = new EditOperation();

await ArcGIS.Desktop.Framework.Threading.Tasks.QueuedTask.Run(() =>
{

using (Geodatabase geodatabase = new Geodatabase(
new DatabaseConnectionFile(new Uri("path\\to\\sde\\file\\sdefile.sde"))))
using (Table enterpriseTable = geodatabase.OpenDataset<Table>("LocalGovernment.GDB.piCIPCost"))
{

//var geodatabase = new Geodatabase(new FileGeodatabaseConnectionPath(uri)) for a File GDB
//
//var shapeFileConnPath = new FileSystemConnectionPath(uri, FileSystemDatastoreType.Shapefile);
//var shapefile = new FileSystemDatastore(shapeFileConnPath);
//var table = shapefile.OpenDataset<Table>(strShapeFileName); for a Shape file

//declare the callback here. We are not executing it ~yet~
editOperation.Callback(context =>
{
TableDefinition tableDefinition = enterpriseTable.GetDefinition();
int assetNameIndex = tableDefinition.FindField("ASSETNA");

using (RowBuffer rowBuffer = enterpriseTable.CreateRowBuffer())
{
// Either the field index or the field name can be used in the indexer.
rowBuffer[assetNameIndex] = "wMain";
rowBuffer["COST"] = 700;
rowBuffer["ACTION"] = "Open Cut";

// subtype value for "Abandon".
rowBuffer[tableDefinition.GetSubtypeField()] = 3;

using (Row row = enterpriseTable.CreateRow(rowBuffer))
{
// To Indicate that the attribute table has to be updated.
context.Invalidate(row);
}
}
}, enterpriseTable);

try
{
creationResult = editOperation.Execute();
if (!creationResult) message = editOperation.ErrorMessage;
}
catch (GeodatabaseException exObj)
{
message = exObj.Message;
}
}
});

if (!string.IsNullOrEmpty(message))
MessageBox.Show(message);

}

创建特征

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
public async Task CreatingAFeature()
{
string message = String.Empty;
bool creationResult = false;

await ArcGIS.Desktop.Framework.Threading.Tasks.QueuedTask.Run(() =>
{
using (Geodatabase geodatabase = new Geodatabase(new DatabaseConnectionFile(new Uri("path\\to\\sde\\file\\sdefile.sde"))))
using (FeatureClass enterpriseFeatureClass = geodatabase.OpenDataset<FeatureClass>("LocalGovernment.GDB.FacilitySite"))
{
//var geodatabase = new Geodatabase(new FileGeodatabaseConnectionPath(uri)) for a File GDB
//
//var shapeFileConnPath = new FileSystemConnectionPath(uri, FileSystemDatastoreType.Shapefile);
//var shapefile = new FileSystemDatastore(shapeFileConnPath);
//var table = shapefile.OpenDataset<Table>(strShapeFileName); for a Shape file

//declare the callback here. We are not executing it ~yet~
EditOperation editOperation = new EditOperation();
editOperation.Callback(context =>
{
FeatureClassDefinition facilitySiteDefinition = enterpriseFeatureClass.GetDefinition();
int facilityIdIndex = facilitySiteDefinition.FindField("FACILITYID");

using (RowBuffer rowBuffer = enterpriseFeatureClass.CreateRowBuffer())
{
// Either the field index or the field name can be used in the indexer.
rowBuffer[facilityIdIndex] = "wMain";
rowBuffer["NAME"] = "Griffith Park";
rowBuffer["OWNTYPE"] = "Municipal";
rowBuffer["FCODE"] = "Park";
// Add it to Public Attractions Subtype.
rowBuffer[facilitySiteDefinition.GetSubtypeField()] = 820;

List<Coordinate2D> newCoordinates = new List<Coordinate2D>
{
new Coordinate2D(1021570, 1880583),
new Coordinate2D(1028730, 1880994),
new Coordinate2D(1029718, 1875644),
new Coordinate2D(1021405, 1875397)
};

rowBuffer[facilitySiteDefinition.GetShapeField()] = new PolygonBuilderEx(newCoordinates).ToGeometry();

using (Feature feature = enterpriseFeatureClass.CreateRow(rowBuffer))
{
//To Indicate that the attribute table has to be updated
context.Invalidate(feature);
}
}

}, enterpriseFeatureClass);

try
{
creationResult = editOperation.Execute();
if (!creationResult) message = editOperation.ErrorMessage;
}
catch (GeodatabaseException exObj)
{
message = exObj.Message;
}
}
});

if (!string.IsNullOrEmpty(message))
MessageBox.Show(message);
}

修改行

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
public async Task ModifyingARow()
{
string message = String.Empty;
bool modificationResult = false;

await ArcGIS.Desktop.Framework.Threading.Tasks.QueuedTask.Run(() =>
{
using (Geodatabase geodatabase = new Geodatabase(new DatabaseConnectionFile(new Uri("path\\to\\sde\\file\\sdefile.sde"))))
using (Table enterpriseTable = geodatabase.OpenDataset<Table>("LocalGovernment.GDB.piCIPCost"))
{
//var geodatabase = new Geodatabase(new FileGeodatabaseConnectionPath(uri)) for a File GDB
//
//var shapeFileConnPath = new FileSystemConnectionPath(uri, FileSystemDatastoreType.Shapefile);
//var shapefile = new FileSystemDatastore(shapeFileConnPath);
//var table = shapefile.OpenDataset<Table>(strShapeFileName); for a Shape file

EditOperation editOperation = new EditOperation();
editOperation.Callback(context =>
{
QueryFilter openCutFilter = new QueryFilter { WhereClause = "ACTION = 'Open Cut'" };

using (RowCursor rowCursor = enterpriseTable.Search(openCutFilter, false))
{
TableDefinition tableDefinition = enterpriseTable.GetDefinition();
int subtypeFieldIndex = tableDefinition.FindField(tableDefinition.GetSubtypeField());

while (rowCursor.MoveNext())
{
using (Row row = rowCursor.Current)
{
// In order to update the Map and/or the attribute table.
// Has to be called before any changes are made to the row.
context.Invalidate(row);

row["ASSETNA"] = "wMainOpenCut";

if (Convert.ToDouble(row["COST"]) > 700)
{
// Abandon asset if cost is higher than 700 (if that is what you want to do).
row["ACTION"] = "Open Cut Abandon";
row[subtypeFieldIndex] = 3; //subtype value for "Abandon"
}

//After all the changes are done, persist it.
row.Store();

// Has to be called after the store too.
context.Invalidate(row);
}
}
}
}, enterpriseTable);

try
{
modificationResult = editOperation.Execute();
if (!modificationResult) message = editOperation.ErrorMessage;
}
catch (GeodatabaseException exObj)
{
message = exObj.Message;
}
}
});

if (!string.IsNullOrEmpty(message))
MessageBox.Show(message);
}

修改特征

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
public async Task ModifyingAFeature()
{
string message = String.Empty;
bool modificationResult = false;

await ArcGIS.Desktop.Framework.Threading.Tasks.QueuedTask.Run(() =>
{
using (Geodatabase geodatabase = new Geodatabase(new DatabaseConnectionFile(new Uri("path\\to\\sde\\file\\sdefile.sde"))))
using (FeatureClass enterpriseFeatureClass = geodatabase.OpenDataset<FeatureClass>("LocalGovernment.GDB.FacilitySite"))
{

//var geodatabase = new Geodatabase(new FileGeodatabaseConnectionPath(uri)) for a File GDB
//
//var shapeFileConnPath = new FileSystemConnectionPath(uri, FileSystemDatastoreType.Shapefile);
//var shapefile = new FileSystemDatastore(shapeFileConnPath);
//var table = shapefile.OpenDataset<Table>(strShapeFileName); for a Shape file

FeatureClassDefinition facilitySiteDefinition = enterpriseFeatureClass.GetDefinition();

int ownTypeIndex = facilitySiteDefinition.FindField("OWNTYPE");
int areaIndex = facilitySiteDefinition.FindField(facilitySiteDefinition.GetAreaField());

EditOperation editOperation = new EditOperation();
editOperation.Callback(context =>
{
QueryFilter queryFilter = new QueryFilter { WhereClause = "FCODE = 'Hazardous Materials Facility' AND OWNTYPE = 'Private'" };

using (RowCursor rowCursor = enterpriseFeatureClass.Search(queryFilter, false))
{
while (rowCursor.MoveNext())
{
using (Feature feature = (Feature)rowCursor.Current)
{
// In order to update the Map and/or the attribute table.
// Has to be called before any changes are made to the row
context.Invalidate(feature);

// Transfer all Hazardous Material Facilities to the City.
feature[ownTypeIndex] = "Municipal";

if (Convert.ToDouble(feature[areaIndex]) > 50000)
{
// Set the Shape of the feature to whatever you need.
List<Coordinate2D> newCoordinates = new List<Coordinate2D>
{
new Coordinate2D(1021570, 1880583),
new Coordinate2D(1028730, 1880994),
new Coordinate2D(1029718, 1875644),
new Coordinate2D(1021405, 1875397)
};

feature.SetShape(new PolygonBuilderEx(newCoordinates).ToGeometry());
}

feature.Store();

// Has to be called after the store too
context.Invalidate(feature);
}
}
}
}, enterpriseFeatureClass);

try
{
modificationResult = editOperation.Execute();
if (!modificationResult) message = editOperation.ErrorMessage;
}
catch (GeodatabaseException exObj)
{
message = exObj.Message;
}
}
});

if (!string.IsNullOrEmpty(message))
MessageBox.Show(message);
}

将值写入 Guid 列

1
row[field.Name] = "{" + guid.ToString() + "}";

删除行/要素

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
public async Task DeletingARowOrFeature()
{
string message = String.Empty;
bool deletionResult = false;

await ArcGIS.Desktop.Framework.Threading.Tasks.QueuedTask.Run(() =>
{
using (Geodatabase geodatabase = new Geodatabase(new DatabaseConnectionFile(new Uri("path\\to\\sde\\file\\sdefile.sde"))))
using (Table enterpriseTable = geodatabase.OpenDataset<Table>("LocalGovernment.GDB.piCIPCost"))
{
//var geodatabase = new Geodatabase(new FileGeodatabaseConnectionPath(uri)) for a File GDB
//
//var shapeFileConnPath = new FileSystemConnectionPath(uri, FileSystemDatastoreType.Shapefile);
//var shapefile = new FileSystemDatastore(shapeFileConnPath);
//var table = shapefile.OpenDataset<Table>(strShapeFileName); for a Shape file

EditOperation editOperation = new EditOperation();
editOperation.Callback(context =>
{
QueryFilter openCutFilter = new QueryFilter { WhereClause = "ACTION = 'Open Cut'" };

using (RowCursor rowCursor = enterpriseTable.Search(openCutFilter, false))
{
while (rowCursor.MoveNext())
{
using (Row row = rowCursor.Current)
{
// In order to update the Map and/or the attribute table. Has to be called before the delete.
context.Invalidate(row);

row.Delete();
}
}
}
}, enterpriseTable);

try
{
deletionResult = editOperation.Execute();
if (!deletionResult) message = editOperation.ErrorMessage;
}
catch (GeodatabaseException exObj)
{
message = exObj.Message;
}
}
});

if (!string.IsNullOrEmpty(message))
MessageBox.Show(message);
}

添加附件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
public async Task AddingAttachments()
{
await ArcGIS.Desktop.Framework.Threading.Tasks.QueuedTask.Run(() =>
{
using (Geodatabase geodatabase = new Geodatabase(new DatabaseConnectionFile(new Uri("path\\to\\sde\\file\\sdefile.sde"))))
using (FeatureClass parkFeatureClass = geodatabase.OpenDataset<FeatureClass>("LocalGovernment.GDB.Park"))
{
QueryFilter filter = new QueryFilter { WhereClause = "NUMPARKING > 0" };

using (RowCursor parkingCursor = parkFeatureClass.Search(filter, false))
{
while (parkingCursor.MoveNext())
{
using (MemoryStream stream = CreateMemoryStreamFromContentsOf("Sample.xml"))
{
Attachment attachment = new Attachment("Sample.xml", "text/xml", stream);

using (Row row = parkingCursor.Current)
{
long attachmentId = row.AddAttachment(attachment);
}
}
}
}
}
});
}

private MemoryStream CreateMemoryStreamFromContentsOf(String fileNameWithPath)
{
MemoryStream memoryStream = new MemoryStream();

using (FileStream file = new FileStream(fileNameWithPath, FileMode.Open, FileAccess.Read))
{
byte[] bytes = new byte[file.Length];
file.Read(bytes, 0, (int)file.Length);
memoryStream.Write(bytes, 0, (int)file.Length);
}

return memoryStream;
}

更新附件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
public async Task UpdatingAttachments()
{
await ArcGIS.Desktop.Framework.Threading.Tasks.QueuedTask.Run(() =>
{
using (Geodatabase geodatabase = new Geodatabase(new DatabaseConnectionFile(new Uri("path\\to\\sde\\file\\sdefile.sde"))))
using (FeatureClass landUseCaseFeatureClass = geodatabase.OpenDataset<FeatureClass>("LocalGovernment.GDB.LandUseCase"))
{
QueryFilter filter = new QueryFilter { WhereClause = "CASETYPE = 'Rezoning'" };

using (RowCursor landUseCursor = landUseCaseFeatureClass.Search(filter, false))
{
while (landUseCursor.MoveNext())
{
using (Feature rezoningUseCase = (Feature)landUseCursor.Current)
{
IReadOnlyList<Attachment> rezoningAttachments = rezoningUseCase.GetAttachments();
IEnumerable<Attachment> filteredAttachments = rezoningAttachments.Where(attachment => !attachment.GetName().Contains("rezoning"));

foreach (Attachment attachmentToUpdate in filteredAttachments)
{
attachmentToUpdate.SetName(attachmentToUpdate.GetName().Replace(".pdf", "Rezoning.pdf"));
rezoningUseCase.UpdateAttachment(attachmentToUpdate);
}
}
}
}
}
});
}

删除附件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
public async Task DeletingAttachments()
{
await ArcGIS.Desktop.Framework.Threading.Tasks.QueuedTask.Run(() =>
{
using (Geodatabase geodatabase = new Geodatabase(new DatabaseConnectionFile(new Uri("path\\to\\sde\\file\\sdefile.sde"))))
using (Table inspectionTable = geodatabase.OpenDataset<Table>("luCodeInspection"))
{
QueryFilter queryFilter = new QueryFilter { WhereClause = "ACTION = '1st Notice'" };

using (RowCursor cursor = inspectionTable.Search(queryFilter, false))
{
while (cursor.MoveNext())
{
using (Row currentRow = cursor.Current)
{
IReadOnlyList<Attachment> rowAttachments = currentRow.GetAttachments(null, true);
IEnumerable<Attachment> attachments = rowAttachments.Where(attachment => attachment.GetContentType().Equals("application/pdf"));

var attachmentIDs = attachments.Select(attachment => attachment.GetAttachmentID()) as IReadOnlyList<long>;
IReadOnlyDictionary<long, Exception> failures = currentRow.DeleteAttachments(attachmentIDs);

if (failures.Count > 0)
{
//process errors
}
}
}
}
}
});
}

写入 Blob 字段

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
public async Task WriteBlobField(Table table, string blobFieldName, string imageFileName)
{
await ArcGIS.Desktop.Framework.Threading.Tasks.QueuedTask.Run(() =>
{
// Read the image file into a MemoryStream
MemoryStream memoryStream = new MemoryStream(); ;
using (FileStream imageFile = new FileStream(imageFileName, FileMode.Open, FileAccess.Read))
{
imageFile.CopyTo(memoryStream);
}

// Create a new row in the table, and write the Memory Stream into a blob fiele
using (RowBuffer rowBuffer = table.CreateRowBuffer())
{
rowBuffer[blobFieldName] = memoryStream;
table.CreateRow(rowBuffer).Dispose();
}
});
}

读取 Blob 字段

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
public async Task ReadBlobField(Table table, QueryFilter queryFilter, string blobFieldName)
{
await ArcGIS.Desktop.Framework.Threading.Tasks.QueuedTask.Run(() =>
{
const string imageFileBaseName = "C:\\path\\to\\image\\directory\\Image";

// for each row that satisfies the search criteria, write the blob field out to an image file
using (RowCursor rowCursor = table.Search(queryFilter))
{
int fileCount = 0;
while (rowCursor.MoveNext())
{
using (Row row = rowCursor.Current)
{
// Read the blob field into a MemoryStream
MemoryStream memoryStream = row[blobFieldName] as MemoryStream;

// Create a file
using (FileStream outputFile = new FileStream(imageFileBaseName + fileCount.ToString(), FileMode.Create, FileAccess.Write))
{
// Write the MemoryStream into the file
memoryStream.WriteTo(outputFile);
}
}
}
}
});
}

获取按关系类关联的行

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
public async Task GettingRowsRelatedByRelationshipClass()
{
await ArcGIS.Desktop.Framework.Threading.Tasks.QueuedTask.Run(() =>
{
using (Geodatabase geodatabase = new Geodatabase(new DatabaseConnectionFile(new Uri("path\\to\\sde\\file"))))
using (RelationshipClass relationshipClass = geodatabase.OpenDataset<RelationshipClass>("LocalGovernment.GDB.luCodeViolationHasInspections"))
using (FeatureClass violationsFeatureClass = geodatabase.OpenDataset<FeatureClass>("LocalGovernment.GDB.luCodeViolation"))
using (Table inspectionTable = geodatabase.OpenDataset<Table>("LocalGovernment.GDB.luCodeInspection"))
{
List<Row> jeffersonAveViolations = new List<Row>();
QueryFilter queryFilter = new QueryFilter { WhereClause = "LOCDESC LIKE '///%Jefferson///%'" };

using (RowCursor rowCursor = violationsFeatureClass.Search(queryFilter, false))
{
while (rowCursor.MoveNext())
{
jeffersonAveViolations.Add(rowCursor.Current);
}
}

IReadOnlyList<Row> relatedOriginRows = null;
IReadOnlyList<Row> relatedDestinationRows = null;

try
{
QueryFilter filter = new QueryFilter { WhereClause = "ACTION = '1st Notice'" };

using (Selection selection = inspectionTable.Select(filter, SelectionType.ObjectID, SelectionOption.Normal))
{
relatedOriginRows = relationshipClass.GetRowsRelatedToDestinationRows(selection.GetObjectIDs());
}

bool containsJeffersonAve = relatedOriginRows.Any(row => Convert.ToString(row["LOCDESC"]).Contains("Jefferson"));

List<long> jeffersonAveViolationObjectIds = jeffersonAveViolations.Select(row => row.GetObjectID()).ToList();

relatedDestinationRows = relationshipClass.GetRowsRelatedToOriginRows(jeffersonAveViolationObjectIds);
bool hasFirstNoticeInspections = relatedDestinationRows.Any(row => Convert.ToString(row["ACTION"]).Contains("1st Notice"));
}
finally
{
Dispose(jeffersonAveViolations);
Dispose(relatedOriginRows);
Dispose(relatedDestinationRows);
}
}
});
}

private static void Dispose(IEnumerable<Row> rows)
{
foreach (Row row in rows)
row.Dispose();
}

创建关系

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
public async Task CreatingARelationship()
{
await ArcGIS.Desktop.Framework.Threading.Tasks.QueuedTask.Run(() =>
{
using (Geodatabase geodatabase = new Geodatabase(new DatabaseConnectionFile(new Uri("path\\to\\sde\\file"))))
using (RelationshipClass relationshipClass = geodatabase.OpenDataset<RelationshipClass>("LocalGovernment.GDB.OverviewToProject"))
using (FeatureClass projectsFeatureClass = geodatabase.OpenDataset<FeatureClass>("LocalGovernment.GDB.CIPProjects"))
using (FeatureClass overviewFeatureClass = geodatabase.OpenDataset<FeatureClass>("LocalGovernment.GDB.CIPProjectsOverview"))
{
// This will be PROJNAME. This can be used to get the field index or used directly as the field name.
string originKeyField = relationshipClass.GetDefinition().GetOriginKeyField();

EditOperation editOperation = new EditOperation();
editOperation.Callback(context =>
{
// The rows are being added to illustrate adding relationships. If one has existing rows, those can be used to add a relationship.
using (RowBuffer projectsRowBuffer = projectsFeatureClass.CreateRowBuffer())
using (RowBuffer overviewRowBuffer = overviewFeatureClass.CreateRowBuffer())
{
projectsRowBuffer["TOTCOST"] = 500000;

overviewRowBuffer[originKeyField] = "LibraryConstruction";
overviewRowBuffer["PROJECTMAN"] = "John Doe";
overviewRowBuffer["FUNDSOUR"] = "Public";

using (Row projectsRow = projectsFeatureClass.CreateRow(projectsRowBuffer))
using (Row overviewRow = overviewFeatureClass.CreateRow(overviewRowBuffer))
{
Relationship relationship = relationshipClass.CreateRelationship(overviewRow, projectsRow);

//To Indicate that the Map has to draw this feature/row and/or the attribute table has to be updated
context.Invalidate(projectsRow);
context.Invalidate(overviewRow);
context.Invalidate(relationshipClass);
}
}
}, projectsFeatureClass, overviewFeatureClass);

bool editResult = editOperation.Execute();
}
});
}

删除关系

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
public async Task DeletingARelationship()
{
await ArcGIS.Desktop.Framework.Threading.Tasks.QueuedTask.Run(() =>
{
using (Geodatabase geodatabase = new Geodatabase(new DatabaseConnectionFile(new Uri("path\\to\\sde\\file"))))
using (RelationshipClass relationshipClass = geodatabase.OpenDataset<RelationshipClass>("LocalGovernment.GDB.luCodeViolationHasInspections"))
using (FeatureClass violationsFeatureClass = geodatabase.OpenDataset<FeatureClass>("LocalGovernment.GDB.luCodeViolation"))
{
QueryFilter queryFilter = new QueryFilter { WhereClause = "LOCDESC LIKE '///%Jefferson///%'" };

using (RowCursor rowCursor = violationsFeatureClass.Search(queryFilter, false))
{
if (!rowCursor.MoveNext())
return;

using (Row jeffersonAveViolation = rowCursor.Current)
{
IReadOnlyList<Row> relatedDestinationRows = relationshipClass.GetRowsRelatedToOriginRows(new List<long> { jeffersonAveViolation.GetObjectID() });

try
{
EditOperation editOperation = new EditOperation();
editOperation.Callback(context =>
{
foreach (Row relatedDestinationRow in relatedDestinationRows)
{
try
{
relationshipClass.DeleteRelationship(jeffersonAveViolation, relatedDestinationRow);
}
catch (GeodatabaseRelationshipClassException exception)
{
Console.WriteLine(exception);
}
}
}, relationshipClass);

bool editResult = editOperation.Execute();
}
finally
{
foreach (Row row in relatedDestinationRows)
row.Dispose();
}
}
}
}
});
}

使用插入游标

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
// Insert Cursors are intended for use in CoreHost applications, not Pro Add-ins
public void UsingInsertCursor()
{
using (Geodatabase geodatabase = new Geodatabase(new DatabaseConnectionFile(new Uri("path\\to\\sde\\file"))))
using (Table citiesTable = geodatabase.OpenDataset<Table>("name\\of\\cities_table"))
{
geodatabase.ApplyEdits(() =>
{
using (InsertCursor insertCursor = citiesTable.CreateInsertCursor())
using (RowBuffer rowBuffer = citiesTable.CreateRowBuffer())
{
rowBuffer["State"] = "Colorado";

rowBuffer["Name"] = "Fort Collins";
rowBuffer["Population"] = 167830;
insertCursor.Insert(rowBuffer);

rowBuffer["Name"] = "Denver";
rowBuffer["Population"] = 727211;
insertCursor.Insert(rowBuffer);

// Insert more rows here
// A more realistic example would be reading source data from a file

insertCursor.Flush();
}
});
}
}

使用 RowBuffer 在注记要素类中创建新的注记要素

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
public async Task CreatingAnAnnotationFeature(Geodatabase geodatabase)
{
await ArcGIS.Desktop.Framework.Threading.Tasks.QueuedTask.Run(() =>
{
using (AnnotationFeatureClass annotationFeatureClass = geodatabase.OpenDataset<AnnotationFeatureClass>("Annotation // feature // class // name"))
using (AnnotationFeatureClassDefinition annotationFeatureClassDefinition = annotationFeatureClass.GetDefinition())
using (RowBuffer rowBuffer = annotationFeatureClass.CreateRowBuffer())
using (AnnotationFeature annotationFeature = annotationFeatureClass.CreateRow(rowBuffer))
{
annotationFeature.SetAnnotationClassID(0);
annotationFeature.SetStatus(AnnotationStatus.Placed);

// Get the annotation labels from the label collection
IReadOnlyList<CIMLabelClass> labelClasses =
annotationFeatureClassDefinition.GetLabelClassCollection();

// Setup the symbol reference with the symbol id and the text symbol
CIMSymbolReference cimSymbolReference = new CIMSymbolReference();
cimSymbolReference.Symbol = labelClasses[0].TextSymbol.Symbol;
cimSymbolReference.SymbolName = labelClasses[0].TextSymbol.SymbolName;

// Setup the text graphic
CIMTextGraphic cimTextGraphic = new CIMTextGraphic();
cimTextGraphic.Text = "Charlotte, North Carolina";
cimTextGraphic.Shape = new MapPointBuilderEx(new Coordinate2D(-80.843, 35.234), SpatialReferences.WGS84).ToGeometry();
cimTextGraphic.Symbol = cimSymbolReference;

// Set the symbol reference on the graphic and store
annotationFeature.SetGraphic(cimTextGraphic);
annotationFeature.Store();
}
});
}

版本控制

连接到版本

1
2
3
4
5
6
7
8
9
10
11
12
13
14
public Geodatabase ConnectToVersion(Geodatabase geodatabase, string versionName)
{
Geodatabase connectedVersion = null;

if (geodatabase.IsVersioningSupported())
{
using (VersionManager versionManager = geodatabase.GetVersionManager())
using (Version version = versionManager.GetVersion(versionName))
{
connectedVersion = version.Connect();
}
}
return connectedVersion;
}

在单独的编辑会话中协调版本并将其与其父级进行核对和提交

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
public void ReconcileAndPost(Geodatabase geodatabase)
{
// Get a reference to our version and our parent
if (geodatabase.IsVersioningSupported())
{
using (VersionManager versionManager = geodatabase.GetVersionManager())
using (Version currentVersion = versionManager.GetCurrentVersion())
using (Version parentVersion = currentVersion.GetParent())
{

//// Create a ReconcileDescription object
//At 2.x -
//ReconcileDescription reconcileDescription = new ReconcileDescription(parentVersion);
//reconcileDescription.ConflictResolutionMethod = ConflictResolutionMethod.Continue; // continue if conflicts are found
//reconcileDescription.WithPost = true;

//// Reconcile and post
//ReconcileResult reconcileResult = currentVersion.Reconcile(reconcileDescription);

// ReconcileResult.HasConflicts can be checked as-needed

// Create a ReconcileOptions object
var reconcileOptions = new ReconcileOptions(parentVersion);
reconcileOptions.ConflictResolutionMethod = ConflictResolutionMethod.Continue; // continue if conflicts are found
reconcileOptions.ConflictDetectionType = ConflictDetectionType.ByRow; //Default
reconcileOptions.ConflictResolutionType = ConflictResolutionType.FavorTargetVersion;//or FavorEditVersion

// Reconcile
ReconcileResult reconcileResult = currentVersion.Reconcile(reconcileOptions);
if (!reconcileResult.HasConflicts)
{
//No conflicts, perform the post
var postOptions = new PostOptions(parentVersion);
//var postOptions = new PostOptions(); for default version
postOptions.ServiceSynchronizationType = ServiceSynchronizationType.Synchronous;//Default
currentVersion.Post(postOptions);
}

}
}
}

在同一编辑会话中协调版本并将其与其父级提交

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
public void ReconcileAndPost2(Geodatabase geodatabase)
{
// Get a reference to our version and our parent
if (geodatabase.IsVersioningSupported())
{
using (VersionManager versionManager = geodatabase.GetVersionManager())
using (Version currentVersion = versionManager.GetCurrentVersion())
using (Version parentVersion = currentVersion.GetParent())
{

//// Create a ReconcileDescription object
//At 2.x -
//ReconcileDescription reconcileDescription = new ReconcileDescription(parentVersion);
//reconcileDescription.ConflictResolutionMethod = ConflictResolutionMethod.Continue; // continue if conflicts are found
//reconcileDescription.WithPost = true;

//// Reconcile and post
//ReconcileResult reconcileResult = currentVersion.Reconcile(reconcileDescription);

// ReconcileResult.HasConflicts can be checked as-needed

// Create a ReconcileOptions object
var reconcileOptions = new ReconcileOptions(parentVersion);
reconcileOptions.ConflictResolutionMethod = ConflictResolutionMethod.Continue; // continue if conflicts are found
reconcileOptions.ConflictDetectionType = ConflictDetectionType.ByRow; //Default
reconcileOptions.ConflictResolutionType = ConflictResolutionType.FavorTargetVersion;//or FavorEditVersion

var postOptions = new PostOptions(parentVersion);
//var postOptions = new PostOptions(); for default version
postOptions.ServiceSynchronizationType = ServiceSynchronizationType.Synchronous;//Default

// Reconcile
ReconcileResult reconcileResult = currentVersion.Reconcile(reconcileOptions, postOptions);
if (reconcileResult.HasConflicts)
{
//TODO resolve conflicts

}

}
}
}

使用版本

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
public async Task WorkingWithVersions()
{
await ArcGIS.Desktop.Framework.Threading.Tasks.QueuedTask.Run(() =>
{
using (Geodatabase geodatabase = new Geodatabase(new DatabaseConnectionFile(new Uri("path\\to\\sde\\file"))))
using (VersionManager versionManager = geodatabase.GetVersionManager())
{
IReadOnlyList<Version> versionList = versionManager.GetVersions();

//The default version will have a null Parent
Version defaultVersion = versionList.First(version => version.GetParent() == null);

IEnumerable<Version> publicVersions = versionList.Where(
version => version.GetAccessType() == VersionAccessType.Public);
Version qaVersion = defaultVersion.GetChildren().First(
version => version.GetName().Contains("QA"));

Geodatabase qaVersionGeodatabase = qaVersion.Connect();

FeatureClass currentFeatureClass = geodatabase.OpenDataset<FeatureClass>("featureClassName");
FeatureClass qaFeatureClass = qaVersionGeodatabase.OpenDataset<FeatureClass>("featureClassName");
}
});
}

使用默认版本

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
// Check to see if the current version is default.
// Works with both branch and traditional versioning.
public bool IsDefaultVersion(Version version)
{
Version parentVersion = version.GetParent();
if (parentVersion == null)
{
return true;
}
parentVersion.Dispose();
return false;
}

public bool IsDefaultVersion(Geodatabase geodatabase)
{
if (!geodatabase.IsVersioningSupported()) return false;
using (VersionManager versionManager = geodatabase.GetVersionManager())
using (Version currentVersion = versionManager.GetCurrentVersion())
{
return IsDefaultVersion(currentVersion);
}
}

// Gets the default version.
// Works with both branch and traditional versioning.
// Note that this routine depends on IsDefaultVersion(), above.
public Version GetDefaultVersion(Version version)
{
if (IsDefaultVersion(version))
{
return version;
}
else
{
Version parent = version.GetParent();
Version ancestor = GetDefaultVersion(parent);
if (parent != ancestor)
{
parent.Dispose(); //If the versioning tree is more than 2 deep, we want to dispose any intermediary versions
}
return ancestor;
}
}

public Version GetDefaultVersion(Geodatabase geodatabase)
{
if (!geodatabase.IsVersioningSupported()) return null;

using (VersionManager versionManager = geodatabase.GetVersionManager())
{
Version currentVersion = versionManager.GetCurrentVersion();
Version defaultVersion = GetDefaultVersion(currentVersion);
if (currentVersion != defaultVersion)
{
currentVersion.Dispose(); // If we are not pointing to default, we want to dispose this Version object
}
return defaultVersion;
}
}

创建版本

1
2
3
4
5
6
7
8
9
10
public Version CreateVersion(Geodatabase geodatabase, string versionName, string description, VersionAccessType versionAccessType)
{
if (!geodatabase.IsVersioningSupported()) return null;

using (VersionManager versionManager = geodatabase.GetVersionManager())
{
VersionDescription versionDescription = new VersionDescription(versionName, description, versionAccessType);
return versionManager.CreateVersion(versionDescription);
}
}

创建历史版本

1
2
3
4
5
6
7
8
9
10
public HistoricalVersion CreateHistoricalVersion(Geodatabase geodatabase, string versionName)
{
using (VersionManager versionManager = geodatabase.GetVersionManager())
{
HistoricalVersionDescription historicalVersionDescription = new HistoricalVersionDescription(versionName, DateTime.Now);
HistoricalVersion historicalVersion = versionManager.CreateHistoricalVersion(historicalVersionDescription);

return historicalVersion;
}
}

在版本之间切换

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
public void ChangeVersions(Geodatabase geodatabase, string toVersionName)
{
using (VersionManager versionManager = geodatabase.GetVersionManager())
{
VersionBaseType versionBaseType = versionManager.GetCurrentVersionBaseType();

if (versionBaseType == VersionBaseType.Version)
{
Version fromVersion = versionManager.GetCurrentVersion();
Version toVersion = versionManager.GetVersion(toVersionName);

// Switch between versions
MapView.Active.Map.ChangeVersion(fromVersion,toVersion);
}

if (versionBaseType == VersionBaseType.HistoricalVersion)
{
HistoricalVersion fromHistoricalVersion = versionManager.GetCurrentHistoricalVersion();
HistoricalVersion toHistoricalVersion = versionManager.GetHistoricalVersion(toVersionName);

// Switch between historical versions
MapView.Active.Map.ChangeVersion(fromHistoricalVersion, toHistoricalVersion);
}

// Switch from HistoricalVersion to Version and vice-versa
// MapView.Active.Map.ChangeVersion(fromHistoricalVersion, toVersion);
// MapView.Active.Map.ChangeVersion(fromVersion, toHistoricalVersion);

}
}

部分过账

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
// Partial posting allows developers to post a subset of changes made in a version.
// One sample use case is an electric utility that uses a version to design the facilities in
// a new housing subdivision. At some point in the process, one block of new houses have been
// completed, while the rest of the subdivision remains unbuilt. Partial posting allows the user
// to post the completed work, while leaving not yet constructed features in the version to be
// posted later. Partial posting requires a branch-versioned feature service using ArcGIS
// Enterprise 10.9 and higher

// Specify a set of features that were constructed
QueryFilter constructedFilter = new QueryFilter()
{
WhereClause = "ConstructedStatus = 'True'"
};
// This selection represents the inserts and updates to the support
// structure feature class that we wish to post
using (Selection constructedSupportStructures =
supportStructureFeatureClass.Select(
constructedFilter, SelectionType.ObjectID, SelectionOption.Normal))
{
// Specifying which feature deletions you wish to post is slightly trickier, since you cannot issue
// a query to fetch a set of deleted features Instead, a list of ObjectIDs must be used
using (Selection deletedSupportStructures = supportStructureFeatureClass.Select(
null, SelectionType.ObjectID, SelectionOption.Empty))
{
deletedSupportStructures.Add(deletedSupportStructureObjectIDs); //deletedSupportStructureObjectIDs is
//defined as List<long>

//Perform the reconcile with partial post
//At 2.x -
//ReconcileDescription reconcileDescription = new ReconcileDescription();
//reconcileDescription.ConflictDetectionType = ConflictDetectionType.ByColumn;
//reconcileDescription.ConflictResolutionMethod = ConflictResolutionMethod.Continue;
//reconcileDescription.ConflictResolutionType = ConflictResolutionType.FavorEditVersion;
//reconcileDescription.PartialPostSelections = new List<Selection>() { constructedSupportStructures, deletedSupportStructures };
//reconcileDescription.WithPost = true;

//ReconcileResult reconcileResult = designVersion.Reconcile(reconcileDescription);

var reconcileOptions = new ReconcileOptions();//reconcile against Default
reconcileOptions.ConflictDetectionType = ConflictDetectionType.ByColumn;
reconcileOptions.ConflictResolutionMethod = ConflictResolutionMethod.Continue;
reconcileOptions.ConflictResolutionType = ConflictResolutionType.FavorEditVersion;

var postOptions = new PostOptions();//post against Default
postOptions.PartialPostSelections = new List<Selection>() {
constructedSupportStructures, deletedSupportStructures };
postOptions.ServiceSynchronizationType = ServiceSynchronizationType.Synchronous;

var reconcileResult = designVersion.Reconcile(reconcileOptions, postOptions);

//TODO process result(s)
}
}

DDL

创建表

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
// Create a PoleInspection table with the following fields
// GlobalID
// ObjectID
// InspectionDate (date)
// InspectionResults (pre-existing InspectionResults coded value domain)
// InspectionNotes (string)

// This static helper routine creates a FieldDescription for a GlobalID field with default values
FieldDescription globalIDFieldDescription = FieldDescription.CreateGlobalIDField();

// This static helper routine creates a FieldDescription for an ObjectID field with default values
FieldDescription objectIDFieldDescription = FieldDescription.CreateObjectIDField();

// Create a FieldDescription for the InspectionDate field
FieldDescription inspectionDateFieldDescription = new FieldDescription("InspectionDate", FieldType.Date)
{
AliasName = "Inspection Date"
};

// This static helper routine creates a FieldDescription for a Domain field (from a pre-existing domain)
FieldDescription inspectionResultsFieldDescription = FieldDescription.CreateDomainField("InspectionResults", new CodedValueDomainDescription(inspectionResultsDomain));
inspectionResultsFieldDescription.AliasName = "Inspection Results";

// This static helper routine creates a FieldDescription for a string field
FieldDescription inspectionNotesFieldDescription = FieldDescription.CreateStringField("InspectionNotes", 512);
inspectionNotesFieldDescription.AliasName = "Inspection Notes";

// Assemble a list of all of our field descriptions
List<FieldDescription> fieldDescriptions = new List<FieldDescription>()
{ globalIDFieldDescription, objectIDFieldDescription, inspectionDateFieldDescription, inspectionResultsFieldDescription, inspectionNotesFieldDescription };

// Create a TableDescription object to describe the table to create
TableDescription tableDescription = new TableDescription("PoleInspection", fieldDescriptions);

// Create a SchemaBuilder object
SchemaBuilder schemaBuilder = new SchemaBuilder(geodatabase);

// Add the creation of PoleInspection to our list of DDL tasks
schemaBuilder.Create(tableDescription);

// Execute the DDL
bool success = schemaBuilder.Build();

// Inspect error messages
if (!success)
{
IReadOnlyList<string> errorMessages = schemaBuilder.ErrorMessages;
//etc.
}

创建要素类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
// Create a Cities feature class with the following fields
// GlobalID
// ObjectID
// Name (string)
// Population (integer)

// This static helper routine creates a FieldDescription for a GlobalID field with default values
FieldDescription globalIDFieldDescription = FieldDescription.CreateGlobalIDField();

// This static helper routine creates a FieldDescription for an ObjectID field with default values
FieldDescription objectIDFieldDescription = FieldDescription.CreateObjectIDField();

// This static helper routine creates a FieldDescription for a string field
FieldDescription nameFieldDescription = FieldDescription.CreateStringField("Name", 255);

// This static helper routine creates a FieldDescription for an integer field
FieldDescription populationFieldDescription = FieldDescription.CreateIntegerField("Population");

// Assemble a list of all of our field descriptions
List<FieldDescription> fieldDescriptions = new List<FieldDescription>()
{ globalIDFieldDescription, objectIDFieldDescription, nameFieldDescription, populationFieldDescription };

// Create a ShapeDescription object
ShapeDescription shapeDescription = new ShapeDescription(GeometryType.Point, spatialReference);

// Alternatively, ShapeDescriptions can be created from another feature class. In this case, the new feature class will inherit the same shape properties of the existing class
ShapeDescription alternativeShapeDescription = new ShapeDescription(existingFeatureClass.GetDefinition());

// Create a FeatureClassDescription object to describe the feature class to create
FeatureClassDescription featureClassDescription =
new FeatureClassDescription("Cities", fieldDescriptions, shapeDescription);

// Create a SchemaBuilder object
SchemaBuilder schemaBuilder = new SchemaBuilder(geodatabase);

// Add the creation of the Cities feature class to our list of DDL tasks
schemaBuilder.Create(featureClassDescription);

// Execute the DDL
bool success = schemaBuilder.Build();

// Inspect error messages
if (!success)
{
IReadOnlyList<string> errorMessages = schemaBuilder.ErrorMessages;
//etc.
}

删除表

1
2
3
4
5
6
7
8
9
10
11
// Create a TableDescription object
TableDescription tableDescription = new TableDescription(table.GetDefinition());

// Create a SchemaBuilder object
SchemaBuilder schemaBuilder = new SchemaBuilder(geodatabase);

// Add the deletion of the table to our list of DDL tasks
schemaBuilder.Delete(tableDescription);

// Execute the DDL
bool success = schemaBuilder.Build();

删除要素类

1
2
3
4
5
6
7
8
9
10
11
// Create a FeatureClassDescription object
FeatureClassDescription featureClassDescription = new FeatureClassDescription(featureClass.GetDefinition());

// Create a SchemaBuilder object
SchemaBuilder schemaBuilder = new SchemaBuilder(geodatabase);

// Add the deletion fo the feature class to our list of DDL tasks
schemaBuilder.Delete(featureClassDescription);

// Execute the DDL
bool success = schemaBuilder.Build();

打开内存地理数据库

1
2
3
4
5
6
7
8
9
10
11
// Connects to the default memory geodatabase, if exists otherwise throws exception
MemoryConnectionProperties memoryConnectionProperties = new MemoryConnectionProperties();

// Alternatively, connects to memory geodatabase named as 'InterimMemoryGeodatabase'
// MemoryConnectionProperties memoryConnectionProperties = new MemoryConnectionProperties("InterimMemoryGeodatabase");

// Opens the memory geodatabase
using (Geodatabase geodatabase = new Geodatabase(memoryConnectionProperties))
{
// Use memory geodatabase
}

创建内存地理数据库

1
2
3
4
5
6
7
8
9
10
11
// Create the memory connection properties to connect to  default memory geodatabase
MemoryConnectionProperties memoryConnectionProperties = new MemoryConnectionProperties();

// Alternatively create the memory connection properties to connect to memory geodatabase named as 'InterimMemoryGeodatabase'
// MemoryConnectionProperties memoryConnectionProperties = new MemoryConnectionProperties("InterimMemoryGeodatabase");

// Create and use the memory geodatabase
using (Geodatabase geodatabase = SchemaBuilder.CreateGeodatabase(memoryConnectionProperties))
{
// Create additional schema here
}

删除内存地理数据库

1
2
3
4
5
// Create the memory connection properties to connect to default memory geodatabase
MemoryConnectionProperties memoryConnectionProperties = new MemoryConnectionProperties();

// Delete the memory geodatabase
SchemaBuilder.DeleteGeodatabase(memoryConnectionProperties);

创建文件地理数据库

1
2
3
4
5
6
7
8
9
10
// Create a FileGeodatabaseConnectionPath with the name of the file geodatabase you wish to create
FileGeodatabaseConnectionPath fileGeodatabaseConnectionPath =
new FileGeodatabaseConnectionPath(new Uri(@"C:\Path-To-File-Geodatabase\YourName.gdb"));

// Create and use the file geodatabase
using (Geodatabase geodatabase =
SchemaBuilder.CreateGeodatabase(fileGeodatabaseConnectionPath))
{
// Create additional schema here
}

删除文件地理数据库

1
2
3
4
5
// Create a FileGeodatabaseConnectionPath with the name of the file geodatabase you wish to delete
FileGeodatabaseConnectionPath fileGeodatabaseConnectionPath = new FileGeodatabaseConnectionPath(new Uri(@"C:\Path-To-File-Geodatabase\YourName.gdb"));

// Delete the file geodatabase
SchemaBuilder.DeleteGeodatabase(fileGeodatabaseConnectionPath);

创建移动地理数据库

1
2
3
4
5
6
7
8
9
// Create a MobileGeodatabaseConnectionPath with the name of the mobile geodatabase you wish to create
MobileGeodatabaseConnectionPath mobileGeodatabaseConnectionPath =
new MobileGeodatabaseConnectionPath(new Uri(@"C:\Path-To-Mobile-Geodatabase\YourName.geodatabase"));

// Create and use the mobile geodatabase
using (Geodatabase geodatabase = SchemaBuilder.CreateGeodatabase(mobileGeodatabaseConnectionPath))
{
// Create additional schema here
}

删除移动地理数据库

1
2
3
4
5
6
// Create a MobileGeodatabaseConnectionPath with the name of the mobile geodatabase you wish to delete
MobileGeodatabaseConnectionPath mobileGeodatabaseConnectionPath =
new MobileGeodatabaseConnectionPath(new Uri(@"C:\Path-To-Mobile-Geodatabase\YourName.geodatabase"));

// Delete the mobile geodatabase
SchemaBuilder.DeleteGeodatabase(mobileGeodatabaseConnectionPath);

创建范围域

1
2
3
4
5
6
7
8
9
10
// Create a range description with minimum value = 0 and maximum value = 1000
RangeDomainDescription rangeDomainDescriptionMinMax = new RangeDomainDescription("RangeDomain_0_1000",
FieldType.Integer, 0, 1000)
{ Description = "Domain value ranges from 0 to 1000" };

SchemaBuilder schemaBuilder = new SchemaBuilder(geodatabase);

// Create a range domain
schemaBuilder.Create(rangeDomainDescriptionMinMax);
schemaBuilder.Build();

创建编码值域

1
2
3
4
5
6
7
8
9
10
11
12
13
14
// Create a CodedValueDomain description for water pipes
CodedValueDomainDescription codedValueDomainDescription = new CodedValueDomainDescription("WaterPipeTypes", FieldType.String,
new SortedList<object, string> { { "Copper", "C_1" },
{ "Steel", "S_2" } })
{
SplitPolicy = SplitPolicy.Duplicate,
MergePolicy = MergePolicy.DefaultValue
};

SchemaBuilder schemaBuilder = new SchemaBuilder(geodatabase);

// Create a coded value domain
CodedValueDomainToken codedValueDomainToken = schemaBuilder.Create(codedValueDomainDescription);
schemaBuilder.Build();

创建要素数据集

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
// Creating a FeatureDataset named as 'Parcel_Information'

SchemaBuilder schemaBuilder = new SchemaBuilder(geodatabase);

// Create a FeatureDataset named as 'Parcel Information'
FeatureDatasetDescription featureDatasetDescription =
new FeatureDatasetDescription("Parcel_Information", SpatialReferences.WGS84);
schemaBuilder.Create(featureDatasetDescription);

// Build status
bool buildStatus = schemaBuilder.Build();

// Build errors
if (!buildStatus)
{
IReadOnlyList<string> errors = schemaBuilder.ErrorMessages;
}

删除要素数据集

1
2
3
4
5
6
7
8
9
10
11
// Deleting a FeatureDataset named as 'Parcel_Information'

FeatureDatasetDefinition featureDatasetDefinition = geodatabase.GetDefinition<FeatureDatasetDefinition>("Parcel_Information");
FeatureDatasetDescription featureDatasetDescription =
new FeatureDatasetDescription(featureDatasetDefinition);

SchemaBuilder schemaBuilder = new SchemaBuilder(geodatabase);

// Delete an existing feature dataset named as 'Parcel_Information'
schemaBuilder.Delete(featureDatasetDescription);
schemaBuilder.Build();

重命名要素数据集

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// Renaming a FeatureDataset from 'Parcel_Information' to 'Parcel_Information_With_Tax_Jurisdiction'

string originalDatasetName = "Parcel_Information";
string datasetRenameAs = "Parcel_Information_With_Tax_Jurisdiction";

FeatureDatasetDefinition originalDatasetDefinition =
geodatabase.GetDefinition<FeatureDatasetDefinition>(originalDatasetName);
FeatureDatasetDescription originalFeatureDatasetDescription =
new FeatureDatasetDescription(originalDatasetDefinition);

SchemaBuilder schemaBuilder = new SchemaBuilder(geodatabase);

// Rename the existing FeatureDataset, 'Parcel_Information' to 'Parcel_Information_With_Tax_Jurisdiction'
schemaBuilder.Rename(originalFeatureDatasetDescription, datasetRenameAs);
schemaBuilder.Build();

在一次操作中创建具有要素类的要素数据集

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
// Creating a FeatureDataset named as 'Parcel_Information' and a FeatureClass with name 'Parcels' in one operation

string featureDatasetName = "Parcel_Information";
string featureClassName = "Parcels";

SchemaBuilder schemaBuilder = new SchemaBuilder(geodatabase);

// Create a FeatureDataset token
FeatureDatasetDescription featureDatasetDescription = new FeatureDatasetDescription(featureDatasetName, SpatialReferences.WGS84);
FeatureDatasetToken featureDatasetToken = schemaBuilder.Create(featureDatasetDescription);

// Create a FeatureClass description
FeatureClassDescription featureClassDescription = new FeatureClassDescription(featureClassName,
new List<FieldDescription>()
{
new FieldDescription("Id", FieldType.Integer),
new FieldDescription("Address", FieldType.String)
},
new ShapeDescription(GeometryType.Point, SpatialReferences.WGS84));

// Create a FeatureClass inside a FeatureDataset
FeatureClassToken featureClassToken = schemaBuilder.Create(new FeatureDatasetDescription(featureDatasetToken), featureClassDescription);

// Build status
bool buildStatus = schemaBuilder.Build();

// Build errors
if (!buildStatus)
{
IReadOnlyList<string> errors = schemaBuilder.ErrorMessages;
}

在现有要素数据集中创建要素类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
// Creating a FeatureClass named as 'Tax_Jurisdiction' in existing FeatureDataset with name 'Parcels_Information'
string featureDatasetName = "Parcels_Information";
string featureClassName = "Tax_Jurisdiction";

// Create a FeatureClass description
FeatureClassDescription featureClassDescription = new FeatureClassDescription(featureClassName,
new List<FieldDescription>()
{
new FieldDescription("Tax_Id", FieldType.Integer),
new FieldDescription("Address", FieldType.String)
},
new ShapeDescription(GeometryType.Point, SpatialReferences.WGS84));

FeatureDatasetDefinition featureDatasetDefinition = geodatabase.GetDefinition<FeatureDatasetDefinition>(featureDatasetName);

SchemaBuilder schemaBuilder = new SchemaBuilder(geodatabase);

// Create a FeatureClass inside a FeatureDataset using a FeatureDatasetDefinition
schemaBuilder.Create(new FeatureDatasetDescription(featureDatasetDefinition), featureClassDescription);

// Build status
bool buildStatus = schemaBuilder.Build();

// Build errors
if (!buildStatus)
{
IReadOnlyList<string> errors = schemaBuilder.ErrorMessages;
}

将要素类添加到要素数据集

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
// Adding a FeatureClass with name 'Tax_Jurisdiction' into a FeatureDataset named as 'Parcels_Information'

string featureDatasetName = "Parcels_Information";
string featureClassNameToAdd = "Tax_Jurisdiction";

FeatureDatasetDefinition featureDatasetDefinition = geodatabase.GetDefinition<FeatureDatasetDefinition>(featureDatasetName);
FeatureDatasetDescription featureDatasetDescription = new FeatureDatasetDescription(featureDatasetDefinition);

FeatureClassDefinition featureClassDefinition = geodatabase.GetDefinition<FeatureClassDefinition>(featureClassNameToAdd);
FeatureClassDescription featureClassDescription = new FeatureClassDescription(featureClassDefinition);

SchemaBuilder schemaBuilder = new SchemaBuilder(geodatabase);

// Add the 'Tax_Jurisdiction' FeatureClass to the 'Parcels_Information' FeatureDataset
schemaBuilder.AddFeatureClass(featureDatasetDescription, featureClassDescription);
bool addStatus = schemaBuilder.Build();

if (!addStatus)
{
IReadOnlyList<string> errors = schemaBuilder.ErrorMessages;
}

重命名表

1
2
3
4
5
6
7
8
9
10
11
12
//Renaming a table from 'Original_Table' to 'Renamed_Table'

string tableToBeRenamed = "Original_Table";
string tableRenameAs = "Renamed_Table";

TableDefinition tableDefinition = geodatabase.GetDefinition<TableDefinition>(tableToBeRenamed);

SchemaBuilder schemaBuilder = new SchemaBuilder(geodatabase);

// Table rename
schemaBuilder.Rename(new TableDescription(tableDefinition), tableRenameAs);
schemaBuilder.Build();

向要素类添加字段

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
// Adding following fields to the 'Parcels' FeatureClass
// Global ID
// Parcel_ID
// Tax_Code
// Parcel_Address


// The FeatureClass to add fields
string featureClassName = "Parcels";

FeatureClassDefinition originalFeatureClassDefinition = geodatabase.GetDefinition<FeatureClassDefinition>(featureClassName);
FeatureClassDescription originalFeatureClassDescription = new
FeatureClassDescription(originalFeatureClassDefinition);

// The four new fields to add on the 'Parcels' FeatureClass
FieldDescription globalIdField = FieldDescription.CreateGlobalIDField();
FieldDescription parcelIdDescription = new FieldDescription("Parcel_ID", FieldType.GUID);
FieldDescription taxCodeDescription = FieldDescription.CreateIntegerField("Tax_Code");
FieldDescription addressDescription = FieldDescription.CreateStringField("Parcel_Address", 150);

List<FieldDescription> fieldsToAdd = new List<FieldDescription> { globalIdField, parcelIdDescription,
taxCodeDescription, addressDescription };

// Add new fields on the new FieldDescription list
List<FieldDescription> modifiedFieldDescriptions = new List<FieldDescription>(originalFeatureClassDescription.FieldDescriptions);
modifiedFieldDescriptions.AddRange(fieldsToAdd);

// The new FeatureClassDescription with additional fields
FeatureClassDescription modifiedFeatureClassDescription = new FeatureClassDescription(originalFeatureClassDescription.Name,
modifiedFieldDescriptions, originalFeatureClassDescription.ShapeDescription);

SchemaBuilder schemaBuilder = new SchemaBuilder(geodatabase);

// Update the 'Parcels' FeatureClass with newly added fields
schemaBuilder.Modify(modifiedFeatureClassDescription);
bool modifyStatus = schemaBuilder.Build();

if (!modifyStatus)
{
IReadOnlyList<string> errors = schemaBuilder.ErrorMessages;
}

添加使用域的字段

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
// Adding a field,'PipeType', which uses the coded value domain to the 'Pipes' FeatureClass

//The FeatureClass to add field
string featureClassName = "Pipes";

SchemaBuilder schemaBuilder = new SchemaBuilder(geodatabase);

// Create a CodedValueDomain description for water pipes
CodedValueDomainDescription pipeDomainDescription =
new CodedValueDomainDescription("WaterPipeTypes", FieldType.String,
new SortedList<object, string> { { "Copper", "C_1" },
{ "Steel", "S_2" } })
{
SplitPolicy = SplitPolicy.Duplicate,
MergePolicy = MergePolicy.DefaultValue
};

// Create a coded value domain token
CodedValueDomainToken codedValueDomainToken = schemaBuilder.Create(pipeDomainDescription);

// Create a new description from domain token
CodedValueDomainDescription codedValueDomainDescription = new CodedValueDomainDescription(codedValueDomainToken);

// Create a field named as 'PipeType' using a domain description
FieldDescription domainFieldDescription = new FieldDescription("PipeType", FieldType.String)
{ DomainDescription = codedValueDomainDescription };

//Retrieve existing information for 'Pipes' FeatureClass
FeatureClassDefinition originalFeatureClassDefinition = geodatabase.GetDefinition<FeatureClassDefinition>(featureClassName);
FeatureClassDescription originalFeatureClassDescription =
new FeatureClassDescription(originalFeatureClassDefinition);

// Add domain field on existing fields
List<FieldDescription> modifiedFieldDescriptions = new List<FieldDescription>(originalFeatureClassDescription.FieldDescriptions) { domainFieldDescription };

// Create a new description with updated fields for 'Pipes' FeatureClass
FeatureClassDescription featureClassDescription =
new FeatureClassDescription(originalFeatureClassDescription.Name, modifiedFieldDescriptions,
originalFeatureClassDescription.ShapeDescription);

// Update the 'Pipes' FeatureClass with domain field
schemaBuilder.Modify(featureClassDescription);

// Build status
bool buildStatus = schemaBuilder.Build();

// Build errors
if (!buildStatus)
{
IReadOnlyList<string> errors = schemaBuilder.ErrorMessages;
}

从表中删除字段

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
// Removing all fields from 'Parcels' table except following 
// Tax_Code
// Parcel_Address


// The table to remove fields
string tableName = "Parcels";

TableDefinition tableDefinition = geodatabase.GetDefinition<TableDefinition>(tableName);
IReadOnlyList<Field> fields = tableDefinition.GetFields();

// Existing fields from 'Parcels' table
Field taxCodeField = fields.First(f => f.Name.Equals("Tax_Code"));
Field parcelAddressField = fields.First(f => f.Name.Equals("Parcel_Address"));

FieldDescription taxFieldDescription = new FieldDescription(taxCodeField);
FieldDescription parcelAddressFieldDescription = new FieldDescription(parcelAddressField);

// Fields to retain in modified table
List<FieldDescription> fieldsToBeRetained = new List<FieldDescription>()
{
taxFieldDescription, parcelAddressFieldDescription
};

// New description of the 'Parcels' table with the 'Tax_Code' and 'Parcel_Address' fields
TableDescription modifiedTableDescription = new TableDescription(tableName, fieldsToBeRetained);

SchemaBuilder schemaBuilder = new SchemaBuilder(geodatabase);

// Remove all fields except the 'Tax_Code' and 'Parcel_Address' fields
schemaBuilder.Modify(modifiedTableDescription);
schemaBuilder.Build();

创建注记要素类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
// Creating a Cities annotation feature class
// with following user defined fields
// Name
// GlobalID

// Annotation feature class name
string annotationFeatureClassName = "CitiesAnnotation";

// Create user defined attribute fields for annotation feature class
FieldDescription globalIDFieldDescription = FieldDescription.CreateGlobalIDField();
FieldDescription nameFieldDescription = FieldDescription.CreateStringField("Name", 255);

// Create a list of all field descriptions
List<FieldDescription> fieldDescriptions = new List<FieldDescription> { globalIDFieldDescription, nameFieldDescription };

// Create a ShapeDescription object
ShapeDescription shapeDescription = new ShapeDescription(GeometryType.Polygon, spatialReference);

// Create general placement properties for Maplex engine
CIMMaplexGeneralPlacementProperties generalPlacementProperties =
new CIMMaplexGeneralPlacementProperties
{
AllowBorderOverlap = true,
PlacementQuality = MaplexQualityType.High,
DrawUnplacedLabels = true,
InvertedLabelTolerance = 1.0,
RotateLabelWithDisplay = true,
UnplacedLabelColor = new CIMRGBColor
{
R = 0,
G = 255,
B = 0,
Alpha = 0.5f // Green
}
};

// Create general placement properties for Standard engine

//CIMStandardGeneralPlacementProperties generalPlacementProperties =
// new CIMStandardGeneralPlacementProperties
// {
// DrawUnplacedLabels = true,
// InvertedLabelTolerance = 3.0,
// RotateLabelWithDisplay = true,
// UnplacedLabelColor = new CIMRGBColor
// {
// R = 255, G = 0, B = 0, Alpha = 0.5f // Red
// }
// };


// Create annotation label classes
// Green label
CIMLabelClass greenLabelClass = new CIMLabelClass
{
Name = "Green",
ExpressionTitle = "Expression-Green",
ExpressionEngine = LabelExpressionEngine.Arcade,
Expression = "$feature.OBJECTID",
ID = 1,
Priority = 0,
Visibility = true,
TextSymbol = new CIMSymbolReference
{
Symbol = new CIMTextSymbol()
{
Angle = 45,
FontType = FontType.Type1,
FontFamilyName = "Tahoma",
FontEffects = FontEffects.Normal,
HaloSize = 2.0,

Symbol = new CIMPolygonSymbol
{
SymbolLayers = new CIMSymbolLayer[]
{
new CIMSolidFill
{
Color = CIMColor.CreateRGBColor(0, 255, 0)
}
},
UseRealWorldSymbolSizes = true
}
},
MaxScale = 0,
MinScale = 0,
SymbolName = "TextSymbol-Green"
},
StandardLabelPlacementProperties = new CIMStandardLabelPlacementProperties
{
AllowOverlappingLabels = true,
LineOffset = 1.0
},
MaplexLabelPlacementProperties = new CIMMaplexLabelPlacementProperties
{
AlignLabelToLineDirection = true,
AvoidPolygonHoles = true
}
};

// Blue label
CIMLabelClass blueLabelClass = new CIMLabelClass
{
Name = "Blue",
ExpressionTitle = "Expression-Blue",
ExpressionEngine = LabelExpressionEngine.Arcade,
Expression = "$feature.OBJECTID",
ID = 2,
Priority = 0,
Visibility = true,
TextSymbol = new CIMSymbolReference
{
Symbol = new CIMTextSymbol()
{
Angle = 45,
FontType = FontType.Type1,
FontFamilyName = "Consolas",
FontEffects = FontEffects.Normal,
HaloSize = 2.0,

Symbol = new CIMPolygonSymbol
{
SymbolLayers = new CIMSymbolLayer[]
{
new CIMSolidFill
{
Color = CIMColor.CreateRGBColor(0, 0, 255)
}
},
UseRealWorldSymbolSizes = true
}
},
MaxScale = 0,
MinScale = 0,
SymbolName = "TextSymbol-Blue"
},
StandardLabelPlacementProperties = new CIMStandardLabelPlacementProperties
{
AllowOverlappingLabels = true,
LineOffset = 1.0
},
MaplexLabelPlacementProperties = new CIMMaplexLabelPlacementProperties
{
AlignLabelToLineDirection = true,
AvoidPolygonHoles = true
}
};

// Create a list of labels
List<CIMLabelClass> labelClasses = new List<CIMLabelClass> { greenLabelClass, blueLabelClass };

// Create an annotation feature class description object to describe the feature class to create
AnnotationFeatureClassDescription annotationFeatureClassDescription =
new AnnotationFeatureClassDescription(annotationFeatureClassName, fieldDescriptions, shapeDescription,
generalPlacementProperties, labelClasses)
{
IsAutoCreate = true,
IsSymbolIDRequired = false,
IsUpdatedOnShapeChange = true
};

// Create a SchemaBuilder object
SchemaBuilder schemaBuilder = new SchemaBuilder(geodatabase);

// Add the creation of the Cities annotation feature class to the list of DDL tasks
schemaBuilder.Create(annotationFeatureClassDescription);

// Execute the DDL
bool success = schemaBuilder.Build();

// Inspect error messages
if (!success)
{
IReadOnlyList<string> errorMessages = schemaBuilder.ErrorMessages;
//etc.
}

创建关联要素的注记要素类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
// Creating a feature-linked annotation feature class between water pipe and valve in water distribution network
// with following user defined fields
// PipeName
// GlobalID

// Annotation feature class name
string annotationFeatureClassName = "WaterPipeAnnotation";

// Create user defined attribute fields for annotation feature class
FieldDescription pipeGlobalID = FieldDescription.CreateGlobalIDField();
FieldDescription nameFieldDescription = FieldDescription.CreateStringField("Name", 255);

// Create a list of all field descriptions
List<FieldDescription> fieldDescriptions = new List<FieldDescription> { pipeGlobalID, nameFieldDescription };

// Create a ShapeDescription object
ShapeDescription shapeDescription = new ShapeDescription(GeometryType.Polygon, spatialReference);

// Create general placement properties for Maplex engine
CIMMaplexGeneralPlacementProperties generalPlacementProperties = new CIMMaplexGeneralPlacementProperties
{
AllowBorderOverlap = true,
PlacementQuality = MaplexQualityType.High,
DrawUnplacedLabels = true,
InvertedLabelTolerance = 1.0,
RotateLabelWithDisplay = true,
UnplacedLabelColor = new CIMRGBColor
{
R = 255,
G = 0,
B = 0,
Alpha = 0.5f
}
};

// Create annotation label classes
// Green label
CIMLabelClass greenLabelClass = new CIMLabelClass
{
Name = "Green",
ExpressionTitle = "Expression-Green",
ExpressionEngine = LabelExpressionEngine.Arcade,
Expression = "$feature.OBJECTID",
ID = 1,
Priority = 0,
Visibility = true,
TextSymbol = new CIMSymbolReference
{
Symbol = new CIMTextSymbol()
{
Angle = 45,
FontType = FontType.Type1,
FontFamilyName = "Tahoma",
FontEffects = FontEffects.Normal,
HaloSize = 2.0,

Symbol = new CIMPolygonSymbol
{
SymbolLayers = new CIMSymbolLayer[]
{
new CIMSolidFill
{
Color = CIMColor.CreateRGBColor(0, 255, 0)
}
},
UseRealWorldSymbolSizes = true
}
},
MaxScale = 0,
MinScale = 0,
SymbolName = "TextSymbol-Green"
},
StandardLabelPlacementProperties = new CIMStandardLabelPlacementProperties
{
AllowOverlappingLabels = true,
LineOffset = 1.0
},
MaplexLabelPlacementProperties = new CIMMaplexLabelPlacementProperties
{
AlignLabelToLineDirection = true,
AvoidPolygonHoles = true
}
};

// Blue label
CIMLabelClass blueLabelClass = new CIMLabelClass
{
Name = "Blue",
ExpressionTitle = "Expression-Blue",
ExpressionEngine = LabelExpressionEngine.Arcade,
Expression = "$feature.OBJECTID",
ID = 2,
Priority = 0,
Visibility = true,
TextSymbol = new CIMSymbolReference
{
Symbol = new CIMTextSymbol()
{
Angle = 45,
FontType = FontType.Type1,
FontFamilyName = "Consolas",
FontEffects = FontEffects.Normal,
HaloSize = 2.0,

Symbol = new CIMPolygonSymbol
{
SymbolLayers = new CIMSymbolLayer[]
{
new CIMSolidFill
{
Color = CIMColor.CreateRGBColor(0, 0, 255)
}
},
UseRealWorldSymbolSizes = true
}
},
MaxScale = 0,
MinScale = 0,
SymbolName = "TextSymbol-Blue"
},
StandardLabelPlacementProperties = new CIMStandardLabelPlacementProperties
{
AllowOverlappingLabels = true,
LineOffset = 1.0
},
MaplexLabelPlacementProperties = new CIMMaplexLabelPlacementProperties
{
AlignLabelToLineDirection = true,
AvoidPolygonHoles = true
}
};

// Create a list of labels
List<CIMLabelClass> labelClasses = new List<CIMLabelClass> { greenLabelClass, blueLabelClass };


// Create linked feature description
// Linked feature class name
string linkedFeatureClassName = "WaterPipe";

// Create fields for water pipe
FieldDescription waterPipeGlobalID = FieldDescription.CreateGlobalIDField();
FieldDescription pipeName = FieldDescription.CreateStringField("PipeName", 255);

// Create a list of water pipe field descriptions
List<FieldDescription> pipeFieldDescriptions = new List<FieldDescription> { waterPipeGlobalID, pipeName };

// Create a linked feature class description
FeatureClassDescription linkedFeatureClassDescription = new FeatureClassDescription(linkedFeatureClassName, pipeFieldDescriptions,
new ShapeDescription(GeometryType.Polyline, spatialReference));

// Create a SchemaBuilder object
SchemaBuilder schemaBuilder = new SchemaBuilder(geodatabase);

// Add the creation of the linked feature class to the list of DDL tasks
FeatureClassToken linkedFeatureClassToken = schemaBuilder.Create(linkedFeatureClassDescription);

// Create an annotation feature class description object to describe the feature class to create
AnnotationFeatureClassDescription annotationFeatureClassDescription =
new AnnotationFeatureClassDescription(annotationFeatureClassName, fieldDescriptions, shapeDescription,
generalPlacementProperties, labelClasses, new FeatureClassDescription(linkedFeatureClassToken))
{
IsAutoCreate = true,
IsSymbolIDRequired = false,
IsUpdatedOnShapeChange = true
};

// Add the creation of the annotation feature class to the list of DDL tasks
schemaBuilder.Create(annotationFeatureClassDescription);

// Execute the DDL
bool success = schemaBuilder.Build();

// Inspect error messages
if (!success)
{
IReadOnlyList<string> errorMessages = schemaBuilder.ErrorMessages;
//etc.
}

在要素数据集内创建注记要素类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
// Create a Cities annotation feature class inside Places feature dataset using existing annotation feature class 

// Feature dataset name
string featureDatasetName = "Places";

// Annotation feature class name
string annotationFeatureClassName = "CitiesAnnotation";

// Create a SchemaBuilder object
SchemaBuilder schemaBuilder = new SchemaBuilder(geodatabase);

// Open existing annotation feature class name
using (AnnotationFeatureClass existingAnnotationFeatureClass = geodatabase.OpenDataset<AnnotationFeatureClass>("ExistingAnnotationFeatureClass"))
{

// Create Feature dataset description
FeatureDatasetDescription featureDatasetDescription =
new FeatureDatasetDescription(featureDatasetName, existingAnnotationFeatureClass.GetDefinition().GetSpatialReference());

// Add the creation of the Places dataset to DDL task
FeatureDatasetToken featureDatasetToken = schemaBuilder.Create(featureDatasetDescription);

// Create an annotation feature class description using existing annotation feature class
AnnotationFeatureClassDescription annotationFeatureClassDescription = new AnnotationFeatureClassDescription(annotationFeatureClassName, existingAnnotationFeatureClass.GetDefinition())
{
IsAutoCreate = true,
IsSymbolIDRequired = false,
IsUpdatedOnShapeChange = true
};

// Add the creation of the Cities annotation feature class inside Places feature dataset
schemaBuilder.Create(new FeatureDatasetDescription(featureDatasetToken), annotationFeatureClassDescription);

// Execute the DDL
bool success = schemaBuilder.Build();

// Inspect error messages
if (!success)
{
IReadOnlyList<string> errorMessages = schemaBuilder.ErrorMessages;
//etc.
}
}

地理数据库拓扑代码段

开放拓扑和进程定义

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
public void OpenTopologyAndProcessDefinition()
{
// Open a geodatabase topology from a file geodatabase and process the topology definition.

using (Geodatabase geodatabase = new Geodatabase(new FileGeodatabaseConnectionPath(new Uri(@"C:\TestData\GrandTeton.gdb"))))
using (Topology topology = geodatabase.OpenDataset<Topology>("Backcountry_Topology"))
{
ProcessDefinition(geodatabase, topology);
}

// Open a feature service topology and process the topology definition.

const string TOPOLOGY_LAYER_ID = "0";

using (Geodatabase geodatabase = new Geodatabase(new ServiceConnectionProperties(new Uri("https://sdkexamples.esri.com/server/rest/services/GrandTeton/FeatureServer"))))
using (Topology topology = geodatabase.OpenDataset<Topology>(TOPOLOGY_LAYER_ID))
{
ProcessDefinition(geodatabase, topology);
}
}

private void ProcessDefinition(Geodatabase geodatabase, Topology topology)
{
// Similar to the rest of the Definition objects in the Core.Data API, there are two ways to open a dataset's
// definition -- via the Topology dataset itself or via the Geodatabase.

using (TopologyDefinition definitionViaTopology = topology.GetDefinition())
{
OutputDefinition(geodatabase, definitionViaTopology);
}

using (TopologyDefinition definitionViaGeodatabase =
geodatabase.GetDefinition<TopologyDefinition>("Backcountry_Topology"))
{
OutputDefinition(geodatabase, definitionViaGeodatabase);
}
}

private void OutputDefinition(Geodatabase geodatabase, TopologyDefinition topologyDefinition)
{
Console.WriteLine($"Topology cluster tolerance => {topologyDefinition.GetClusterTolerance()}");
Console.WriteLine($"Topology Z cluster tolerance => {topologyDefinition.GetZClusterTolerance()}");

IReadOnlyList<string> featureClassNames = topologyDefinition.GetFeatureClassNames();
Console.WriteLine($"There are {featureClassNames.Count} feature classes that are participating in the topology:");

foreach (string name in featureClassNames)
{
// Open each feature class that participates in the topology.

using (FeatureClass featureClass = geodatabase.OpenDataset<FeatureClass>(name))
using (FeatureClassDefinition featureClassDefinition = featureClass.GetDefinition())
{
Console.WriteLine($"\t{featureClass.GetName()} ({featureClassDefinition.GetShapeType()})");
}
}
}

获取拓扑规则

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
using (TopologyDefinition topologyDefinition = topology.GetDefinition())
{
IReadOnlyList<TopologyRule> rules = topologyDefinition.GetRules();

Console.WriteLine($"There are {rules.Count} topology rules defined for the topology:");
Console.WriteLine("ID \t Origin Class \t Origin Subtype \t Destination Class \t Destination Subtype \t Rule Type");

foreach (TopologyRule rule in rules)
{
Console.Write($"{rule.ID}");

Console.Write(!String.IsNullOrEmpty(rule.OriginClass) ? $"\t{rule.OriginClass}" : "\t\"\"");

Console.Write(rule.OriginSubtype != null ? $"\t{rule.OriginSubtype.GetName()}" : "\t\"\"");

Console.Write(!String.IsNullOrEmpty(rule.DestinationClass) ? $"\t{rule.DestinationClass}" : "\t\"\"");

Console.Write(rule.DestinationSubtype != null ? $"\t{rule.DestinationSubtype.GetName()}" : "\t\"\"");

Console.Write($"\t{rule.RuleType}");

Console.WriteLine();
}
}

验证拓扑

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
public void ValidateTopology()
{
using (Geodatabase geodatabase = new Geodatabase(new FileGeodatabaseConnectionPath(new Uri(@"C:\TestData\GrandTeton.gdb"))))
using (Topology topology = geodatabase.OpenDataset<Topology>("Backcountry_Topology"))
{
// If the topology currently does not have dirty areas, calling Validate() returns an empty envelope.

ValidationResult result = topology.Validate(new ValidationDescription(topology.GetExtent()));
Console.WriteLine($"'AffectedArea' after validating a topology that has not been edited => {result.AffectedArea.ToJson()}");

// Now create a feature that purposely violates the "PointProperlyInsideArea" topology rule. This action will
// create dirty areas.

Feature newFeature = null;

try
{
// Fetch the feature in the Campsites feature class whose objectID is 2. Then create a new geometry slightly
// altered from this and use it to create a new feature.

using (Feature featureViaCampsites2 = GetFeature(geodatabase, "Campsites", 2))
{
Geometry currentGeometry = featureViaCampsites2.GetShape();
Geometry newGeometry = GeometryEngine.Instance.Move(currentGeometry, (currentGeometry.Extent.XMax / 8),
(currentGeometry.Extent.YMax / 8));

using (FeatureClass campsitesFeatureClass = featureViaCampsites2.GetTable())
using (FeatureClassDefinition definition = campsitesFeatureClass.GetDefinition())
using (RowBuffer rowBuffer = campsitesFeatureClass.CreateRowBuffer())
{
rowBuffer[definition.GetShapeField()] = newGeometry;

geodatabase.ApplyEdits(() =>
{
newFeature = campsitesFeatureClass.CreateRow(rowBuffer);
});
}
}

// After creating a new feature in the 'Campsites' participating feature class, the topology's state should be
// "Unanalyzed" because it has not been validated.

Console.WriteLine($"The topology state after an edit has been applied => {topology.GetState()}");

// Now validate the topology. The result envelope corresponds to the dirty areas.

result = topology.Validate(new ValidationDescription(topology.GetExtent()));
Console.WriteLine($"'AffectedArea' after validating a topology that has just been edited => {result.AffectedArea.ToJson()}");

// After Validate(), the topology's state should be "AnalyzedWithErrors" because the topology currently has errors.

Console.WriteLine($"The topology state after validate topology => {topology.GetState()}");

// If there are no dirty areas, the result envelope should be empty.

result = topology.Validate(new ValidationDescription(topology.GetExtent()));
Console.WriteLine($"'AffectedArea' after validating a topology that has just been validated => {result.AffectedArea.ToJson()}");
}
finally
{
if (newFeature != null)
{
geodatabase.ApplyEdits(() =>
{
newFeature.Delete();
});

newFeature.Dispose();
}
}

// Validate again after deleting the newly-created feature.

topology.Validate(new ValidationDescription(topology.GetExtent()));
}
}

private Feature GetFeature(Geodatabase geodatabase, string featureClassName, long objectID)
{
using (FeatureClass featureClass = geodatabase.OpenDataset<FeatureClass>(featureClassName))
{
QueryFilter queryFilter = new QueryFilter()
{
ObjectIDs = new List<long>() { objectID }
};

using (RowCursor cursor = featureClass.Search(queryFilter))
{
System.Diagnostics.Debug.Assert(cursor.MoveNext());
return (Feature)cursor.Current;
}
}
}

获取拓扑错误

1
2
3
4
5
6
7
8
9
10
11
12
13
// Get all the errors and exceptions currently associated with the topology.

IReadOnlyList<TopologyError> allErrorsAndExceptions = topology.GetErrors(new ErrorDescription(topology.GetExtent()));
Console.WriteLine($"errors and exceptions count => {allErrorsAndExceptions.Count}");

Console.WriteLine("OriginClassName \t OriginObjectID \t DestinationClassName \t DestinationObjectID \t RuleType \t IsException \t Shape type \t Shape width & height \t Rule ID \t");

foreach (TopologyError error in allErrorsAndExceptions)
{
Console.WriteLine($"'{error.OriginClassName}' \t {error.OriginObjectID} \t '{error.DestinationClassName}' \t " +
$"{error.DestinationObjectID} \t {error.RuleType} \t {error.IsException} \t {error.Shape.GeometryType} \t " +
$"{error.Shape.Extent.Width},{error.Shape.Extent.Height} \t {error.RuleID}");
}

MarkAndUnmarkAsErrors

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
// Get all the errors due to features violating the "PointProperlyInsideArea" topology rule.

using (TopologyDefinition topologyDefinition = topology.GetDefinition())
{
TopologyRule pointProperlyInsideAreaRule = topologyDefinition.GetRules().First(rule => rule.RuleType == TopologyRuleType.PointProperlyInsideArea);

ErrorDescription errorDescription = new ErrorDescription(topology.GetExtent())
{
TopologyRule = pointProperlyInsideAreaRule
};

IReadOnlyList<TopologyError> errorsDueToViolatingPointProperlyInsideAreaRule = topology.GetErrors(errorDescription);
Console.WriteLine($"There are {errorsDueToViolatingPointProperlyInsideAreaRule.Count} feature violating the 'PointProperlyInsideArea' topology rule.");

// Mark all errors from features violating the 'PointProperlyInsideArea' topology rule as exceptions.

foreach (TopologyError error in errorsDueToViolatingPointProperlyInsideAreaRule)
{
topology.MarkAsException(error);
}

// Now verify all the errors from features violating the 'PointProperlyInsideArea' topology rule have indeed been
// marked as exceptions.
//
// By default, ErrorDescription is initialized to ErrorType.ErrorAndException. Here we want ErrorType.ErrorOnly.

errorDescription = new ErrorDescription(topology.GetExtent())
{
ErrorType = ErrorType.ErrorOnly,
TopologyRule = pointProperlyInsideAreaRule
};

IReadOnlyList<TopologyError> errorsAfterMarkedAsExceptions = topology.GetErrors(errorDescription);
Console.WriteLine($"There are {errorsAfterMarkedAsExceptions.Count} feature violating the 'PointProperlyInsideArea' topology rule after all the errors have been marked as exceptions.");

// Finally, reset all the exceptions as errors by unmarking them as exceptions.

foreach (TopologyError error in errorsDueToViolatingPointProperlyInsideAreaRule)
{
topology.UnmarkAsException(error);
}

IReadOnlyList<TopologyError> errorsAfterUnmarkedAsExceptions = topology.GetErrors(errorDescription);
Console.WriteLine($"There are {errorsAfterUnmarkedAsExceptions.Count} feature violating the 'PointProperlyInsideArea' topology rule after all the exceptions have been reset as errors.");
}

探索拓扑图

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
public void ExploreTopologyGraph()
{
using (Geodatabase geodatabase = new Geodatabase(new FileGeodatabaseConnectionPath(new Uri(@"C:\TestData\GrandTeton.gdb"))))
using (Topology topology = geodatabase.OpenDataset<Topology>("Backcountry_Topology"))
{
// Build a topology graph using the extent of the topology dataset.

topology.BuildGraph(topology.GetExtent(), (topologyGraph) =>
{
using (Feature campsites12 = GetFeature(geodatabase, "Campsites", 12))
{
IReadOnlyList<TopologyNode> topologyNodesViaCampsites12 = topologyGraph.GetNodes(campsites12);

TopologyNode topologyNodeViaCampsites12 = topologyNodesViaCampsites12[0];

IReadOnlyList<TopologyEdge> allEdgesConnectedToNodeViaCampsites12 = topologyNodeViaCampsites12.GetEdges();
IReadOnlyList<TopologyEdge> allEdgesConnectedToNodeViaCampsites12CounterClockwise = topologyNodeViaCampsites12.GetEdges(false);

System.Diagnostics.Debug.Assert(allEdgesConnectedToNodeViaCampsites12.Count == allEdgesConnectedToNodeViaCampsites12CounterClockwise.Count);

foreach (TopologyEdge edgeConnectedToNodeViaCampsites12 in allEdgesConnectedToNodeViaCampsites12)
{
TopologyNode fromNode = edgeConnectedToNodeViaCampsites12.GetFromNode();
TopologyNode toNode = edgeConnectedToNodeViaCampsites12.GetToNode();

bool fromNodeIsTheSameAsTopologyNodeViaCampsites12 = (fromNode == topologyNodeViaCampsites12);
bool toNodeIsTheSameAsTopologyNodeViaCampsites12 = (toNode == topologyNodeViaCampsites12);

System.Diagnostics.Debug.Assert(fromNodeIsTheSameAsTopologyNodeViaCampsites12 || toNodeIsTheSameAsTopologyNodeViaCampsites12,
"The FromNode *or* ToNode of each edge connected to 'topologyNodeViaCampsites12' should be the same as 'topologyNodeViaCampsites12' itself.");

IReadOnlyList<FeatureInfo> leftParentFeaturesBoundedByEdge = edgeConnectedToNodeViaCampsites12.GetLeftParentFeatures();
foreach (FeatureInfo featureInfo in leftParentFeaturesBoundedByEdge)
{
System.Diagnostics.Debug.Assert(!String.IsNullOrEmpty(featureInfo.FeatureClassName));
System.Diagnostics.Debug.Assert(featureInfo.ObjectID > 0);
EnsureShapeIsNotEmpty(featureInfo);
}

IReadOnlyList<FeatureInfo> leftParentFeaturesNotBoundedByEdge = edgeConnectedToNodeViaCampsites12.GetLeftParentFeatures(false);
foreach (FeatureInfo featureInfo in leftParentFeaturesNotBoundedByEdge)
{
System.Diagnostics.Debug.Assert(!String.IsNullOrEmpty(featureInfo.FeatureClassName));
System.Diagnostics.Debug.Assert(featureInfo.ObjectID > 0);
EnsureShapeIsNotEmpty(featureInfo);
}

IReadOnlyList<FeatureInfo> rightParentFeaturesBoundedByEdge = edgeConnectedToNodeViaCampsites12.GetRightParentFeatures();
foreach (FeatureInfo featureInfo in rightParentFeaturesBoundedByEdge)
{
System.Diagnostics.Debug.Assert(!String.IsNullOrEmpty(featureInfo.FeatureClassName));
System.Diagnostics.Debug.Assert(featureInfo.ObjectID > 0);
EnsureShapeIsNotEmpty(featureInfo);
}

IReadOnlyList<FeatureInfo> rightParentFeaturesNotBoundedByEdge = edgeConnectedToNodeViaCampsites12.GetRightParentFeatures(false);
foreach (FeatureInfo featureInfo in rightParentFeaturesNotBoundedByEdge)
{
System.Diagnostics.Debug.Assert(!String.IsNullOrEmpty(featureInfo.FeatureClassName));
System.Diagnostics.Debug.Assert(featureInfo.ObjectID > 0);
EnsureShapeIsNotEmpty(featureInfo);
}
}
}
});
}
}

private void EnsureShapeIsNotEmpty(FeatureInfo featureInfo)
{
using (Feature feature = featureInfo.GetFeature())
{
System.Diagnostics.Debug.Assert(!feature.GetShape().IsEmpty, "The feature's shape should not be empty.");
}
}

FindClosestElement

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
public void FindClosestElement()
{
using (Geodatabase geodatabase = new Geodatabase(new FileGeodatabaseConnectionPath(new Uri(@"C:\TestData\GrandTeton.gdb"))))
using (Topology topology = geodatabase.OpenDataset<Topology>("Backcountry_Topology"))
{
// Build a topology graph using the extent of the topology dataset.

topology.BuildGraph(topology.GetExtent(), (topologyGraph) =>
{
MapPoint queryPointViaCampsites12 = null;

using (Feature campsites12 = GetFeature(geodatabase, "Campsites", 12))
{
queryPointViaCampsites12 = campsites12.GetShape() as MapPoint;
}

double searchRadius = 1.0;

TopologyElement topologyElementViaCampsites12 =
topologyGraph.FindClosestElement<TopologyElement>(
queryPointViaCampsites12, searchRadius);

System.Diagnostics.Debug.Assert(
topologyElementViaCampsites12 != null, "There should be a topology element corresponding to 'queryPointViaCampsites12' within the 'searchRadius' units.");

IReadOnlyList<FeatureInfo> parentFeatures = topologyElementViaCampsites12.GetParentFeatures();

Console.WriteLine("The parent features that spawn 'topologyElementViaCampsites12' are:");
foreach (FeatureInfo parentFeature in parentFeatures)
{
Console.WriteLine($"\t{parentFeature.FeatureClassName}; OID: {parentFeature.ObjectID}");
}

TopologyNode topologyNodeViaCampsites12 = topologyGraph.FindClosestElement<TopologyNode>(queryPointViaCampsites12, searchRadius);

if (topologyNodeViaCampsites12 != null)
{
// There exists a TopologyNode nearest to the query point within searchRadius units.
}

TopologyEdge topologyEdgeViaCampsites12 = topologyGraph.FindClosestElement<TopologyEdge>(queryPointViaCampsites12, searchRadius);

if (topologyEdgeViaCampsites12 != null)
{
// There exists a TopologyEdge nearest to the query point within searchRadius units.
}
});
}
}

几何

空间参考

构造空间参考 - 从已知 ID

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// Use a builder convenience method or use a builder constructor.

// Builder convenience methods don't need to run on the MCT.
SpatialReference sr3857 = SpatialReferenceBuilder.CreateSpatialReference(3857);

// Builder constructors need to run on the MCT.
ArcGIS.Desktop.Framework.Threading.Tasks.QueuedTask.Run(() =>
{
using (SpatialReferenceBuilder srBuilder = new SpatialReferenceBuilder(3857))
{
// do something with the builder

sr3857 = srBuilder.ToSpatialReference();
}
});

构造空间引用 - 从字符串

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
// Use a builder convenience method or use a builder constructor.

string wkt = "GEOGCS[\"MyGCS84\",DATUM[\"D_WGS_1984\",SPHEROID[\"WGS_1984\",6378137.0,298.257223563]],PRIMEM[\"Greenwich\",0.0],UNIT[\"Radian\",1.0]]";

// Builder convenience methods don't need to run on the MCT.
SpatialReference sr = SpatialReferenceBuilder.CreateSpatialReference(wkt);

// Builder constructors need to run on the MCT.
ArcGIS.Desktop.Framework.Threading.Tasks.QueuedTask.Run(() =>
{
using (SpatialReferenceBuilder builder = new SpatialReferenceBuilder(wkt))
{
// do something with the builder

SpatialReference anotherSR = builder.ToSpatialReference();
}
});

使用 WGS84 空间参考

1
2
3
SpatialReference wgs84 = SpatialReferences.WGS84;
bool isProjected = wgs84.IsProjected; // false
bool isGeographic = wgs84.IsGeographic; // true

使用垂直坐标系构造空间参考 - 从已知 ID

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
// Use a builder convenience method or use a builder constructor.

// see a list of vertical coordinate systems at http://resources.arcgis.com/en/help/arcgis-rest-api/index.html#/Vertical_coordinate_systems/02r3000000rn000000/

// Builder convenience methods don't need to run on the MCT.
// 4326 = GCS_WGS_1984
// 115700 = vertical WGS_1984
SpatialReference sr4326_115700 = SpatialReferenceBuilder.CreateSpatialReference(4326, 115700);

// Builder constructors need to run on the MCT.
ArcGIS.Desktop.Framework.Threading.Tasks.QueuedTask.Run(() =>
{
using (SpatialReferenceBuilder sb = new SpatialReferenceBuilder(4326, 115700))
{
// SpatialReferenceBuilder properties
// sb.wkid == 4326
// sb.Wkt == "GEOGCS["MyGCS84",DATUM["D_WGS_1984",SPHEROID["WGS_1984",6378137.0,298.257223563]],PRIMEM["Greenwich",0.0],UNIT[\"Radian\",1.0]]"
// sb.name == GCS_WGS_1984
// sb.vcsWkid == 115700
// sb.VcsWkt == "VERTCS["WGS_1984",DATUM["D_WGS_1984",SPHEROID["WGS_1984",6378137.0,298.257223563]],PARAMETER["Vertical_Shift",0.0],PARAMETER["Direction",1.0],UNIT["Meter",1.0]]

// do something with the builder

sr4326_115700 = sb.ToSpatialReference();
}
});

使用垂直坐标系构造空间参考 - 从字符串

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
// Use a builder convenience method or use a builder constructor.

// custom VCS - use vertical shift of -1.23 instead of 0
string custom_vWkt = @"VERTCS[""SHD_height"",VDATUM[""Singapore_Height_Datum""],PARAMETER[""Vertical_Shift"",-1.23],PARAMETER[""Direction"",-1.0],UNIT[""Meter"",1.0]]";

// Builder convenience methods don't need to run on the MCT.
SpatialReference sr4326_customVertical = SpatialReferenceBuilder.CreateSpatialReference(4326, custom_vWkt);
// SpatialReferenceBuilder properties
// sr4326_customVertical.wkid == 4326
// sr4326_customVertical.vert_wkid == 0
// sr4326_customVertical.vert_wkt == custom_vWkt
// sr4326_customVertical.hasVcs == true

// Builder constructors need to run on the MCT.
ArcGIS.Desktop.Framework.Threading.Tasks.QueuedTask.Run(() =>
{
using (SpatialReferenceBuilder sb = new SpatialReferenceBuilder(4326, custom_vWkt))
{
// do something with the builder

sr4326_customVertical = sb.ToSpatialReference();
}
});

使用自定义 PCS 构造空间参考 - 从字符串

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
// Use a builder convenience method or use a builder constructor.

// Custom PCS, Predefined GCS
string customWkt = "PROJCS[\"WebMercatorMile\",GEOGCS[\"GCS_WGS_1984\",DATUM[\"D_WGS_1984\",SPHEROID[\"WGS_1984\",6378137.0,298.257223563]],PRIMEM[\"Greenwich\",0.0],UNIT[\"Degree\",0.0174532925199433]],PROJECTION[\"Mercator_Auxiliary_Sphere\"],PARAMETER[\"False_Easting\",0.0],PARAMETER[\"False_Northing\",0.0],PARAMETER[\"Central_Meridian\",0.0],PARAMETER[\"Standard_Parallel_1\",0.0],PARAMETER[\"Auxiliary_Sphere_Type\",0.0],UNIT[\"Mile\",1609.344000614692]]";

// Builder convenience methods don't need to run on the MCT.
SpatialReference spatialReference = SpatialReferenceBuilder.CreateSpatialReference(customWkt);
// SpatialReferenceBuilder properties
// spatialReference.Wkt == customWkt
// spatialReference.Wkid == 0
// spatialReference.VcsWkid == 0
// spatialReference.GcsWkid == 4326

SpatialReference gcs = spatialReference.Gcs;
// gcs.Wkid == 4326
// gcs.IsGeographic == true
// spatialReference.GcsWkt == gcs.Wkt

// Builder constructors need to run on the MCT.
ArcGIS.Desktop.Framework.Threading.Tasks.QueuedTask.Run(() =>
{
using (SpatialReferenceBuilder sb = new SpatialReferenceBuilder(customWkt))
{
// do something with the builder

spatialReference = sb.ToSpatialReference();
}
});

空间参考属性

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
// Builder constructors need to run on the MCT.
ArcGIS.Desktop.Framework.Threading.Tasks.QueuedTask.Run(() =>
{
// use the builder constructor
using (SpatialReferenceBuilder srBuilder = new SpatialReferenceBuilder(3857))
{
// spatial reference builder properties
int builderWkid = srBuilder.Wkid;
string builderWkt = srBuilder.Wkt;
string builderName = srBuilder.Name;

double xyScale = srBuilder.XYScale;
double xyTolerance = srBuilder.XYTolerance;
double xyResolution = srBuilder.XYResolution;
Unit unit = srBuilder.Unit;

double zScale = srBuilder.ZScale;
double zTolerance = srBuilder.ZTolerance;
Unit zUnit = srBuilder.ZUnit;

double mScale = srBuilder.MScale;
double mTolerance = srBuilder.MTolerance;

double falseX = srBuilder.FalseX;
double falseY = srBuilder.FalseY;
double falseZ = srBuilder.FalseZ;
double falseM = srBuilder.FalseM;

// get the spatial reference
SpatialReference sr3857 = srBuilder.ToSpatialReference();

// spatial reference properties
int srWkid = sr3857.Wkid;
string srWkt = sr3857.Wkt;
string srName = sr3857.Name;

xyScale = sr3857.XYScale;
xyTolerance = sr3857.XYTolerance;
xyResolution = sr3857.XYResolution;
unit = sr3857.Unit;

zScale = sr3857.ZScale;
zTolerance = sr3857.ZTolerance;
zUnit = sr3857.ZUnit;

mScale = sr3857.MScale;
mTolerance = sr3857.MTolerance;

falseX = sr3857.FalseX;
falseY = sr3857.FalseY;
falseZ = sr3857.FalseZ;
falseM = sr3857.FalseM;

bool hasVcs = sr3857.HasVcs;
}
});

导入和导出空间参考

1
2
3
4
5
6
7
8
9
10
11
SpatialReference srWithVertical = SpatialReferenceBuilder.CreateSpatialReference(4326, 6916);

string xml = srWithVertical.ToXml();
SpatialReference importedSR = SpatialReferenceBuilder.FromXml(xml);
// importedSR.Wkid = 4326
// importedSR.VcsWkid = 6916

string json = srWithVertical.ToJson();
importedSR = SpatialReferenceBuilder.FromJson(json);
// importedSR.Wkid = 4326
// importedSR.VcsWkid = 6916

确定给定点处空间参考的格网收敛

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
Coordinate2D coordinate = new Coordinate2D(10, 30);
double angle = SpatialReferences.WGS84.GetConvergenceAngle(coordinate);
// angle = 0

SpatialReference srUTM30N = SpatialReferenceBuilder.CreateSpatialReference(32630);
coordinate.X = 500000;
coordinate.Y = 550000;
angle = srUTM30N.GetConvergenceAngle(coordinate);
// angle = 0

MapPoint pointWGS84 = MapPointBuilderEx.CreateMapPoint(10, 50, SpatialReferences.WGS84);
MapPoint pointUTM30N = GeometryEngine.Instance.Project(
pointWGS84, srUTM30N) as MapPoint;

coordinate = (Coordinate2D)pointUTM30N;
// get convergence angle and convert to degrees
angle = srUTM30N.GetConvergenceAngle(coordinate) * 180 / Math.PI;
// angle = 10.03

基准

1
2
3
4
5
var cimMapDefinition = MapView.Active.Map.GetDefinition();
// use if map's sr does not have a vertical coordinate system
var datumTransformations = cimMapDefinition.DatumTransforms;
// use if map's sr has a vertical coordinate system
var hvDatumTransformations = cimMapDefinition.HVDatumTransforms;

空间参照基准和基准属性

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
// Get datum of a spatial reference
SpatialReference srWgs84 = SpatialReferences.WGS84;
Datum datum = srWgs84.Datum;
// datum.Name = "D_WGS_1984"
// datum.Wkid = 6326
// datum.SpheroidName = "WGS_1984"
// datum.SpheroidWkid = 7030
// datum.SpheroidFlattening = 0.0033528106647474805
// datum.SpheroidSemiMajorAxis = 6378137.0
// datum.SpheroidSemiMinorAxis = 6356752.3142451793

// Custom WKT
string wyomingWkt = "PROJCS[\"Wyoming_State_Pl_NAD_1927\",GEOGCS[\"GCS_North_American_1927\",DATUM[\"D_North_American_1927_Perry\",SPHEROID[\"Clarke_1866_Chase\",6378210.0,250.0]],PRIMEM[\"Greenwich\",0.0],UNIT[\"Degree\",0.0174532925199433]],PROJECTION[\"Transverse_Mercator\"],PARAMETER[\"false_easting\",500000.0],PARAMETER[\"false_northing\",0.0],PARAMETER[\"central_meridian\",-107.3333333],PARAMETER[\"scale_factor\",0.9999412],PARAMETER[\"latitude_of_origin\",40.66666667],UNIT[\"Foot_US\",0.3048006096012192]]";
SpatialReference srFromWkt = SpatialReferenceBuilder.CreateSpatialReference(wyomingWkt);
datum = srWgs84.Datum;
// datum.Name = "D_North_American_1927_Perry"
// datum.Wkid = 0
// datum.SpheroidName = "Clarke_1866_Chase"
// datum.SpheroidWkid = 0
// datum.SpheroidFlattening = 0.004
// datum.SpheroidSemiMajorAxis = 6378210.0
// datum.SpheroidSemiMinorAxis = 6352697.16

坐标3D

矢量极坐标

1
2
3
4
5
6
7
8
9
10
11
Coordinate3D polarVector = new Coordinate3D(0, 7, 0);
Tuple<double, double, double> polarComponents = polarVector.QueryPolarComponents();
// polarComponents.Item1 = 0 (azimuth)
// polarComponents.Item2 = 0 (inclination)
// polarComponents.Item3 = 7 (magnitude)

polarVector.SetPolarComponents(Math.PI / 4, Math.PI / 2, 8);
polarComponents = polarVector.QueryComponents();
// polarComponents.Item1 = 0 (x)
// polarComponents.Item2 = 0 (y)
// polarComponents.Item3 = 7 (z)

获取矢量倾角

1
2
3
4
5
6
7
8
Coordinate3D v = new Coordinate3D(0, 0, 7);
double inclination = v.Inclination; // inclination = PI/2

v.SetComponents(-2, -3, 0);
inclination = v.Inclination; // inclination = 0

v.SetComponents(0, 0, -2);
inclination = v.Inclination; // inclination = -PI/2

获取矢量方位角

1
2
3
4
5
6
7
8
9
10
Coordinate3D vector = new Coordinate3D(0, 7, 0);
double azimuth = vector.Azimuth; // azimuth = 0

vector.SetComponents(1, 1, 42);
azimuth = vector.Azimuth;
double degrees = AngularUnit.Degrees.ConvertFromRadians(azimuth); // degrees = 45

vector.SetComponents(-8, 8, 2);
azimuth = vector.Azimuth;
degrees = AngularUnit.Degrees.ConvertFromRadians(azimuth); // degrees = 315

向量运算

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
// Easy 3D vectors
Coordinate3D v = new Coordinate3D(0, 1, 0);
// v.Magnitude = 1

Coordinate3D other = new Coordinate3D(-1, 0, 0);
// other.Magnitude = -1

double dotProduct = v.DotProduct(other); // dotProduct = 0

Coordinate3D crossProduct = v.CrossProduct(other);
// crossProduct.X = 0
// crossProduct.Y = 0
// crossProduct.Z = 1

Coordinate3D addVector = v.AddCoordinate3D(other);
// addVector.X = -1
// addVector.Y = 1
// addVector.Z = 0

// Rotate around x-axis
Coordinate3D w = v;
w.Rotate(Math.PI, other);
// w.X = 0
// w.Y = -1
// w.Z = 0

w.Scale(0.5);
// w.X = 0
// w.Y = -0.5
// w.Z = 0

w.Scale(-4);
// w.X = 0
// ww.Y = 2
// w.Z = 0
// w.Magnitude = 2

w.Move(3, 2, 0);
// w.X = 3
// w.Y = 4
// w.Z = 0
// w.Magnitude = 5


Coordinate3D emptyVector = new Coordinate3D();
// emptyVector = (0, 0, 0)
emptyVector.SetEmpty();
// emptyVector = (Nan, Nan, Nan)

Coordinate3D c1 = new Coordinate3D(2, 3, 4);
Coordinate3D c2 = new Coordinate3D(9, -1, 3);

var result_add = c1 + c2;
// result_add = (11, 2, 7)
var result_sub = c1 - c2;
// result_sub = (-7, 4, 1)

var b = result_sub != result_add;
// b = true

result_add = emptyVector + c1;
// result_add = (Nan, Nan, Nan)

b = result_add == emptyVector;
// b = true

2D 矢量操作

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
Coordinate2D v = new Coordinate2D(0, 1);
// v.Magnitude = 1

Coordinate2D other = new Coordinate2D(-1, 0);
double dotProduct = v.DotProduct(other);
// dotProduct = 0

Coordinate2D w = v + other;
// w = (-1, 1)

w += other;
// w = (-2, 1)

w -= other;
// w = (-1, 1)

w = v;
w.Rotate(Math.PI, other);
// w = (-2, -1)

w = other;

w.Scale(-4);
// w = (4, 0)
// w.Magnitude = 4

w.Move(-1, 4);
// w = (3, 4)
// w.Magnitude = 5

w.Move(-6, -1);
Tuple<double, double> components = w.QueryComponents();
// components = (-3, 3)
// w.Magnitude = 3 * Math.Sqrt(2)

Coordinate2D unitVector = w.GetUnitVector();
// w = (-Math.Sqrt(2) / 2, Math.Sqrt(2) / 2)
// w.Magnitude = 1


w.SetComponents(3, 4);

生成器属性

生成器属性

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
// list of points
List<MapPoint> points = new List<MapPoint>
{
MapPointBuilderEx.CreateMapPoint(0, 0, 2, 3, 1),
MapPointBuilderEx.CreateMapPoint(1, 1, 5, 6),
MapPointBuilderEx.CreateMapPoint(2, 1, 6),
MapPointBuilderEx.CreateMapPoint(0, 0)
};

// will have attributes because it is created with convenience method
Polyline polylineWithAttrs = PolylineBuilderEx.CreatePolyline(points);
bool hasZ = polylineWithAttrs.HasZ; // hasZ = true
bool hasM = polylineWithAttrs.HasM; // hasM = true
bool hasID = polylineWithAttrs.HasID; // hasID = true

// will not have attributes because it is specified as a parameter
Polyline polylineWithoutAttrs =
PolylineBuilderEx.CreatePolyline(points, AttributeFlags.None);
hasZ = polylineWithoutAttrs.HasZ; // hasZ = false
hasM = polylineWithoutAttrs.HasM; // hasM = false
hasID = polylineWithoutAttrs.HasID; // hasID = false

// will have attributes because it is created with convenience method
Polygon polygonWithAttrs = PolygonBuilderEx.CreatePolygon(points);
hasZ = polygonWithAttrs.HasZ; // hasZ = true
hasM = polygonWithAttrs.HasM; // hasM = true
hasID = polygonWithAttrs.HasID; // hasID = true

// will not have attributes because it is specified as a parameter
Polygon polygonWithoutAttrs =
PolygonBuilderEx.CreatePolygon(points, AttributeFlags.None);
hasZ = polygonWithoutAttrs.HasZ; // hasZ = false
hasM = polygonWithoutAttrs.HasM; // hasM = false
hasID = polygonWithoutAttrs.HasID; // hasID = false

// will not have attributes because it is specified as a parameter
PolylineBuilderEx polylineB =
new PolylineBuilderEx(points, AttributeFlags.None);
hasZ = polylineB.HasZ; // hasZ = false
hasM = polylineB.HasM; // hasM = false
hasID = polylineB.HasID; // hasID = false

// will have attributes because it is passed an attributed polyline
polylineB = new PolylineBuilderEx(polylineWithAttrs);
hasZ = polylineB.HasZ; // hasZ = true
hasM = polylineB.HasM; // hasM = true
hasID = polylineB.HasID; // hasID = true

// will not have attributes because it is passed a non-attributed polyline
polylineB = new PolylineBuilderEx(polylineWithoutAttrs);
hasZ = polylineB.HasZ; // hasZ = false
hasM = polylineB.HasM; // hasM = false
hasID = polylineB.HasID; // hasID = false

// will not have attributes because it is specified as a parameter
PolygonBuilderEx polygonB = new PolygonBuilderEx(points, AttributeFlags.None);
hasZ = polygonB.HasZ; // hasZ = false
hasM = polygonB.HasM; // hasM = false
hasID = polygonB.HasID; // hasID = false

// will have attributes because it is passed an attributed polygon
polygonB = new PolygonBuilderEx(polygonWithAttrs);
hasZ = polygonB.HasZ; // hasZ = true
hasM = polygonB.HasM; // hasM = true
hasID = polygonB.HasID; // hasID = true

// will not have attributes because it is passed a non-attributed polygon
polygonB = new PolygonBuilderEx(polygonWithoutAttrs);
hasZ = polygonB.HasZ; // hasZ = true
hasM = polygonB.HasM; // hasM = true
hasID = polygonB.HasID; // hasID = true

地图点

构造地图点

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
// Use a builder convenience method or use a builder constructor.

// create a 3d point with M
MapPoint pt = MapPointBuilderEx.CreateMapPoint(1.0, 2.0, 3.0, 4.0);


// builderEx constructors don't need to run on the MCT.
MapPointBuilderEx mb = new MapPointBuilderEx(1.0, 2.0, 3.0, 4.0);
// do something with the builder

MapPoint ptWithM = mb.ToGeometry();


MapPoint clone = ptWithM.Clone() as MapPoint;
MapPoint anotherM = MapPointBuilderEx.CreateMapPoint(ptWithM);


MapPointBuilderEx builderEx = new MapPointBuilderEx(1.0, 2.0, 3.0);
builderEx.HasM = true;
builderEx.M = 4.0;

pt = builderEx.ToGeometry() as MapPoint;


// or another alternative with builderEx constructor
builderEx = new MapPointBuilderEx(1.0, 2.0, true, 3.0, true, 4.0, false, 0);
pt = builderEx.ToGeometry() as MapPoint;


// or use a builderEx convenience method
pt = MapPointBuilderEx.CreateMapPoint(1.0, 2.0, 3.0, 4.0);

地图点生成器属性

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
// Use a builderEx convenience method or a builderEx constructor.
// neither need to run on the MCT.

MapPoint point1 = null;
MapPoint point2 = null;

MapPointBuilderEx mb = new MapPointBuilderEx(1.0, 2.0, 3.0);
bool bhasZ = mb.HasZ; // hasZ = true
bool bhasM = mb.HasM; // hasM = false
bool bhasID = mb.HasID; // hasID = false

// do something with the builder

point1 = mb.ToGeometry();

// change some of the builder properties
mb.X = 11;
mb.Y = 22;
mb.HasZ = false;
mb.HasM = true;
mb.M = 44;
// create another point
point2 = mb.ToGeometry();

double x = point1.X; // x = 1.0
double y = point1.Y; // y = 2.0
double z = point1.Z; // z = 3.0
double m = point1.M; // m = Nan
int ID = point1.ID; // ID = 0
bool hasZ = point1.HasZ; // hasZ = true
bool hasM = point1.HasM; // hasM = false
bool hasID = point1.HasID; // hasID = false
bool isEmpty = point1.IsEmpty; // isEmpty = false

bool isEqual = point1.IsEqual(point2); // isEqual = false


// BuilderEx convenience methods
MapPoint point3 = MapPointBuilderEx.CreateMapPoint(point1);
x = point3.X; // x = 1.0
y = point3.Y; // y = 2.0
z = point3.Z; // z = 3.0
m = point3.M; // m = Nan
ID = point3.ID; // ID = 0
hasZ = point3.HasZ; // hasZ = true
hasM = point3.HasM; // hasM = false
hasID = point3.HasID; // hasID = false


MapPointBuilderEx builderEx = new MapPointBuilderEx(point1);
x = builderEx.X; // x = 1.0
y = builderEx.Y; // y = 2.0
z = builderEx.Z; // z = 3.0
m = builderEx.M; // m = Nan
ID = builderEx.ID; // ID = 0
hasZ = builderEx.HasZ; // hasZ = true
hasM = builderEx.HasM; // hasM = false
hasID = builderEx.HasID; // hasID = false
isEmpty = builderEx.IsEmpty; // isEmpty = false

MapPoint point4 = builderEx.ToGeometry() as MapPoint;


MapPoint point5 = MapPointBuilderEx.CreateMapPoint(point1);
x = point5.X; // x = 1.0
y = point5.Y; // y = 2.0
z = point5.Z; // z = 3.0
m = point5.M; // m = Nan
ID = point5.ID; // ID = 0
hasZ = point5.HasZ; // hasZ = true
hasM = point5.HasM; // hasM = false
hasID = point5.HasID; // hasID = false
isEmpty = point5.IsEmpty; // isEmpty = false

地图点是平等的

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
MapPoint pt1 = MapPointBuilderEx.CreateMapPoint(1, 2, 3, 4, 5);
int ID = pt1.ID; // ID = 5
bool hasID = pt1.HasID; // hasID = true

MapPoint pt2 = MapPointBuilderEx.CreateMapPoint(1, 2, 3, 4, 0);
ID = pt2.ID; // ID = 0
hasID = pt2.HasID; // hasID = true

MapPoint pt3 = MapPointBuilderEx.CreateMapPoint(1, 2, 3, 4);
ID = pt3.ID; // ID = 0
hasID = pt3.HasID; // hasID = false

MapPoint pt4 = MapPointBuilderEx.CreateMapPoint(1, 2, 3, 44);
ID = pt4.ID; // ID = 0
hasID = pt4.HasID; // hasID = false
bool hasM = pt4.HasM; // hasM = true

MapPoint pt5 = MapPointBuilderEx.CreateMapPoint(1, 2, 3);
ID = pt5.ID; // ID = 0
hasID = pt5.HasID; // hasID = false
hasM = pt5.HasM; // hasM = false

bool isEqual = pt1.IsEqual(pt2); // isEqual = false, different IDs
isEqual = pt2.IsEqual(pt3); // isEqual = false, HasId is different
isEqual = pt4.IsEqual(pt3); // isEqual = false, different Ms
isEqual = pt1.IsEqual(pt5); // isEqual = false, pt has M, id but pt5 does not.

缩放至指定点

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
//Create a point
var pt = MapPointBuilderEx.CreateMapPoint(x, y,
SpatialReferenceBuilder.CreateSpatialReference(4326));
//Buffer it - for purpose of zoom
var poly = GeometryEngine.Instance.Buffer(pt, buffer_size);

//do we need to project the buffer polygon?
if (!MapView.Active.Map.SpatialReference.IsEqual(poly.SpatialReference))
{
//project the polygon
poly = GeometryEngine.Instance.Project(poly, MapView.Active.Map.SpatialReference);
}

// Must run on MCT.
QueuedTask.Run(() =>
{
//Zoom - add in a delay for animation effect
MapView.Active.ZoomTo(poly, new TimeSpan(0, 0, 0, 3));
});

折线

构造折线 - 从映射点的枚举

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
// Use a builderEx convenience method or a builderEx constructor.
// neither need to run on the MCT

MapPoint startPt = MapPointBuilderEx.CreateMapPoint(1.0, 1.0);
MapPoint endPt = MapPointBuilderEx.CreateMapPoint(2.0, 1.0);

List<MapPoint> list = new List<MapPoint>();
list.Add(startPt);
list.Add(endPt);

Polyline polyline = PolylineBuilderEx.CreatePolyline(list, SpatialReferences.WGS84);

// use AttributeFlags.None since we only have 2D points in the list
PolylineBuilderEx pb = new PolylineBuilderEx(list, AttributeFlags.None);
pb.SpatialReference = SpatialReferences.WGS84;
Polyline polyline2 = pb.ToGeometry();

// use AttributeFlags.NoAttributes because we only have 2d points in the list
Polyline polyline4 = PolylineBuilderEx.CreatePolyline(list, AttributeFlags.None);

获取折线的点

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
// get the points as a readonly Collection
ReadOnlyPointCollection pts = polyline.Points;
int numPts = polyline.PointCount;

// OR get an enumeration of the points
IEnumerator<MapPoint> enumPts = polyline.Points.GetEnumerator();

// OR get the point coordinates as a readonly list of Coordinate2D
IReadOnlyList<Coordinate2D> coordinates = polyline.Copy2DCoordinatesToList();

// OR get the point coordinates as a readonly list of Coordinate3D
IReadOnlyList<Coordinate3D> coordinates3D = polyline.Copy3DCoordinatesToList();

// OR get a subset of the collection as Coordinate2D using preallocated memory

IList<Coordinate2D> coordinate2Ds = new List<Coordinate2D>(10); // allocate some space
ICollection<Coordinate2D> subsetCoordinates2D = coordinate2Ds; // assign
pts.Copy2DCoordinatesToList(1, 2, ref subsetCoordinates2D); // copy 2 elements from index 1 into the allocated list
// coordinate2Ds.Count = 2
// do something with the coordinate2Ds

// without allocating more space, obtain a different set of coordinates
pts.Copy2DCoordinatesToList(5, 9, ref subsetCoordinates2D); // copy 9 elements from index 5 into the allocated list
// coordinate2Ds.Count = 9


// OR get a subset of the collection as Coordinate3D using preallocated memory

IList<Coordinate3D> coordinate3Ds = new List<Coordinate3D>(15); // allocate some space
ICollection<Coordinate3D> subsetCoordinates3D = coordinate3Ds; // assign
pts.Copy3DCoordinatesToList(3, 5, ref subsetCoordinates3D); // copy 5 elements from index 3 into the allocated list
// coordinate3Ds.Count = 5


// OR get a subset of the collection as MapPoint using preallocated memory

IList<MapPoint> mapPoints = new List<MapPoint>(7); // allocate some space
ICollection<MapPoint> subsetMapPoint = mapPoints; // assign
pts.CopyPointsToList(1, 4, ref subsetMapPoint); // copy 4 elements from index 1 into the allocated list
// mapPoints.Count = 4

获取折线的各个部分

1
2
3
int numParts = polyline.PartCount;
// get the parts as a readonly collection
ReadOnlyPartCollection parts = polyline.Parts;

枚举折线的各个部分

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
ReadOnlyPartCollection polylineParts = polyline.Parts;

// enumerate the segments to get the length
double len = 0;
IEnumerator<ReadOnlySegmentCollection> segments = polylineParts.GetEnumerator();
while (segments.MoveNext())
{
ReadOnlySegmentCollection seg = segments.Current;
foreach (Segment s in seg)
{
len += s.Length;

// perhaps do something specific per segment type
switch (s.SegmentType)
{
case SegmentType.Line:
break;
case SegmentType.Bezier:
break;
case SegmentType.EllipticArc:
break;
}
}
}

// or use foreach pattern
foreach (var part in polyline.Parts)
{
foreach (var segment in part)
{
len += segment.Length;

// perhaps do something specific per segment type
switch (segment.SegmentType)
{
case SegmentType.Line:
break;
case SegmentType.Bezier:
break;
case SegmentType.EllipticArc:
break;
}
}
}

反转折线中点的顺序

1
2
3
var polylineBuilder = new PolylineBuilderEx(polyline);
polylineBuilder.ReverseOrientation();
Polyline reversedPolyline = polylineBuilder.ToGeometry();

获取折线的段

1
2
3
4
5
6
7
8
9
10
11
12
ICollection<Segment> collection = new List<Segment>();
polyline.GetAllSegments(ref collection);
int numSegments = collection.Count; // = 10

IList<Segment> iList = collection as IList<Segment>;
for (int i = 0; i < numSegments; i++)
{
// do something with iList[i]
}

// use the segments to build another polyline
Polyline polylineFromSegments = PolylineBuilderEx.CreatePolyline(collection);

构建多部分折线

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
List<MapPoint> firstPoints = new List<MapPoint>();
firstPoints.Add(MapPointBuilderEx.CreateMapPoint(1.0, 1.0));
firstPoints.Add(MapPointBuilderEx.CreateMapPoint(1.0, 2.0));
firstPoints.Add(MapPointBuilderEx.CreateMapPoint(2.0, 2.0));
firstPoints.Add(MapPointBuilderEx.CreateMapPoint(2.0, 1.0));

List<MapPoint> nextPoints = new List<MapPoint>();
nextPoints.Add(MapPointBuilderEx.CreateMapPoint(11.0, 1.0));
nextPoints.Add(MapPointBuilderEx.CreateMapPoint(11.0, 2.0));
nextPoints.Add(MapPointBuilderEx.CreateMapPoint(12.0, 2.0));
nextPoints.Add(MapPointBuilderEx.CreateMapPoint(12.0, 1.0));

// use AttributeFlags.None since we have 2D points in the list
PolylineBuilderEx pBuilder = new PolylineBuilderEx(firstPoints, AttributeFlags.None);
pBuilder.AddPart(nextPoints);

Polyline polyline = pBuilder.ToGeometry();
// polyline has 2 parts

pBuilder.RemovePart(0);
polyline = pBuilder.ToGeometry();
// polyline has 1 part

折线的起点

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
// Method 1: Get the start point of the polyline by converting the polyline 
// into a collection of points and getting the first point

// sketchGeometry is a Polyline
// get the sketch as a point collection
var pointCol = ((Multipart)sketchGeometry).Points;
// Get the start point of the line
var firstPoint = pointCol[0];

// Method 2: Convert polyline into a collection of line segments
// and get the "StartPoint" of the first line segment.
var polylineGeom = sketchGeometry as ArcGIS.Core.Geometry.Polyline;
var polyLineParts = polylineGeom.Parts;

ReadOnlySegmentCollection polylineSegments = polyLineParts.First();

//get the first segment as a LineSegment
var firsLineSegment = polylineSegments.First() as LineSegment;

//Now get the start Point
var startPoint = firsLineSegment.StartPoint;

按角度构造布料

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
MapPoint startPoint = MapPointBuilderEx.CreateMapPoint(0, 0);
double tangentDirection = Math.PI / 6;
ArcOrientation orientation = ArcOrientation.ArcCounterClockwise;
double startRadius = double.PositiveInfinity;
double endRadius = 0.2;
ClothoidCreateMethod createMethod = ClothoidCreateMethod.ByAngle;
double angle = Math.PI / 2;
CurveDensifyMethod densifyMethod = CurveDensifyMethod.ByLength;
double densifyParameter = 0.1;

Polyline polyline = PolylineBuilderEx.CreatePolyline(startPoint, tangentDirection, startRadius, endRadius, orientation, createMethod, angle, densifyMethod, densifyParameter, SpatialReferences.WGS84);

int numPoints = polyline.PointCount;
MapPoint queryPoint = polyline.Points[numPoints - 2];

MapPoint pointOnPath;
double radiusCalculated, tangentDirectionCalculated, lengthCalculated, angleCalculated;

PolylineBuilderEx.QueryClothoidParameters(queryPoint, startPoint, tangentDirection, startRadius, endRadius, orientation, createMethod, angle, out pointOnPath, out radiusCalculated, out tangentDirectionCalculated, out lengthCalculated, out angleCalculated, SpatialReferences.WGS84);

按长度构造布料

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
MapPoint startPoint = MapPointBuilderEx.CreateMapPoint(0, 0);
MapPoint queryPoint = MapPointBuilderEx.CreateMapPoint(3.8, 1);
double tangentDirection = 0;
ArcOrientation orientation = ArcOrientation.ArcCounterClockwise;
double startRadius = double.PositiveInfinity;
double endRadius = 1;
ClothoidCreateMethod createMethod = ClothoidCreateMethod.ByLength;
double curveLength = 10;
MapPoint pointOnPath;
double radiusCalculated, tangentDirectionCalculated, lengthCalculated, angleCalculated;


PolylineBuilderEx.QueryClothoidParameters(queryPoint, startPoint, tangentDirection, startRadius, endRadius, orientation, createMethod, curveLength, out pointOnPath, out radiusCalculated, out tangentDirectionCalculated, out lengthCalculated, out angleCalculated, SpatialReferences.WGS84);

pointOnPath = MapPointBuilderEx.CreateMapPoint(3.7652656620171379, 1.0332006103128575);
radiusCalculated = 2.4876382887687227;
tangentDirectionCalculated = 0.80797056423543978;
lengthCalculated = 4.0198770235802987;
angleCalculated = 0.80797056423544011;

queryPoint = MapPointBuilderEx.CreateMapPoint(1.85, 2.6);

PolylineBuilderEx.QueryClothoidParameters(queryPoint, startPoint, tangentDirection, startRadius, endRadius, orientation, createMethod, curveLength, out pointOnPath, out radiusCalculated, out tangentDirectionCalculated, out lengthCalculated, out angleCalculated, SpatialReferences.WGS84);

pointOnPath = MapPointBuilderEx.CreateMapPoint(1.8409964973501549, 2.6115979967308132);
radiusCalculated = 1;
tangentDirectionCalculated = -1.2831853071795867;
lengthCalculated = 10;
angleCalculated = 5;

tangentDirection = Math.PI / 4;
orientation = ArcOrientation.ArcClockwise;
startRadius = double.PositiveInfinity;
endRadius = 0.8;
createMethod = ClothoidCreateMethod.ByLength;
curveLength = 10;

Polyline polyline = PolylineBuilderEx.CreatePolyline(startPoint, tangentDirection, startRadius, endRadius, orientation, createMethod, curveLength, CurveDensifyMethod.ByLength, 0.5, SpatialReferences.WGS84);

远距离分割折线

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
// create list of points
MapPoint startPt = MapPointBuilderEx.CreateMapPoint(1.0, 1.0);
MapPoint endPt = MapPointBuilderEx.CreateMapPoint(2.0, 1.0);

List<MapPoint> list = new List<MapPoint>();
list.Add(startPt);
list.Add(endPt);

// BuilderEx constructors don't need to run on the MCT.

// use the PolylineBuilder as we wish to manipulate the geometry
// use AttributeFlags.None as we have 2D points
PolylineBuilderEx polylineBuilder = new PolylineBuilderEx(list, AttributeFlags.None);
// split at a distance 0.75
polylineBuilder.SplitAtDistance(0.75, false);
// get the polyline
Polyline p = polylineBuilder.ToGeometry();
// polyline p should have 3 points (1,1), (1.75, 1), (2,1)

// add another path
MapPoint p1 = MapPointBuilderEx.CreateMapPoint(4.0, 1.0);
MapPoint p2 = MapPointBuilderEx.CreateMapPoint(6.0, 1.0);
MapPoint p3 = MapPointBuilderEx.CreateMapPoint(7.0, 1.0);
List<MapPoint> pts = new List<MapPoint>();
pts.Add(p1);
pts.Add(p2);
pts.Add(p3);

polylineBuilder.AddPart(pts);
p = polylineBuilder.ToGeometry();

// polyline p has 2 parts. Each part has 3 points

// split the 2nd path half way - dont create a new path
polylineBuilder.SplitPartAtDistance(1, 0.5, true, false);

p = polylineBuilder.ToGeometry();

// polyline p still has 2 parts; but now has 7 points

多边形

构造多边形 - 从映射点的枚举

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
// Use a builderEx convenience method or use a builderEx constructor.

MapPoint pt1 = MapPointBuilderEx.CreateMapPoint(1.0, 1.0);
MapPoint pt2 = MapPointBuilderEx.CreateMapPoint(1.0, 2.0);
MapPoint pt3 = MapPointBuilderEx.CreateMapPoint(2.0, 2.0);
MapPoint pt4 = MapPointBuilderEx.CreateMapPoint(2.0, 1.0);

List<MapPoint> list = new List<MapPoint>() { pt1, pt2, pt3, pt4 };

Polygon polygon = PolygonBuilderEx.CreatePolygon(list, SpatialReferences.WGS84);
// polygon.HasZ will be false - it is determined by the HasZ flag of the points in the list

// or specifically use AttributeFlags.NoAttributes
polygon = PolygonBuilderEx.CreatePolygon(list, AttributeFlags.None);

// use AttributeFlags.None as we have 2D points
PolygonBuilderEx polygonBuilder = new PolygonBuilderEx(list, AttributeFlags.None);
polygonBuilder.SpatialReference = SpatialReferences.WGS84;
polygon = polygonBuilder.ToGeometry();

构造多边形 - 从信封

1
2
3
4
5
6
7
8
9
10
11
12
13
// Use a builderEx convenience method or use a builderEx constructor.

MapPoint minPt = MapPointBuilderEx.CreateMapPoint(1.0, 1.0);
MapPoint maxPt = MapPointBuilderEx.CreateMapPoint(2.0, 2.0);

// Create an envelope
Envelope env = EnvelopeBuilderEx.CreateEnvelope(minPt, maxPt);

Polygon polygonFromEnv = PolygonBuilderEx.CreatePolygon(env);

PolygonBuilderEx polygonBuilderEx = new PolygonBuilderEx(env);
polygonBuilderEx.SpatialReference = SpatialReferences.WGS84;
polygonFromEnv = polygonBuilderEx.ToGeometry() as Polygon;

获取多边形的点

1
2
3
4
5
6
7
8
9
10
11
// get the points as a readonly Collection
ReadOnlyPointCollection pts = polygon.Points;

// get an enumeration of the points
IEnumerator<MapPoint> enumPts = polygon.Points.GetEnumerator();

// get the point coordinates as a readonly list of Coordinate2D
IReadOnlyList<Coordinate2D> coordinates = polygon.Copy2DCoordinatesToList();

// get the point coordinates as a readonly list of Coordinate3D
IReadOnlyList<Coordinate3D> coordinates3D = polygon.Copy3DCoordinatesToList();

获取多边形的各个部分

1
2
// get the parts as a readonly collection
ReadOnlyPartCollection parts = polygon.Parts;

枚举多边形的各个部分

1
2
3
4
5
6
7
8
9
10
11
int numSegments = 0;
IEnumerator<ReadOnlySegmentCollection> segments = polygon.Parts.GetEnumerator();
while (segments.MoveNext())
{
ReadOnlySegmentCollection seg = segments.Current;
numSegments += seg.Count;
foreach (Segment s in seg)
{
// do something with the segment
}
}

获取多边形的线段

1
2
3
4
5
6
7
8
List<Segment> segmentList = new List<Segment>(30);
ICollection<Segment> collection = segmentList;
polygon.GetAllSegments(ref collection);
// segmentList.Count = 4
// segmentList.Capacity = 30

// use the segments to build another polygon
Polygon polygonFromSegments = PolygonBuilderEx.CreatePolygon(collection);

构建圆环多边形

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
List<Coordinate2D> outerCoordinates = new List<Coordinate2D>();
outerCoordinates.Add(new Coordinate2D(10.0, 10.0));
outerCoordinates.Add(new Coordinate2D(10.0, 20.0));
outerCoordinates.Add(new Coordinate2D(20.0, 20.0));
outerCoordinates.Add(new Coordinate2D(20.0, 10.0));

// define the inner polygon as anti-clockwise
List<Coordinate2D> innerCoordinates = new List<Coordinate2D>();
innerCoordinates.Add(new Coordinate2D(13.0, 13.0));
innerCoordinates.Add(new Coordinate2D(17.0, 13.0));
innerCoordinates.Add(new Coordinate2D(17.0, 17.0));
innerCoordinates.Add(new Coordinate2D(13.0, 17.0));

PolygonBuilderEx pbEx = new PolygonBuilderEx(outerCoordinates);
Polygon donutEx = pbEx.ToGeometry() as Polygon;
double areaEx = donutEx.Area; // area = 100

pbEx.AddPart(innerCoordinates);
donutEx = pbEx.ToGeometry() as Polygon;

areaEx = donutEx.Area; // area = 84.0

areaEx = GeometryEngine.Instance.Area(donutEx); // area = 84.0

创建 N 侧正多边形

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
// <summary>
// Create an N-sided regular polygon. A regular sided polygon is a polygon that is equiangular (all angles are equal in measure)
// and equilateral (all sides are equal in length). See https://en.wikipedia.org/wiki/Regular_polygon
// </summary>
// <param name="numSides">The number of sides in the polygon.</param>
// <param name="center">The center of the polygon.</param>
// <param name="radius">The distance from the center of the polygon to a vertex.</param>
// <param name="rotation">The rotation angle in radians of the start point of the polygon. The start point will be
// rotated counterclockwise from the positive x-axis.</param>
// <returns>N-sided regular polygon.</returns>
// <exception cref="ArgumentException">Number of sides is less than 3.</exception>
public Polygon CreateRegularPolygon(int numSides, Coordinate2D center, double radius, double rotation)
{
if (numSides < 3)
throw new ArgumentException();

Coordinate2D[] coords = new Coordinate2D[numSides + 1];

double centerX = center.X;
double centerY = center.Y;
double x = radius * Math.Cos(rotation) + centerX;
double y = radius * Math.Sin(rotation) + centerY;
Coordinate2D start = new Coordinate2D(x, y);
coords[0] = start;

double da = 2 * Math.PI / numSides;
for (int i = 1; i < numSides; i++)
{
x = radius * Math.Cos(i * da + rotation) + centerX;
y = radius * Math.Sin(i * da + rotation) + centerY;

coords[i] = new Coordinate2D(x, y);
}

coords[numSides] = start;

return PolygonBuilderEx.CreatePolygon(coords);
}

获取多边形的外环 - 多边形。获取外部环

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
public void GetExteriorRings(Polygon inputPolygon)
{
if (inputPolygon == null || inputPolygon.IsEmpty)
return;

// polygon part count
int partCount = inputPolygon.PartCount;
// polygon exterior ring count
int numExtRings = inputPolygon.ExteriorRingCount;
// get set of exterior rings for the polygon
IList<Polygon> extRings = inputPolygon.GetExteriorRings();

// test each part for "exterior ring"
for (int idx = 0; idx < partCount; idx++)
{
bool isExteriorRing = inputPolygon.IsExteriorRing(idx);
var ring = inputPolygon.GetExteriorRing(idx);
}
}

信封

构造封套

1
2
3
4
5
6
7
8
9
// Use a builderEx convenience method or use a builderEx constructor.

MapPoint minPt = MapPointBuilderEx.CreateMapPoint(1.0, 1.0);
MapPoint maxPt = MapPointBuilderEx.CreateMapPoint(2.0, 2.0);

Envelope envelope = EnvelopeBuilderEx.CreateEnvelope(minPt, maxPt);

EnvelopeBuilderEx builderEx = new EnvelopeBuilderEx(minPt, maxPt);
envelope = builderEx.ToGeometry() as Envelope;

构造信封 - 从 JSON 字符串

1
2
string jsonString = "{ \"xmin\" : 1, \"ymin\" : 2,\"xmax\":3,\"ymax\":4,\"spatialReference\":{\"wkid\":4326}}";
Envelope envFromJson = EnvelopeBuilderEx.FromJson(jsonString);

合并两个信封

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
// use the convenience builders
Envelope env1 = EnvelopeBuilderEx.CreateEnvelope(0, 0, 1, 1, SpatialReferences.WGS84);
Envelope env2 = EnvelopeBuilderEx.CreateEnvelope(0.5, 0.5, 1.5, 1.5, SpatialReferences.WGS84);

Envelope env3 = env1.Union(env2);

double area = env3.Area;
double depth = env3.Depth;
double height = env3.Height;
double width = env3.Width;
double len = env3.Length;

MapPoint centerPt = env3.Center;
Coordinate2D coord = env3.CenterCoordinate;

bool isEmpty = env3.IsEmpty;
int pointCount = env3.PointCount;

// coordinates
//env3.XMin, env3.XMax, env3.YMin, env3.YMax
//env3.ZMin, env3.ZMax, env3.MMin, env3.MMax

bool isEqual = env1.IsEqual(env2); // false


// or use the builderEx constructors = don't need to run on the MCT.
EnvelopeBuilderEx builderEx = new EnvelopeBuilderEx(0, 0, 1, 1, SpatialReferences.WGS84);
builderEx.Union(env2); // builder is updated to the result

depth = builderEx.Depth;
height = builderEx.Height;
width = builderEx.Width;

centerPt = builderEx.Center;
coord = builderEx.CenterCoordinate;

isEmpty = builderEx.IsEmpty;

env3 = builderEx.ToGeometry() as Envelope;

与两个信封相交

1
2
3
4
5
6
7
8
9
10
11
12
13
// use the convenience builders
Envelope env1 = EnvelopeBuilderEx.CreateEnvelope(0, 0, 1, 1, SpatialReferences.WGS84);
Envelope env2 = EnvelopeBuilderEx.CreateEnvelope(0.5, 0.5, 1.5, 1.5, SpatialReferences.WGS84);

bool intersects = env1.Intersects(env2); // true
Envelope env3 = env1.Intersection(env2);


// or use the builderEx constructors = don't need to run on the MCT.
EnvelopeBuilderEx builderEx = new EnvelopeBuilderEx(0, 0, 1, 1, SpatialReferences.WGS84);
intersects = builderEx.Intersects(env2);
builderEx.Intersection(env2); // note this sets the builder to the intersection
env3 = builderEx.ToGeometry() as Envelope;

展开信封

1
2
3
4
5
6
7
8
9
10
11
12
13
// Use a builderEx convenience method or use a builderEx constructor.

// convenience methods don't need to run on the MCT.
Envelope envelope = EnvelopeBuilderEx.CreateEnvelope(100.0, 100.0, 500.0, 500.0);

// shrink the envelope by 50%
Envelope result = envelope.Expand(0.5, 0.5, true);


// builderEx constructors don't need to run on the MCT.
EnvelopeBuilderEx builderEx = new EnvelopeBuilderEx(100.0, 100.0, 500.0, 500.0);
builderEx.Expand(0.5, 0.5, true);
envelope = builderEx.ToGeometry() as Envelope;

更新封套的坐标

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
Coordinate2D minCoord = new Coordinate2D(1, 3);
Coordinate2D maxCoord = new Coordinate2D(2, 4);

Coordinate2D c1 = new Coordinate2D(0, 5);
Coordinate2D c2 = new Coordinate2D(1, 3);


// use the EnvelopeBuilderEx. This constructor doesn't need to run on the MCT.

EnvelopeBuilderEx builderEx = new EnvelopeBuilderEx(minCoord, maxCoord);
// builderEx.XMin, YMin, Zmin, MMin = 1, 3, 0, double.Nan
// builderEx.XMax, YMax, ZMax, MMax = 2, 4, 0, double.Nan

// set XMin. if XMin > XMax; both XMin and XMax change
builderEx.XMin = 6;
// builderEx.XMin, YMin, ZMin, MMin = 6, 3, 0, double.Nan
// builderEx.XMax, YMax, ZMax, MMax = 6, 4, 0, double.Nan

// set XMax
builderEx.XMax = 8;
// builderEx.XMin, YMin, ZMin, MMin = 6, 3, 0, double.Nan
// builderEx.XMax, YMax, ZMax, MMax = 8, 4, 0, double.Nan

// set XMax. if XMax < XMin, both XMin and XMax change
builderEx.XMax = 3;
// builderEx.XMin, YMin, ZMin, MMin = 3, 3, 0, double.Nan
// builderEx.XMax, YMax, ZMax, MMax = 3, 4, 0, double.Nan

// set YMin
builderEx.YMin = 2;
// builderEx.XMin, YMin, ZMin, MMin = 3, 2, 0, double.Nan
// builderEx.XMax, YMax, ZMax, MMax = 3, 4, 0, double.Nan

// set ZMin. if ZMin > ZMax, both ZMin and ZMax change
builderEx.ZMin = 3;
// builderEx.XMin, YMin, ZMin, MMin = 3, 2, 3, double.Nan
// builderEx.XMax, YMax, ZMax, MMax = 3, 4, 3, double.Nan

// set ZMax. if ZMax < ZMin. both ZMin and ZMax change
builderEx.ZMax = -1;
// builderEx.XMin, YMin, ZMin, MMin = 3, 2, -1, double.Nan
// builderEx.XMax, YMax, ZMax, MMax = 3, 4, -1, double.Nan

builderEx.SetZCoords(8, -5);
// builderEx.XMin, YMin, ZMin, MMin = 3, 2, -5, double.Nan
// builderEx.XMax, YMax, ZMax, MMax = 3, 4, 8, double.Nan


builderEx.SetXYCoords(c1, c2);
// builderEx.XMin, YMin, ZMin, MMin = 0, 3, -5, double.Nan
// builderEx.XMax, YMax, ZMax, MMax = 1, 5, 8, double.Nan


builderEx.HasM = true;
builderEx.SetMCoords(2, 5);

var geomEx = builderEx.ToGeometry();

多点

构造多点 - 从映射点的枚举

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
// Use a builderEx convenience method or use a builderEx constructor.

List<MapPoint> list = new List<MapPoint>();
list.Add(MapPointBuilderEx.CreateMapPoint(1.0, 1.0));
list.Add(MapPointBuilderEx.CreateMapPoint(1.0, 2.0));
list.Add(MapPointBuilderEx.CreateMapPoint(2.0, 2.0));
list.Add(MapPointBuilderEx.CreateMapPoint(2.0, 1.0));

// use the builderEx constructors - don't need to run on the MCT.
// use AttributeFlags.NoAttributes - we have 2d points in the list
MultipointBuilderEx builderEx = new MultipointBuilderEx(list, AttributeFlags.None);
Multipoint multiPoint = builderEx.ToGeometry() as Multipoint;
int ptCount = builderEx.PointCount;

// builderEx convenience methods dont need to run on the MCT
multiPoint = MultipointBuilderEx.CreateMultipoint(list);
// multiPoint.HasZ, HasM, HasID will be false - the attributes are determined
// based on the attribute state of the points in the list

// or specifically set the state
multiPoint = MultipointBuilderEx.CreateMultipoint(list, AttributeFlags.None);
// multiPoint.HasM = false

multiPoint = MultipointBuilderEx.CreateMultipoint(list, AttributeFlags.HasM);
// multiPoint.HasM = true

ptCount = multiPoint.PointCount;

构造多点 - 使用 MultipointBuilderEx

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
Coordinate2D[] coordinate2Ds = new Coordinate2D[] { new Coordinate2D(1, 2), new Coordinate2D(-1, -2) };
SpatialReference sr = SpatialReferences.WGS84;

MultipointBuilderEx builder = new MultipointBuilderEx(coordinate2Ds, sr);

// builder.PointCount = 2

builder.HasZ = true;
// builder.Zs.Count = 2
// builder.Zs[0] = 0
// builder.Zs[1] = 0

builder.HasM = true;
// builder.Ms.Count = 2
// builder.Ms[0] = NaN
// builder.Ms[1] = NaN

builder.HasID = true;
// builder.IDs.Count = 2
// builder.IDs[0] = 0
// builder.IDs[1] = 0

// set it empty
builder.SetEmpty();
// builder.Coords.Count = 0
// builder.Zs.Count = 0
// builder.Ms.Count = 0
// builder.IDs.Count = 0


// reset coordinates
List<Coordinate2D> inCoords = new List<Coordinate2D>() { new Coordinate2D(1, 2), new Coordinate2D(3, 4), new Coordinate2D(5, 6) };
builder.Coordinate2Ds = inCoords;
// builder.Coords.Count = 3
// builder.HasZ = true
// builder.HasM = true
// builder.HasID = true

double[] zs = new double[] { 1, 2, 1, 2, 1, 2 };
builder.Zs = zs;
// builder.Zs.Count = 6

double[] ms = new double[] { 0, 1 };
builder.Ms = ms;
// builder.Ms.Count = 2

// coordinates are now (x, y, z, m, id)
// (1, 2, 1, 0, 0), (3, 4, 2, 1, 0) (5, 6, 1, NaN, 0)

MapPoint mapPoint = builder.GetPoint(2);
// mapPoint.HasZ = true
// mapPoint.HasM = true
// mapPoint.HasID = true
// mapPoint.Z = 1
// mapPoint.M = NaN
// mapPoint.ID = 0

// add an M to the list
builder.Ms.Add(2);
// builder.Ms.count = 3

// coordinates are now (x, y, z, m, id)
// (1, 2, 1, 0, 0), (3, 4, 2, 1, 0) (5, 6, 1, 2, 0)

// now get the 2nd point again; it will now have an M value
mapPoint = builder.GetPoint(2);
// mapPoint.M = 2


int[] ids = new int[] { -1, -2, -3 };
// assign ID values
builder.IDs = ids;

// coordinates are now (x, y, z, m, id)
// (1, 2, 1, 0, -1), (3, 4, 2, 1, -2) (5, 6, 1, 2, -3)


// create a new point
MapPoint point = MapPointBuilderEx.CreateMapPoint(-300, 400, 4);
builder.SetPoint(2, point);

// coordinates are now (x, y, z, m, id)
// (1, 2, 1, 0, -1), (3, 4, 2, 1, -2) (-300, 400, 4, NaN, 0)


builder.RemovePoints(1, 3);
// builder.PointCount = 1

修改多点的点

1
2
3
4
5
6
7
8
9
10
11
12
13
14
// assume a multiPoint has been built from 4 points
// the modified multiPoint will have the first point removed and the last point moved

// use the builderEx constructors = don't need to run on the MCT.
MultipointBuilderEx builderEx = new MultipointBuilderEx(multipoint);
// remove the first point
builderEx.RemovePoint(0);
// modify the coordinates of the last point
var ptEx = builderEx.GetPoint(builderEx.PointCount - 1);
builderEx.RemovePoint(builderEx.PointCount - 1);

var newPtEx = MapPointBuilderEx.CreateMapPoint(ptEx.X + 1.0, ptEx.Y + 2.0);
builderEx.AddPoint(newPtEx);
Multipoint modifiedMultiPointEx = builderEx.ToGeometry() as Multipoint;

从多点检索点、2D 坐标、3D 坐标

1
2
3
ReadOnlyPointCollection points = multipoint.Points;
IReadOnlyList<Coordinate2D> coords2d = multipoint.Copy2DCoordinatesToList();
IReadOnlyList<Coordinate3D> coords3d = multipoint.Copy3DCoordinatesToList();

线段

使用两个地图点构造线段

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
// Use a builderEx convenience method or use a builderEx constructor.

MapPoint startPt = MapPointBuilderEx.CreateMapPoint(1.0, 1.0);
MapPoint endPt = MapPointBuilderEx.CreateMapPoint(2.0, 1.0);

// BuilderEx convenience methods don't need to run on the MCT.
LineSegment lineFromMapPoint = LineBuilderEx.CreateLineSegment(startPt, endPt);

// coordinate2D
Coordinate2D start2d = (Coordinate2D)startPt;
Coordinate2D end2d = (Coordinate2D)endPt;

LineSegment lineFromCoordinate2D = LineBuilderEx.CreateLineSegment(start2d, end2d);

// coordinate3D
Coordinate3D start3d = (Coordinate3D)startPt;
Coordinate3D end3d = (Coordinate3D)endPt;

LineSegment lineFromCoordinate3D = LineBuilderEx.CreateLineSegment(start3d, end3d);

// lineSegment
LineSegment anotherLineFromLineSegment = LineBuilderEx.CreateLineSegment(lineFromCoordinate3D);


// builderEx constructors don't need to run on the MCT
LineBuilderEx lbEx = new LineBuilderEx(startPt, endPt);
lineFromMapPoint = lbEx.ToSegment() as LineSegment;

lbEx = new LineBuilderEx(start2d, end2d);
lineFromCoordinate2D = lbEx.ToSegment() as LineSegment;

lbEx = new LineBuilderEx(start3d, end3d);
lineFromCoordinate3D = lbEx.ToSegment() as LineSegment;

lbEx = new LineBuilderEx(startPt, endPt);
lineFromMapPoint = lbEx.ToSegment() as LineSegment;

lbEx = new LineBuilderEx(lineFromCoordinate3D);
anotherLineFromLineSegment = lbEx.ToSegment() as LineSegment;

更改线段坐标

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
// builderEx constructors don't need to run on the MCT
LineBuilderEx lbuilderEx = new LineBuilderEx(lineSegment);
// find the existing coordinates
lbuilderEx.QueryCoords(out startPt, out endPt);

// or use
//startPt = lbuilderEx.StartPoint;
//endPt = lbuilderEx.EndPoint;

// update the coordinates
lbuilderEx.SetCoords(GeometryEngine.Instance.Move(startPt, 10, 10) as MapPoint, GeometryEngine.Instance.Move(endPt, -10, -10) as MapPoint);

// or use
//lbuilderEx.StartPoint = GeometryEngine.Instance.Move(startPt, 10, 10) as MapPoint;
//lbuilderEx.EndPoint = GeometryEngine.Instance.Move(endPt, -10, -10) as MapPoint;

LineSegment segment2 = lbuilderEx.ToSegment() as LineSegment;

立方贝塞尔

构建三次方贝塞尔 - 从坐标

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
// Use a builderEx convenience method or a builderEx constructor.

MapPoint startPt = MapPointBuilderEx.CreateMapPoint(1.0, 1.0, 3.0);
MapPoint endPt = MapPointBuilderEx.CreateMapPoint(2.0, 2.0, 3.0);

Coordinate2D ctrl1Pt = new Coordinate2D(1.0, 2.0);
Coordinate2D ctrl2Pt = new Coordinate2D(2.0, 1.0);

// BuilderEx convenience methods don't need to run on the MCT
CubicBezierSegment bezier = CubicBezierBuilderEx.CreateCubicBezierSegment(startPt, ctrl1Pt, ctrl2Pt, endPt, SpatialReferences.WGS84);

// without a SR
bezier = CubicBezierBuilderEx.CreateCubicBezierSegment(startPt, ctrl1Pt, ctrl2Pt, endPt);


// builderEx constructors dont need to run on the MCT
CubicBezierBuilderEx cbbEx = new CubicBezierBuilderEx(startPt, ctrl1Pt, ctrl2Pt, endPt);
bezier = cbbEx.ToSegment() as CubicBezierSegment;

// another alternative
cbbEx = new CubicBezierBuilderEx(startPt, ctrl1Pt.ToMapPoint(), ctrl2Pt.ToMapPoint(), endPt);
bezier = cbbEx.ToSegment() as CubicBezierSegment;

构建立方贝塞尔 - 从地图点

1
2
3
4
5
6
7
8
9
10
11
12
13
14
// Use a builderEx convenience method or a builderEx constructor.

MapPoint startPt = MapPointBuilderEx.CreateMapPoint(1.0, 1.0, SpatialReferences.WGS84);
MapPoint endPt = MapPointBuilderEx.CreateMapPoint(2.0, 2.0, SpatialReferences.WGS84);

MapPoint ctrl1Pt = MapPointBuilderEx.CreateMapPoint(1.0, 2.0, SpatialReferences.WGS84);
MapPoint ctrl2Pt = MapPointBuilderEx.CreateMapPoint(2.0, 1.0, SpatialReferences.WGS84);

// BuilderEx convenience methods don't need to run on the MCT
CubicBezierSegment bezier = CubicBezierBuilderEx.CreateCubicBezierSegment(startPt, ctrl1Pt, ctrl2Pt, endPt);

// builderEx constructors dont need to run on the MCT
CubicBezierBuilderEx cbbEx = new CubicBezierBuilderEx(startPt, ctrl1Pt, ctrl2Pt, endPt);
bezier = cbbEx.ToSegment() as CubicBezierSegment;

构造三次贝塞尔 - 从映射点的枚举

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
// Use a buildeExr convenience method or use a builderEx constructor.

MapPoint startPt = MapPointBuilderEx.CreateMapPoint(1.0, 1.0, SpatialReferences.WGS84);
MapPoint endPt = MapPointBuilderEx.CreateMapPoint(2.0, 2.0, SpatialReferences.WGS84);

MapPoint ctrl1Pt = MapPointBuilderEx.CreateMapPoint(1.0, 2.0, SpatialReferences.WGS84);
MapPoint ctrl2Pt = MapPointBuilderEx.CreateMapPoint(2.0, 1.0, SpatialReferences.WGS84);

List<MapPoint> listMapPoints = new List<MapPoint>();
listMapPoints.Add(startPt);
listMapPoints.Add(ctrl1Pt);
listMapPoints.Add(ctrl2Pt);
listMapPoints.Add(endPt);

// BuilderEx convenience methods don't need to run on the MCT
CubicBezierSegment bezier = CubicBezierBuilderEx.CreateCubicBezierSegment(listMapPoints);

// builderEx constructors dont need to run on the MCT
CubicBezierBuilderEx cbbEx = new CubicBezierBuilderEx(listMapPoints);
bezier = cbbEx.ToSegment() as CubicBezierSegment;

立方贝塞尔生成器属性

1
2
3
4
5
6
7
8
9
10
// retrieve the bezier curve's control points

CubicBezierBuilderEx cbbEx = new CubicBezierBuilderEx(bezierSegment);
MapPoint startPtEx = cbbEx.StartPoint;
Coordinate2D ctrlPt1Ex = cbbEx.ControlPoint1;
Coordinate2D ctrlPt2Ex = cbbEx.ControlPoint2;
MapPoint endPtEx = cbbEx.EndPoint;

// or use the QueryCoords method
cbbEx.QueryCoords(out startPtEx, out ctrlPt1Ex, out ctrlPt2Ex, out endPtEx);

立方贝塞尔属性

1
2
3
4
5
6
7
8
9
// retrieve the bezier curve's control points
CubicBezierSegment cb = CubicBezierBuilderEx.CreateCubicBezierSegment(bezierSegment);
MapPoint startPt = cb.StartPoint;
Coordinate2D ctrlPt1 = cb.ControlPoint1;
Coordinate2D ctrlPt2 = cb.ControlPoint2;
MapPoint endPt = cb.EndPoint;

bool isCurve = cb.IsCurve;
double len = cb.Length;

构造折线 - 从三次贝塞尔

1
Polyline polyline = PolylineBuilderEx.CreatePolyline(bezierSegment);

构造圆弧 - 使用内部点

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// Construct a circular arc from (2, 1) to (1, 2) with interior pt (1 + sqrt(2)/2, 1 + sqrt(2)/2).
// Use a builderEx convenience method or use a builderEx constructor.

MapPoint fromPt = MapPointBuilderEx.CreateMapPoint(2, 1);
MapPoint toPt = MapPointBuilderEx.CreateMapPoint(1, 2);
Coordinate2D interiorPt = new Coordinate2D(1 + Math.Sqrt(2) / 2, 1 + Math.Sqrt(2) / 2);

// BuilderEx convenience methods don't need to run on the MCT.
EllipticArcSegment circularArc = EllipticArcBuilderEx.CreateCircularArc(fromPt, toPt, interiorPt);

// BuilderEx constructors dont need to run on the MCT.
EllipticArcBuilderEx eab = new EllipticArcBuilderEx(fromPt, toPt, interiorPt);
// do something with the builder

EllipticArcSegment anotherCircularArc = eab.ToSegment();

构造圆弧 - 使用弦长度和方位

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
// Construct a circular arc counterclockwise from (2, 1) to (1, 2) such that the embedded 
// circle has center point at (1, 1) and radius = 1.
// Use a builderEx convenience method or use a builderEx constructor.

MapPoint fromPt = MapPointBuilderEx.CreateMapPoint(2, 1, SpatialReferences.WGS84);
double chordLength = Math.Sqrt(2);
double chordBearing = 3 * Math.PI / 4;
double radius = 1;
ArcOrientation orientation = ArcOrientation.ArcCounterClockwise;
MinorOrMajor minorOrMajor = MinorOrMajor.Minor;

// BuildeExr convenience methods don't need to run on the MCT.
EllipticArcSegment circularArc = EllipticArcBuilderEx.CreateCircularArc(fromPt, chordLength, chordBearing, radius, orientation, minorOrMajor);

// BuilderEx constructors need to run on the MCT.
EllipticArcBuilderEx cab = new EllipticArcBuilderEx(fromPt, chordLength, chordBearing, radius, orientation, minorOrMajor);
// do something with the builder

EllipticArcSegment anotherCircularArc = cab.ToSegment();

构建圆弧 - 使用中心点、角度和半径

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// Construct a circular arc with center point at (0, 0), from angle = 0, 
// central angle = pi/2, radius = 1.
// Use a builderEx convenience method or use a builderEx constructor.

SpatialReference sr4326 = SpatialReferences.WGS84;
Coordinate2D centerPt = new Coordinate2D(0, 0);
double fromAngle = 0;
double centralAngle = Math.PI / 2;
double radius = 1;

// BuilderEx convenience methods don't need to run on the MCT.
EllipticArcSegment circularArc = EllipticArcBuilderEx.CreateCircularArc(fromAngle, centralAngle, centerPt, radius, sr4326);

// BuilderEx constructors dont need to run on the MCT.
EllipticArcBuilderEx cab = new EllipticArcBuilderEx(fromAngle, centralAngle, centerPt, radius, sr4326);
EllipticArcSegment otherCircularArc = cab.ToSegment();

构造椭圆弧 - 使用中心点和旋转角度

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
// Construct an elliptic arc centered at (1,1), startAngle = 0, centralAngle = PI/2, 
// rotationAngle = 0, semiMajorAxis = 1, minorMajorRatio = 0.5.
// Use a builderEx convenience method or use a builderEx constructor.

Coordinate2D centerPt = new Coordinate2D(1, 1);

// BuilderEx convenience methods don't need to run on the MCT.
EllipticArcSegment circularArc = EllipticArcBuilderEx.CreateEllipticArcSegment(centerPt, 0, Math.PI / 2, 0, 1, 0.5);

double semiMajor;
double semiMinor;
circularArc.GetAxes(out semiMajor, out semiMinor);
// semiMajor = 1, semiMinor = 0.5

// BuilderEx constructors dont need to run on the MCT.
EllipticArcBuilderEx cab = new EllipticArcBuilderEx(centerPt, 0, Math.PI / 2, 0, 1, 0.5);
cab.GetAxes(out semiMajor, out semiMinor);
EllipticArcSegment otherCircularArc = cab.ToSegment();

构造圆弧 - 使用中心点和方向

1
2
3
4
5
6
7
8
9
10
11
12
13
14
// Construct a circular arc from (2, 1) to (1, 2) 
// with center point at (1, 1) and orientation counterclockwise.
// Use a builderEx convenience method or use a builderEx constructor.

MapPoint toPt = MapPointBuilderEx.CreateMapPoint(1, 2);
MapPoint fromPt = MapPointBuilderEx.CreateMapPoint(2, 1);
Coordinate2D centerPtCoord = new Coordinate2D(1, 1);

// BuilderEx convenience methods don't need to run on the MCT.
EllipticArcSegment circularArc = EllipticArcBuilderEx.CreateCircularArc(fromPt, toPt, centerPtCoord, ArcOrientation.ArcCounterClockwise);

// BuilderEx constructors need to run on the MCT.
EllipticArcBuilderEx cab = new EllipticArcBuilderEx(fromPt, toPt, centerPtCoord, ArcOrientation.ArcCounterClockwise);
EllipticArcSegment otherCircularArc = cab.ToSegment();

构造圆弧 - 使用两个线段和半径

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
// Construct a segment from (100, 100) to (50, 50) and another segment from (100, 100) to (150, 50).
// Use a builderEx convenience method or use a builderEx constructor.

LineSegment segment1 = LineBuilderEx.CreateLineSegment(new Coordinate2D(100, 100), new Coordinate2D(50, 50));
LineSegment segment2 = LineBuilderEx.CreateLineSegment(new Coordinate2D(100, 100), new Coordinate2D(150, 50));

// Construct the hint point to determine where the arc will be constructed.
Coordinate2D hintPoint = new Coordinate2D(100, 75);

// Call QueryFilletRadius to get the minimum and maximum radii that can be used with these segments.
var minMaxRadii = EllipticArcBuilderEx.QueryFilletRadiusRange(segment1, segment2, hintPoint);

// Use the maximum radius to create the arc.
double maxRadius = minMaxRadii.Item2;

// BuilderEx convenience methods don't need to run on the MCT.
//At 2.x - EllipticArcSegment circularArc = EllipticArcBuilderEx.CreateEllipticArcSegment(segment1, segment2, maxRadius, hintPoint);
EllipticArcSegment circularArc = EllipticArcBuilderEx.CreateCircularArc(
segment1, segment2, maxRadius, hintPoint);

// BuilderEx constructors need to run on the MCT.
EllipticArcBuilderEx cab = new EllipticArcBuilderEx(segment1, segment2, maxRadius, hintPoint);
EllipticArcSegment otherCircularArc = cab.ToSegment();

构造一个圆

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
// Construct a circle with center at (-1,-1), radius = 2, and oriented clockwise.
// Use a builderEx convenience method or use a builderEx constructor.

Coordinate2D centerPtCoord = new Coordinate2D(-1, -1);

// Builder convenience methods don't need to run on the MCT.
EllipticArcSegment circle = EllipticArcBuilderEx.CreateCircle(centerPtCoord, 2, ArcOrientation.ArcClockwise);
// circle.IsCircular = true
// circle.IsCounterClockwise = false
// circle.IsMinor = false

double startAngle, rotationAngle, centralAngle, semiMajor, semiMinor;
Coordinate2D actualCenterPt;
circle.QueryCoords(out actualCenterPt, out startAngle, out centralAngle, out rotationAngle, out semiMajor, out semiMinor);

// semiMajor = 2.0
// semiMinor = 2.0
// startAngle = PI/2
// centralAngle = -2*PI
// rotationAngle = 0
// endAngle = PI/2

// BuilderEx constructors need to run on the MCT.
EllipticArcBuilderEx builder = new EllipticArcBuilderEx(centerPtCoord, 2, ArcOrientation.ArcClockwise);
EllipticArcSegment otherCircle = builder.ToSegment();

构造椭圆

1
2
3
4
5
6
7
8
9
10
11
12
// Construct an ellipse centered at (1, 2) with rotationAngle = -pi/6,  
// semiMajorAxis = 5, minorMajorRatio = 0.2, oriented clockwise.
// Use a builderEx convenience method or use a builderEx constructor.

Coordinate2D centerPt = new Coordinate2D(1, 2);

// BuilderEx convenience methods don't need to run on the MCT.
EllipticArcSegment ellipse = EllipticArcBuilderEx.CreateEllipse(centerPt, -1 * Math.PI / 6, 5, 0.2, ArcOrientation.ArcClockwise);

// BuilderEx constructors need to run on the MCT.
EllipticArcBuilderEx builder = new EllipticArcBuilderEx(centerPt, -1 * Math.PI / 6, 5, 0.2, ArcOrientation.ArcClockwise);
EllipticArcSegment anotherEllipse = builder.ToSegment();

Elliptic Arc Builder Properties

1
2
3
4
5
6
7
8
9
10
11
12
// retrieve the curve's properties
EllipticArcBuilderEx builder = new EllipticArcBuilderEx(arcSegment);
MapPoint startPt = builder.StartPoint;
MapPoint endPt = builder.EndPoint;
Coordinate2D centerPt = builder.CenterPoint;
bool isCircular = builder.IsCircular;
bool isMinor = builder.IsMinor;
double startAngle = builder.StartAngle;
double endAngle = builder.EndAngle;
double centralAngle = builder.CentralAngle;
double rotationAngle = builder.RotationAngle;
ArcOrientation orientation = builder.Orientation;

椭圆弧属性

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
// retrieve the curve's control points
EllipticArcSegment arc = EllipticArcBuilderEx.CreateEllipticArcSegment(arcSegment);
MapPoint startPt = arc.StartPoint;
MapPoint endPt = arc.EndPoint;
Coordinate2D centerPt = arc.CenterPoint;
bool isCircular = arc.IsCircular;
bool isMinor = arc.IsMinor;
bool isCounterClockwise = arc.IsCounterClockwise;
bool isCurve = arc.IsCurve;
double len = arc.Length;
double ratio = arc.MinorMajorRatio;

double semiMajorAxis, semiMinorAxis;
// get the axes
arc.GetAxes(out semiMajorAxis, out semiMinorAxis);
// or use the properties
// semiMajorAxis = arc.SemiMajorAxis;
// semiMinorAxis = arc.SemiMinorAxis;

double startAngle, centralAngle, rotationAngle;
// or use QueryCoords to get complete information
arc.QueryCoords(out centerPt, out startAngle, out centralAngle, out rotationAngle, out semiMajorAxis, out semiMinorAxis);

// use properties to get angle information
//double endAngle = arc.EndAngle;
//centralAngle = arc.CentralAngle;
//rotationAngle = arc.RotationAngle;
//startAngle = arc.StartAngle;

几何袋

构造几何包

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
MapPoint point = MapPointBuilderEx.CreateMapPoint(1, 2, SpatialReferences.WebMercator);

List<Coordinate2D> coords2D = new List<Coordinate2D>()
{
new Coordinate2D(0, 0),
new Coordinate2D(0, 1),
new Coordinate2D(1, 1),
new Coordinate2D(1, 0)
};

Multipoint multipoint = MultipointBuilderEx.CreateMultipoint(coords2D, SpatialReferences.WGS84);
Polyline polyline = PolylineBuilderEx.CreatePolyline(coords2D, SpatialReferences.WebMercator);

GeometryBagBuilderEx builder = new GeometryBagBuilderEx(SpatialReferences.WGS84);

GeometryBag emptyBag = builder.ToGeometry();
// emptyBag.IsEmpty = true

builder.AddGeometry(point);
// builder.GeometryCount = 1

GeometryBag geometryBag = builder.ToGeometry();
// geometryBag.PartCount = 1
// geometryBag.PointCount = 1
// geometryBag.IsEmpty = false

IReadOnlyList<Geometry> geometries = geometryBag.Geometries;
// geometries.Count = 1
// geometries[0] is MapPoint with a sr of WGS84

bool isEqual = geometryBag.IsEqual(emptyBag); // isEqual = false

builder.InsertGeometry(0, multipoint);
geometryBag = builder.ToGeometry();
// geometryBag.PartCount = 2

geometries = geometryBag.Geometries;
// geometries.Count = 2
// geometries[0] is Multipoint
// geometries[1] is MapPoint

builder.AddGeometry(polyline);
builder.RemoveGeometry(1);
geometryBag = builder.ToGeometry();
// geometryBag.PartCount = 2

geometries = geometryBag.Geometries;
// geometries.Count = 2
// geometries[0] is Multipoint
// geometries[1] is Polyline

构造几何包 - 从几何枚举

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
// Use a builder convenience method or use a builder constructor.

MapPoint point = MapPointBuilderEx.CreateMapPoint(10, 20);
List<Coordinate2D> coords = new List<Coordinate2D>() { new Coordinate2D(50, 60), new Coordinate2D(-120, -70), new Coordinate2D(40, 60) };
Multipoint multipoint = MultipointBuilderEx.CreateMultipoint(coords, SpatialReferences.WebMercator);
Polyline polyline = PolylineBuilderEx.CreatePolyline(coords);

string json = "{\"rings\":[[[0,0],[0,1],[1,1],[1,0],[0,0]],[[3,0],[3,1],[4,1],[4,0],[3,0]]]}";
Polygon polygon = PolygonBuilderEx.FromJson(json);

var geometries = new List<Geometry>() { point, multipoint, polyline, polygon };

// Builder convenience methods don't need to run on the MCT.
//At 2.x - GeometryBag bag = GeometryBagBuilder.CreateGeometryBag(geometries, SpatialReferences.WGS84);
var bag = GeometryBagBuilderEx.CreateGeometryBag(geometries, SpatialReferences.WGS84);

//At 2.x - using (var builder = new GeometryBagBuilder(geometries, SpatialReferences.WGS84))
var builder = new GeometryBagBuilderEx(geometries, SpatialReferences.WGS84);
// do something with the builder
bag = builder.ToGeometry();

ConstructingGeometryBag - 来自 JSON、Xml

1
2
3
4
5
6
7
const string jsonString = "{\"geometries\":[{\"x\":1,\"y\":2},{\"rings\":[[[0,0],[0,4],[3,4],[3,0],[0,0]]]}],\"spatialReference\":{\"wkid\":4326,\"latestWkid\":4326}}";
//At 2.x - GeometryBag geometryBag = GeometryBagBuilder.FromJson(jsonString);
var geometryBag = GeometryBagBuilderEx.FromJson(jsonString);

string xml = geometryBag.ToXml();
//At 2.x - GeometryBag xmlString = GeometryBagBuilder.FromXML(xml);
var xmlString = GeometryBagBuilderEx.FromXml(xml);

构造几何包 - 添加或插入几何枚举

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
MapPoint point = MapPointBuilderEx.CreateMapPoint(10, 20);
List<Coordinate2D> coords = new List<Coordinate2D>() { new Coordinate2D(50, 60), new Coordinate2D(-120, -70), new Coordinate2D(40, 60) };
Multipoint multipoint = MultipointBuilderEx.CreateMultipoint(coords, SpatialReferences.WebMercator);
Polyline polyline = PolylineBuilderEx.CreatePolyline(coords);

string json = "{\"rings\":[[[0,0],[0,1],[1,1],[1,0],[0,0]],[[3,0],[3,1],[4,1],[4,0],[3,0]]]}";
Polygon polygon = PolygonBuilderEx.FromJson(json);

var geometries = new List<Geometry>() { point, multipoint, polyline, polygon };

//At 2.x - using (var builder = new GeometryBagBuilder(SpatialReferences.WGS84))
var builder = new GeometryBagBuilderEx(SpatialReferences.WGS84);
builder.AddGeometries(geometries);

GeometryBag geomBag = builder.ToGeometry();
// geomBag.PartCount == 4 (point, multipoint, polyline, polygon)

geometries = new List<Geometry>() { point, polyline };
builder.InsertGeometries(1, geometries);
// builder.GeometryCount == 6
geomBag = builder.ToGeometry();
// geomBag.PartCount == 6 (point, point, polyline, multipoint, polyline, polygon)

多面体

通过拉伸多边形或折线构建多面体

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
// build a polygon
string json = "{\"hasZ\":true,\"rings\":[[[0,0,0],[0,1,0],[1,1,0],[1,0,0],[0,0,0]]],\"spatialReference\":{\"wkid\":4326}}";
Polygon polygon = PolygonBuilderEx.FromJson(json);

// extrude the polygon by an offset to create a multipatch
Multipatch multipatch = GeometryEngine.Instance.ConstructMultipatchExtrude(polygon, 2);

// a different polygon
json = "{\"hasZ\":true,\"rings\":[[[0,0,1],[0,1,2],[1,1,3],[1,0,4],[0,0,1]]],\"spatialReference\":{\"wkid\":4326}}";
polygon = PolygonBuilderEx.FromJson(json);

// extrude between z values to create a multipatch
multipatch = GeometryEngine.Instance.ConstructMultipatchExtrudeFromToZ(polygon, -10, 20);

// extrude along the axis defined by the coordinate to create a multipatch
Coordinate3D coord = new Coordinate3D(10, 18, -10);
multipatch = GeometryEngine.Instance.ConstructMultipatchExtrudeAlongVector3D(polygon, coord);

// build a polyline
json = "{\"hasZ\":true,\"paths\":[[[400,800,1000],[800,1400,1500],[1200,800,2000],[1800,1800,2500],[2200,800,3000]]],\"spatialReference\":{\"wkid\":3857}}";
Polyline polyline = PolylineBuilderEx.FromJson(json);

// extrude to a specific z value to create a multipatch
multipatch = GeometryEngine.Instance.ConstructMultipatchExtrudeToZ(polyline, 500);

Coordinate3D fromCoord = new Coordinate3D(50, 50, -500);
Coordinate3D toCoord = new Coordinate3D(200, 50, 1000);

// extrude between two coordinates to create a multipatch
multipatch = GeometryEngine.Instance.ConstructMultipatchExtrudeAlongLine(polyline, fromCoord, toCoord);

多面体属性

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
// standard geometry properties
bool hasZ = multipatch.HasZ;
bool hasM = multipatch.HasM;
bool hasID = multipatch.HasID;
bool isEmpty = multipatch.IsEmpty;
var sr = multipatch.SpatialReference;

// number of patches (parts)
int patchCount = multiPatch.PartCount;
// number of points
int pointCount = multiPatch.PointCount;

// retrieve the points as MapPoints
ReadOnlyPointCollection points = multipatch.Points;
// or as 3D Coordinates
IReadOnlyList<Coordinate3D> coordinates = multipatch.Copy3DCoordinatesToList();


// multipatch materials
bool hasMaterials = multiPatch.HasMaterials;
int materialCount = multiPatch.MaterialCount;


// multipatch textures
bool hasTextures = multiPatch.HasTextures;
int textureVertexCount = multiPatch.TextureVertexCount;

// normals
bool hasNormals = multiPatch.HasNormals;


// properties for an individual patch (if multipatch.PartCount > 0)
int patchPriority = multiPatch.GetPatchPriority(patchIndex);
PatchType patchType = multiPatch.GetPatchType(patchIndex);

// patch points
int patchPointCount = multiPatch.GetPatchPointCount(patchIndex);
int pointStartIndex = multiPatch.GetPatchStartPointIndex(patchIndex);
// the patch Points are then the points in multipatch.Points from pointStartIndex to pointStartIndex + patchPointCount

// if the multipatch has materials
if (hasMaterials)
{
// does the patch have a material?
// materialIndex = -1 if the patch does not have a material;
// 0 <= materialIndex < materialCount if the patch does have materials
int materialIndex = multipatch.GetPatchMaterialIndex(patchIndex);


// properties for an individual material (if multipatch.MaterialCount > 0)
var color = multipatch.GetMaterialColor(materialIndex);
var edgeColor = multipatch.GetMaterialEdgeColor(materialIndex);
var edgeWidth = multipatch.GetMaterialEdgeWidth(materialIndex);
var shiness = multipatch.GetMaterialShininess(materialIndex);
var percent = multipatch.GetMaterialTransparencyPercent(materialIndex);
var cullBackFace = multipatch.IsMaterialCullBackFace(materialIndex);

// texture properties
bool isTextured = multipatch.IsMaterialTextured(materialIndex);
if (isTextured)
{
int columnCount = multipatch.GetMaterialTextureColumnCount(materialIndex);
int rowCount = multipatch.GetMaterialTextureRowCount(materialIndex);
int bpp = multipatch.GetMaterialTextureBytesPerPixel(materialIndex);
TextureCompressionType compressionType = multipatch.GetMaterialTextureCompressionType(materialIndex);
var texture = multipatch.GetMaterialTexture(materialIndex);
}
}

// texture coordinates (if multipatch.HasTextures = true)
if (hasTextures)
{
int numPatchTexturePoints = multiPatch.GetPatchTextureVertexCount(patchIndex);
var coordinate2D = multiPatch.GetPatchTextureCoordinate(patchIndex, 0);

ICollection<Coordinate2D> textureCoordinates = new List<Coordinate2D>(numPatchTexturePoints);
multiPatch.GetPatchTextureCoordinates(patchIndex, ref textureCoordinates);
}


// patch normals (if multipatch.HasNormals = true)
if (hasNormals)
{
// number of normal coordinates = multipatch.GetPatchPointCount(patchIndex)
Coordinate3D patchNormal = multipatch.GetPatchNormal(patchIndex, 0);
ICollection<Coordinate3D> normalCoordinates = new List<Coordinate3D>(patchPointCount);
multipatch.GetPatchNormals(patchIndex, ref normalCoordinates);
}

构建多面体

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// export to binary xml
string binaryXml = multiPatch.ToBinaryXml();

// import from binaryXML - methods need to run on the MCT
Multipatch binaryMultipatch = MultipatchBuilderEx.FromBinaryXml(binaryXml);

// xml export / import
string xml = multiPatch.ToXml();
Multipatch xmlMultipatch = MultipatchBuilderEx.FromXml(xml);

// esriShape export/import
byte[] buffer = multiPatch.ToEsriShape();
Multipatch esriPatch = MultipatchBuilderEx.FromEsriShape(buffer);

// or use GeometryEngine
Multipatch patchImport = GeometryEngine.Instance.ImportFromEsriShape(EsriShapeImportFlags.EsriShapeImportDefaults, buffer, multiPatch.SpatialReference) as Multipatch;

通过MultipatchBuilderEx构建多面体

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
var coords_face1 = new List<Coordinate3D>()
{
new Coordinate3D(12.495461061000071,41.902603910000039,62.552700000000186),
new Coordinate3D(12.495461061000071,41.902603910000039,59.504700000004959),
new Coordinate3D(12.495461061000071,41.902576344000067,59.504700000004959),
new Coordinate3D(12.495461061000071,41.902603910000039,62.552700000000186),
new Coordinate3D(12.495461061000071,41.902576344000067,59.504700000004959),
new Coordinate3D(12.495461061000071,41.902576344000067,62.552700000000186),
};

var coords_face2 = new List<Coordinate3D>()
{
new Coordinate3D(12.495461061000071, 41.902576344000067, 62.552700000000186),
new Coordinate3D(12.495461061000071, 41.902576344000067, 59.504700000004959),
new Coordinate3D(12.495488442000067, 41.902576344000067, 59.504700000004959),
new Coordinate3D(12.495461061000071, 41.902576344000067, 62.552700000000186),
new Coordinate3D(12.495488442000067, 41.902576344000067, 59.504700000004959),
new Coordinate3D(12.495488442000067, 41.902576344000067, 62.552700000000186),
};

var coords_face3 = new List<Coordinate3D>()
{
new Coordinate3D(12.495488442000067, 41.902576344000067, 62.552700000000186),
new Coordinate3D(12.495488442000067, 41.902576344000067, 59.504700000004959),
new Coordinate3D(12.495488442000067, 41.902603910000039, 59.504700000004959),
new Coordinate3D(12.495488442000067, 41.902576344000067, 62.552700000000186),
new Coordinate3D(12.495488442000067, 41.902603910000039, 59.504700000004959),
new Coordinate3D(12.495488442000067, 41.902603910000039, 62.552700000000186),
};

var coords_face4 = new List<Coordinate3D>()
{
new Coordinate3D(12.495488442000067, 41.902576344000067, 59.504700000004959),
new Coordinate3D(12.495461061000071, 41.902576344000067, 59.504700000004959),
new Coordinate3D(12.495461061000071, 41.902603910000039, 59.504700000004959),
new Coordinate3D(12.495488442000067, 41.902576344000067, 59.504700000004959),
new Coordinate3D(12.495461061000071, 41.902603910000039, 59.504700000004959),
new Coordinate3D(12.495488442000067, 41.902603910000039, 59.504700000004959),
};

var coords_face5 = new List<Coordinate3D>()
{
new Coordinate3D(12.495488442000067, 41.902603910000039, 59.504700000004959),
new Coordinate3D(12.495461061000071, 41.902603910000039, 59.504700000004959),
new Coordinate3D(12.495461061000071, 41.902603910000039, 62.552700000000186),
new Coordinate3D(12.495488442000067, 41.902603910000039, 59.504700000004959),
new Coordinate3D(12.495461061000071, 41.902603910000039, 62.552700000000186),
new Coordinate3D(12.495488442000067, 41.902603910000039, 62.552700000000186),
};

var coords_face6 = new List<Coordinate3D>()
{
new Coordinate3D(12.495488442000067, 41.902603910000039, 62.552700000000186),
new Coordinate3D(12.495461061000071, 41.902603910000039, 62.552700000000186),
new Coordinate3D(12.495461061000071, 41.902576344000067, 62.552700000000186),
new Coordinate3D(12.495488442000067, 41.902603910000039, 62.552700000000186),
new Coordinate3D(12.495461061000071, 41.902576344000067, 62.552700000000186),
new Coordinate3D(12.495488442000067, 41.902576344000067, 62.552700000000186),
};

// materials
var materialRed = new BasicMaterial();
materialRed.Color = System.Windows.Media.Colors.Red;

var materialTransparent = new BasicMaterial();
materialTransparent.Color = System.Windows.Media.Colors.White;
materialTransparent.TransparencyPercent = 80;

var blueTransparent = new BasicMaterial(materialTransparent);
blueTransparent.Color = System.Windows.Media.Colors.SkyBlue;

// create a list of patch objects
var patches = new List<Patch>();

// create the multipatchBuilderEx object
var mpb = new ArcGIS.Core.Geometry.MultipatchBuilderEx();

// make each patch using the appropriate coordinates and add to the patch list
var patch = mpb.MakePatch(PatchType.Triangles);
patch.Coords = coords_face1;
patches.Add(patch);

patch = mpb.MakePatch(PatchType.Triangles);
patch.Coords = coords_face2;
patches.Add(patch);

patch = mpb.MakePatch(PatchType.Triangles);
patch.Coords = coords_face3;
patches.Add(patch);

patch = mpb.MakePatch(PatchType.Triangles);
patch.Coords = coords_face4;
patches.Add(patch);

patch = mpb.MakePatch(PatchType.Triangles);
patch.Coords = coords_face5;
patches.Add(patch);

patch = mpb.MakePatch(PatchType.Triangles);
patch.Coords = coords_face6;
patches.Add(patch);

patches[0].Material = materialRed;
patches[1].Material = materialTransparent;
patches[2].Material = materialRed;
patches[3].Material = materialRed;
patches[4].Material = materialRed;
patches[5].Material = blueTransparent;

// assign the patches to the multipatchBuilder
mpb.Patches = patches;

// check which patches currently contain the material
var red = mpb.QueryPatchIndicesWithMaterial(materialRed);
// red should be [0, 2, 3, 4]


// call ToGeometry to get the multipatch
multipatch = mpb.ToGeometry() as Multipatch;

从另一个多面体构建多面体

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
// create the multipatchBuilderEx object
var builder = new ArcGIS.Core.Geometry.MultipatchBuilderEx(multipatch);

// check some properties
bool hasM = builder.HasM;
bool hasZ = builder.HasZ;
bool hasID = builder.HasID;
bool isEmpty = builder.IsEmpty;
bool hasNormals = builder.HasNormals;

var patches = builder.Patches;
int patchCount = patches.Count;

// if there's some patches
if (patchCount > 0)
{
int pointCount = builder.GetPatchPointCount(0);

// replace the first point in the first patch
if (pointCount > 0)
{
// get the first point
var pt = builder.GetPoint(0, 0);
builder.SetPoint(0, 0, newPoint);
}

// check which patches currently contain the texture
var texture = builder.QueryPatchIndicesWithTexture(brickTextureResource);

// assign a texture material
patches[0].Material = brickMaterialTexture;
}

// update the builder for M awareness
builder.HasM = true;
// synchronize the patch attributes to match the builder attributes
// in this instance because we just set HasM to true on the builder, each patch will now get a default M value for it's set of coordinates
builder.SynchronizeAttributeAwareness();

// call ToGeometry to get the multipatch
multipatch = builder.ToGeometry() as Multipatch;

// multipatch.HasM will be true

从 3D 模型文件构建多面体

1
2
3
4
5
6
7
8
9
10
11
12
13
try
{
var model = ArcGIS.Core.Geometry.MultipatchBuilderEx.From3DModelFile(@"c:\Temp\My3dModelFile.dae");
bool modelIsEmpty = model.IsEmpty;
}
catch (FileNotFoundException)
{
// file not found
}
catch (ArgumentException)
{
// File extension is unsupported or cannot read the file
}

构建 3D 特殊多面体形状

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
var sr = MapView.Active.Map.SpatialReference;

var extent = MapView.Active.Extent;
var center = extent.Center;
var centerZ = MapPointBuilderEx.CreateMapPoint(center.X, center.Y, 500, sr);

// cube
multipatch = ArcGIS.Core.Geometry.MultipatchBuilderEx.CreateMultipatch(MultipatchConstructType.Cube, centerZ, 200, sr);
// tetrahedron
multipatch = ArcGIS.Core.Geometry.MultipatchBuilderEx.CreateMultipatch(MultipatchConstructType.Tetrahedron, centerZ, 200, sr);
// diamond
multipatch = ArcGIS.Core.Geometry.MultipatchBuilderEx.CreateMultipatch(MultipatchConstructType.Diamond, centerZ, 200, sr);
// hexagon
multipatch = ArcGIS.Core.Geometry.MultipatchBuilderEx.CreateMultipatch(MultipatchConstructType.Hexagon, centerZ, 200, sr);

// sphere frame
multipatch = ArcGIS.Core.Geometry.MultipatchBuilderEx.CreateMultipatch(MultipatchConstructType.SphereFrame, centerZ, 200, 0.8, sr);
// sphere
multipatch = ArcGIS.Core.Geometry.MultipatchBuilderEx.CreateMultipatch(MultipatchConstructType.Sphere, centerZ, 200, 0.8, sr);
// cylinder
multipatch = ArcGIS.Core.Geometry.MultipatchBuilderEx.CreateMultipatch(MultipatchConstructType.Cylinder, centerZ, 200, 0.8, sr);
// cone
multipatch = ArcGIS.Core.Geometry.MultipatchBuilderEx.CreateMultipatch(MultipatchConstructType.Cone, centerZ, 200, 0.8, sr);


// use the builder to add materials or textures
// - create a cone with a material
builder = new MultipatchBuilderEx(MultipatchConstructType.Cone, centerZ, 200, 0.8, sr);

BasicMaterial faceMaterial = new BasicMaterial();
faceMaterial.Color = System.Windows.Media.Color.FromRgb(255, 0, 0);
faceMaterial.Shininess = 150;
faceMaterial.TransparencyPercent = 50;
faceMaterial.EdgeWidth = 20;

foreach (var patch in builder.Patches)
patch.Material = faceMaterial;

multipatch = builder.ToGeometry() as Multipatch;

创建基本材料

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// Create BasicMaterial with default values
BasicMaterial material = new BasicMaterial();
System.Windows.Media.Color color = material.Color; // color = Colors.Black
System.Windows.Media.Color edgeColor = material.EdgeColor; // edgeColor = Colors.Black
int edgeWidth = material.EdgeWidth; // edgeWidth = 0
int transparency = material.TransparencyPercent; // transparency = 0
int shininess = material.Shininess; // shininess = 0
bool cullBackFace = material.IsCullBackFace; // cullBackFace = false

// Modify the properties
material.Color = System.Windows.Media.Colors.Red;
material.EdgeColor = System.Windows.Media.Colors.Blue;
material.EdgeWidth = 10;
material.TransparencyPercent = 50;
material.Shininess = 25;
material.IsCullBackFace = true;

使用 JPEG 纹理创建基本材质

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
// read the jpeg into a buffer
//At 3.0 you need https://www.nuget.org/packages/Microsoft.Windows.Compatibility
//System.Drawing
System.Drawing.Image image = System.Drawing.Image.FromFile(@"C:\temp\myImageFile.jpg");
MemoryStream memoryStream = new MemoryStream();

System.Drawing.Imaging.ImageFormat format = System.Drawing.Imaging.ImageFormat.Jpeg;
image.Save(memoryStream, format);
byte[] imageBuffer = memoryStream.ToArray();

var jpgTexture = new JPEGTexture(imageBuffer);

// texture properties
int bpp = jpgTexture.BytesPerPixel;
int columnCount = jpgTexture.ColumnCount;
int rowCount = jpgTexture.RowCount;

// build the textureResource and the material
BasicMaterial material = new BasicMaterial();
material.TextureResource = new TextureResource(jpgTexture);

使用未压缩纹理创建基本材质

1
2
3
4
5
6
7
8
9
10
11
UncompressedTexture uncompressedTexture1 = new UncompressedTexture(new byte[10 * 12 * 3], 10, 12, 3);

// texture properties
int bpp = uncompressedTexture1.BytesPerPixel;
int columnCount = uncompressedTexture1.ColumnCount;
int rowCount = uncompressedTexture1.RowCount;

// build the textureResource and the material
TextureResource tr = new TextureResource(uncompressedTexture1);
BasicMaterial material = new BasicMaterial();
material.TextureResource = tr;

获取多面体的纹理图像

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
// <summary>
// This method gets the material texture image of a multipatch.
// This method must be called on the MCT. Use QueuedTask.Run.
// </summary>
// <param name="multipatch">The input multipatch.</param>
// <param name="patchIndex">The index of the patch (part) for which to get the material texture.</param>
public void GetMultipatchTextureImage(Multipatch multipatch, int patchIndex)
{
int materialIndex = multipatch.GetPatchMaterialIndex(patchIndex);
if (!multipatch.IsMaterialTextured(materialIndex))
return;

TextureCompressionType compressionType =
multipatch.GetMaterialTextureCompressionType(materialIndex);

string ext = compressionType == TextureCompressionType.CompressionJPEG ? ".jpg" : ".dat";
byte[] textureBuffer = multipatch.GetMaterialTexture(materialIndex);

Stream imageStream = new MemoryStream(textureBuffer);
System.Drawing.Image image = System.Drawing.Image.FromStream(imageStream);
image.Save(@"C:\temp\myImage" + ext);
}

获取多面体的法线坐标

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
// <summary>
// This method gets the normal coordinate of a multipatch and does something with it.
// This method must be called on the MCT. Use QueuedTask.Run.
// </summary>
// <param name="multipatch">The input multipatch.</param>
// <param name="patchIndex">The index of the patch (part) for which to get the normal.</param>
public void DoSomethingWithNormalCoordinate(Multipatch multipatch, int patchIndex)
{
if (multipatch.HasNormals)
{
// If the multipatch has normals, then the number of normals is equal to the number of points.
int numNormals = multipatch.GetPatchPointCount(patchIndex);

for (int pointIndex = 0; pointIndex < numNormals; pointIndex++)
{
Coordinate3D normal = multipatch.GetPatchNormal(patchIndex, pointIndex);

// Do something with the normal coordinate.
}
}
}

获取多面体的法线

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
// <summary>
// This method gets the normal coordinate of a multipatch and does something with it.
// This method must be called on the MCT. Use QueuedTask.Run.
// </summary>
// <param name="multipatch">The input multipatch.</param>
public void DoSomethingWithNormalCoordinates(Multipatch multipatch)
{
if (multipatch.HasNormals)
{
// Allocate the list only once
int numPoints = multipatch.PointCount;
ICollection<Coordinate3D> normals = new List<Coordinate3D>(numPoints);

// The parts of a multipatch are also called patches
int numPatches = multipatch.PartCount;

for (int patchIndex = 0; patchIndex < numPatches; patchIndex++)
{
multipatch.GetPatchNormals(patchIndex, ref normals);

// Do something with the normals for this patch.
}
}
}

获取多面体的材质属性

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
public void GetMaterialProperties(Multipatch multipatch, int patchIndex)
{
if (multipatch.HasMaterials)
{
// Get the material index for the specified patch.
int materialIndex = multipatch.GetPatchMaterialIndex(patchIndex);

System.Windows.Media.Color color = multipatch.GetMaterialColor(materialIndex);
int tranparencyPercent = multipatch.GetMaterialTransparencyPercent(materialIndex);
bool isBackCulled = multipatch.IsMaterialCullBackFace(materialIndex);

if (multipatch.IsMaterialTextured(materialIndex))
{
int bpp = multipatch.GetMaterialTextureBytesPerPixel(materialIndex);
int columnCount = multipatch.GetMaterialTextureColumnCount(materialIndex);
int rowCount = multipatch.GetMaterialTextureRowCount(materialIndex);
}
}
}

多部件

获取多部分要素的各个部分

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
public IEnumerable<Geometry> MultipartToSinglePart(Geometry inputGeometry)
{
// list holding the part(s) of the input geometry
List<Geometry> singleParts = new List<Geometry>();

// check if the input is a null pointer or if the geometry is empty
if (inputGeometry == null || inputGeometry.IsEmpty)
return singleParts;

// based on the type of geometry, take the parts/points and add them individually into a list
switch (inputGeometry.GeometryType)
{
case GeometryType.Envelope:
singleParts.Add(inputGeometry.Clone() as Envelope);
break;
case GeometryType.Multipatch:
singleParts.Add(inputGeometry.Clone() as Multipatch);
break;
case GeometryType.Multipoint:
var multiPoint = inputGeometry as Multipoint;

foreach (var point in multiPoint.Points)
{
// add each point of collection as a standalone point into the list
singleParts.Add(point);
}
break;
case GeometryType.Point:
singleParts.Add(inputGeometry.Clone() as MapPoint);
break;
case GeometryType.Polygon:
var polygon = inputGeometry as Polygon;

foreach (var polygonPart in polygon.Parts)
{
// use the PolygonBuilderEx turning the segments into a standalone
// polygon instance
singleParts.Add(PolygonBuilderEx.CreatePolygon(polygonPart));
}
break;
case GeometryType.Polyline:
var polyline = inputGeometry as Polyline;

foreach (var polylinePart in polyline.Parts)
{
// use the PolylineBuilderEx turning the segments into a standalone
// polyline instance
singleParts.Add(PolylineBuilderEx.CreatePolyline(polylinePart));
}
break;
case GeometryType.Unknown:
break;
default:
break;
}

return singleParts;
}

获取多边形的最外层环

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
public Polygon GetOutermostRings(Polygon inputPolygon)
{
if (inputPolygon == null || inputPolygon.IsEmpty)
return null;

List<Polygon> internalRings = new List<Polygon>();

// explode the parts of the polygon into a list of individual geometries
// see the "Get the individual parts of a multipart feature"
// snippet for MultipartToSinglePart
var parts = MultipartToSinglePart(inputPolygon);

// get an enumeration of clockwise geometries (area > 0) ordered by the area
var clockwiseParts = parts.Where(geom => ((Polygon)geom).Area > 0)
.OrderByDescending(geom => ((Polygon)geom).Area);

// for each of the exterior rings
foreach (var part in clockwiseParts)
{
// add the first (the largest) ring into the internal collection
if (internalRings.Count == 0)
internalRings.Add(part as Polygon);

// use flag to indicate if current part is within the already selection polygons
bool isWithin = false;

foreach (var item in internalRings)
{
if (GeometryEngine.Instance.Within(part, item))
isWithin = true;
}

// if the current polygon is not within any polygon of the internal collection
// then it is disjoint and needs to be added to
if (isWithin == false)
internalRings.Add(part as Polygon);
}

PolygonBuilderEx outerRings = new PolygonBuilderEx();
// now assemble a new polygon geometry based on the internal polygon collection
foreach (var ring in internalRings)
{
outerRings.AddParts(ring.Parts);
}

// return the final geometry of the outer rings
return outerRings.ToGeometry();
}

从地理数据库检索几何

从地理数据库检索几何

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
// methods need to run on the MCT
ArcGIS.Desktop.Framework.Threading.Tasks.QueuedTask.Run(() =>
{
try
{
// open a gdb
using (ArcGIS.Core.Data.Geodatabase gdb =
new ArcGIS.Core.Data.Geodatabase(
new FileGeodatabaseConnectionPath(new Uri(@"c:\Temp\MyDatabase.gdb"))))
{
//Open a featureClass
using (ArcGIS.Core.Data.FeatureClass featureClass =
gdb.OpenDataset<ArcGIS.Core.Data.FeatureClass>("Polygon"))
{

ArcGIS.Core.Data.QueryFilter filter =
new ArcGIS.Core.Data.QueryFilter()
{
WhereClause = "OBJECTID = 6"
};

// get the row
using (ArcGIS.Core.Data.RowCursor rowCursor =
featureClass.Search(filter, false))
{
while (rowCursor.MoveNext())
{
using (var row = rowCursor.Current)
{
long oid = row.GetObjectID();

// get the shape from the row
ArcGIS.Core.Data.Feature feature = row as ArcGIS.Core.Data.Feature;
Polygon polygon = feature.GetShape() as Polygon;

// do something here
}
}
}
}
}
}
catch (Exception ex)
{
// error - handle appropriately
}
});

导入、导出几何图形

将几何图形导入和导出为已知文本

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
// create a point with z, m
MapPoint point = MapPointBuilderEx.CreateMapPoint(
100, 200, 300, 400, SpatialReferences.WebMercator);

// set the flags
WktExportFlags wktExportFlags = WktExportFlags.WktExportDefaults;
WktImportFlags wktImportFlags = WktImportFlags.WktImportDefaults;

// export and import
string wktString = GeometryEngine.Instance.ExportToWKT(wktExportFlags, point);
MapPoint importPoint = GeometryEngine.Instance.ImportFromWKT(
wktImportFlags, wktString, SpatialReferences.WebMercator) as MapPoint;

double x = importPoint.X; // x = 100
double y = importPoint.Y; // y = 200
bool hasZ = importPoint.HasZ; // hasZ = true
double z = importPoint.Z; // z = 300
bool hasM = importPoint.HasM; // hasM = true
double m = importPoint.M; // m = 400

// export without z
WktExportFlags exportFlagsNoZ = WktExportFlags.WktExportStripZs;
wktString = GeometryEngine.Instance.ExportToWKT(exportFlagsNoZ, point);
importPoint = GeometryEngine.Instance.ImportFromWKT(
wktImportFlags, wktString, SpatialReferences.WebMercator) as MapPoint;

x = importPoint.X; // x = 100
y = importPoint.Y; // y = 200
hasZ = importPoint.HasZ; // hasZ = false
z = importPoint.Z; // z = 0
hasM = importPoint.HasM; // hasM = true
m = importPoint.M; // m = 400

// export without m
WktExportFlags exportFlagsNoM = WktExportFlags.WktExportStripMs;
wktString = GeometryEngine.Instance.ExportToWKT(exportFlagsNoM, point);
importPoint = GeometryEngine.Instance.ImportFromWKT(
wktImportFlags, wktString, SpatialReferences.WebMercator) as MapPoint;

x = importPoint.X; // x = 100
y = importPoint.Y; // y = 200
hasZ = importPoint.HasZ; // hasZ = true
z = importPoint.Z; // z = 300
hasM = importPoint.HasM; // hasM = false
m = importPoint.M; // m = Nan

// export without z, m
wktString = GeometryEngine.Instance.ExportToWKT(
exportFlagsNoZ | exportFlagsNoM, point);
importPoint = GeometryEngine.Instance.ImportFromWKT(
wktImportFlags, wktString, SpatialReferences.WebMercator) as MapPoint;

x = importPoint.X; // x = 100
y = importPoint.Y; // y = 200
hasZ = importPoint.HasZ; // hasZ = false
z = importPoint.Z; // z = 0
hasM = importPoint.HasM; // hasM = false
m = importPoint.M; // m = Nan

将几何图形导入和导出到众所周知的二进制

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
// create a polyline
List<Coordinate2D> coords = new List<Coordinate2D>
{
new Coordinate2D(0, 0),
new Coordinate2D(0, 1),
new Coordinate2D(1, 1),
new Coordinate2D(1, 0)
};

Polyline polyline = PolylineBuilderEx.CreatePolyline(
coords, SpatialReferences.WGS84);

WkbExportFlags wkbExportFlags = WkbExportFlags.WkbExportDefaults;
WkbImportFlags wkbImportFlags = WkbImportFlags.WkbImportDefaults;

// export and import
byte[] buffer = GeometryEngine.Instance.ExportToWKB(wkbExportFlags, polyline);
Geometry geometry = GeometryEngine.Instance.ImportFromWKB(
wkbImportFlags, buffer, SpatialReferences.WGS84);
Polyline importPolyline = geometry as Polyline;


// alternatively, determine the size for the buffer
int bufferSize = GeometryEngine.Instance.GetWKBSize(wkbExportFlags, polyline);
buffer = new byte[bufferSize];
// export
bufferSize = GeometryEngine.Instance.ExportToWKB(
wkbExportFlags, polyline, ref buffer);
// import
importPolyline = GeometryEngine.Instance.ImportFromWKB(
wkbImportFlags, buffer, SpatialReferences.WGS84) as Polyline;

将几何导入和导出到 EsriShape

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
// create an envelope
List<MapPoint> coordsZM = new List<MapPoint>
{
MapPointBuilderEx.CreateMapPoint(1001, 1002, 1003, 1004),
MapPointBuilderEx.CreateMapPoint(2001, 2002, Double.NaN, 2004),
MapPointBuilderEx.CreateMapPoint(3001, -3002, 3003, 3004),
MapPointBuilderEx.CreateMapPoint(1001, -4002, 4003, 4004)
};

Envelope envelope = EnvelopeBuilderEx.CreateEnvelope(
coordsZM[0], coordsZM[2], SpatialReferences.WGS84);

// export and import
EsriShapeExportFlags exportFlags = EsriShapeExportFlags.EsriShapeExportDefaults;
EsriShapeImportFlags importFlags = EsriShapeImportFlags.EsriShapeImportDefaults;
byte[] buffer = GeometryEngine.Instance.ExportToEsriShape(exportFlags, envelope);
Polygon importedPolygon = GeometryEngine.Instance.ImportFromEsriShape(
importFlags, buffer, envelope.SpatialReference) as Polygon;
Envelope importedEnvelope = importedPolygon.Extent;

// export without z,m
buffer = GeometryEngine.Instance.ExportToEsriShape(
EsriShapeExportFlags.EsriShapeExportStripZs |
EsriShapeExportFlags.EsriShapeExportStripMs, envelope);
importedPolygon = GeometryEngine.Instance.ImportFromEsriShape(
importFlags, buffer, SpatialReferences.WGS84) as Polygon;
importedEnvelope = importedPolygon.Extent;

bool hasZ = importedEnvelope.HasZ; // hasZ = false
bool hasM = importedEnvelope.HasM; // hasM = false

// export with shapeSize
int bufferSize = GeometryEngine.Instance.GetEsriShapeSize(
exportFlags, envelope);
buffer = new byte[bufferSize];

bufferSize = GeometryEngine.Instance.ExportToEsriShape(
exportFlags, envelope, ref buffer);
importedPolygon = GeometryEngine.Instance.ImportFromEsriShape(
importFlags, buffer, envelope.SpatialReference) as Polygon;
importedEnvelope = importedPolygon.Extent;


// or use the envelope and envelopeBuilderEx classes
buffer = envelope.ToEsriShape();
// buffer represents a polygon as there is not an envelope Esri shape buffer
// EnvelopeBuilderEx.FromEsriShape takes a polygon Esri shape buffer and returns the extent of the polygon.
importedEnvelope = EnvelopeBuilderEx.FromEsriShape(buffer);

将几何图形导入和导出为 JSON

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
// MapPoint
string inputString =
"{\"x\":1,\"y\":2,\"spatialReference\":{\"wkid\":4326,\"latestWkid\":4326}}";
Geometry geometry = GeometryEngine.Instance.ImportFromJson(
JsonImportFlags.JsonImportDefaults, inputString);

MapPoint importPoint = geometry as MapPoint;
// importPoint = 1, 2
// importPoint.SpatialReference.WKid = 4326

// use the MapPointBuilderEx convenience method
MapPoint importPoint2 = MapPointBuilderEx.FromJson(inputString);
// importPoint2 = 1, 2
// impointPoint2.SpatialReference.Wkid = 4326

string outputString = GeometryEngine.Instance.ExportToJson(
JsonExportFlags.JsonExportDefaults, importPoint);
// outputString =
// "{\"x\":1,\"y\":2,\"spatialReference\":{\"wkid\":4326,\"latestWkid\":4326}}"

string outputString2 = importPoint.ToJson();

inputString =
"{\"spatialReference\":{\"wkid\":4326},\"z\":3,\"m\":4,\"x\":1,\"y\":2}";
importPoint = GeometryEngine.Instance.ImportFromJson(
JsonImportFlags.JsonImportDefaults, inputString) as MapPoint;
// importPoint.HasM = true
// importPoint.HasZ = true
// importPoint.X = 1
// importPoint.Y = 2
// importPoint.M = 4
// importPoint.Z = 3

importPoint2 = MapPointBuilderEx.FromJson(inputString);

// export to json - skip spatial reference
outputString = GeometryEngine.Instance.ExportToJson(
JsonExportFlags.JsonExportSkipCRS, importPoint);
// outputString = "{\"x\":1,\"y\":2,\"z\":3,\"m\":4}"

// export from mappoint, skipping the sr - same as GeometryEngine.Instance.ExportToJson w JsonExportFlags.JsonExportSkipCRS
outputString2 = importPoint.ToJson(true);

//
// Multipoint
//
List<Coordinate2D> coords = new List<Coordinate2D>()
{
new Coordinate2D(100, 200),
new Coordinate2D(201, 300),
new Coordinate2D(301, 400),
new Coordinate2D(401, 500)
};

Multipoint multipoint = MultipointBuilderEx.CreateMultipoint(
coords, SpatialReferences.WebMercator);

inputString =
"{\"points\":[[100,200],[201,300],[301,400],[401,500]],\"spatialReference\":{\"wkid\":3857}}";
Multipoint importMultipoint =
GeometryEngine.Instance.ImportFromJson(
JsonImportFlags.JsonImportDefaults, inputString) as Multipoint;
// importMultipoint.IsEqual(multipoint) = true

ReadOnlyPointCollection points = importMultipoint.Points;
// points.Count = 4
// points[0] = 100, 200
// points[1] = 201, 300
// points[2] = 301, 400
// points[3] = 401, 500

// use the MultipointbuilderEx convenience method
Multipoint importMultipoint2 = MultipointBuilderEx.FromJson(inputString);
// importMultipoint2.IsEqual(multipoint) = true

// export to json
outputString = GeometryEngine.Instance.ExportToJson(
JsonExportFlags.JsonExportDefaults, multipoint);
// outputString = inputString

// or use the multipoint itself
outputString2 = multipoint.ToJson();

//
// Polyline
//
Polyline polyline = PolylineBuilderEx.CreatePolyline(
coords, SpatialReferences.WebMercator);

// export without the spatial reference
outputString = GeometryEngine.Instance.ExportToJson(
JsonExportFlags.JsonExportSkipCRS, polyline);
// import
geometry = GeometryEngine.Instance.ImportFromJson(
JsonImportFlags.JsonImportDefaults, outputString);
Polyline importPolyline = geometry as Polyline;
// importPolyline.SpatialReference = null


points = importPolyline.Points;
// points.Count = 4
// points[0] = 100, 200
// points[1] = 201, 300
// points[2] = 301, 400
// points[3] = 401, 500

// use the polylineBuilderEx convenience method
Polyline importPolyline2 = PolylineBuilderEx.FromJson(outputString);
// importPolyline2 = importPolyline

outputString2 = importPolyline2.ToJson();
// outputString2 = outputString

//
// Polygon
//
Polygon polygon = PolygonBuilderEx.CreatePolygon(
coords, SpatialReferences.WebMercator);

// export without the spatial reference
outputString = GeometryEngine.Instance.ExportToJson(
JsonExportFlags.JsonExportSkipCRS, polygon);
// import
geometry = GeometryEngine.Instance.ImportFromJson(
JsonImportFlags.JsonImportDefaults, outputString);

Polygon importPolygon = geometry as Polygon;
// importPolygon.SpatialReference = null
points = importPolygon.Points;
// points.Count = 5

// polygonBuilderEx convenience method
Polygon importPolyon2 = PolygonBuilderEx.FromJson(outputString);
// importPolygon2 = importPolygon

// export from the polygon
outputString2 = importPolyon2.ToJson(true);

// Empty polygon
polygon = PolygonBuilderEx.CreatePolygon(SpatialReferences.WebMercator);
outputString = GeometryEngine.Instance.ExportToJson(
JsonExportFlags.JsonExportDefaults, polygon);
importPolygon = GeometryEngine.Instance.ImportFromJson(
JsonImportFlags.JsonImportDefaults, outputString) as Polygon;

// importPolygon.IsEmpty = true
// importPolygon.SpatialReference.Wkid = 3857

将几何图形导入和导出为 XML

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
MapPoint minPoint = MapPointBuilderEx.CreateMapPoint(1, 1, 1, 1, 3);
MapPoint maxPoint = MapPointBuilderEx.CreateMapPoint(5, 5, 5);

//
// MapPoint
//
string xml = minPoint.ToXml();
MapPoint minPointImport = MapPointBuilderEx.FromXml(xml);
// minPointImport = minPoint

//
// Envelope
//
Envelope envelopeWithID = EnvelopeBuilderEx.CreateEnvelope(minPoint, maxPoint);

// Envelopes don't have IDs
// envelopeWithID.HasID = false
// envelopeWithID.HasM = true
// envelopeWithID.HasZ = true

xml = envelopeWithID.ToXml();
Envelope envelopeImport = EnvelopeBuilderEx.FromXml(xml);

//
// Multipoint
//
List<MapPoint> list = new List<MapPoint>();
list.Add(minPoint);
list.Add(maxPoint);

Multipoint multiPoint = MultipointBuilderEx.CreateMultipoint(list);

xml = multiPoint.ToXml();
Multipoint multipointImport = MultipointBuilderEx.FromXml(xml);
// multipointImport.PointCount == 2
// multipointImport.HasID = true
// multipointImport.HasM = true
// multipointImport.HasZ= true

转换

创建地理转换

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// create from wkid
GeographicTransformation gt1478 =
ArcGIS.Core.Geometry.GeographicTransformation.Create(1478);
string name = gt1478.Name;
string wkt = gt1478.Wkt;
int wkid = gt1478.Wkid;

// create from wkt
GeographicTransformation another_gt1478 =
ArcGIS.Core.Geometry.GeographicTransformation.Create(wkt);

// inverse
GeographicTransformation inverse_gt148 =
another_gt1478.GetInverse() as GeographicTransformation;
bool isForward = inverse_gt148.IsForward;

创建复合地理变换

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
// Create singleton from wkid
CompositeGeographicTransformation cgt =
ArcGIS.Core.Geometry.CompositeGeographicTransformation.Create(108272);
int count = cgt.Count; // count = 1

IList<GeographicTransformation> gts = cgt.Transformations
as IList<GeographicTransformation>;
gts.Add(ArcGIS.Core.Geometry.GeographicTransformation.Create(1437, false));
count = cgt.Count; // count = 2

// create from an enumeration
CompositeGeographicTransformation another_cgt =
ArcGIS.Core.Geometry.CompositeGeographicTransformation.Create(gts);
GeographicTransformation gt0 = another_cgt[0];
GeographicTransformation gt1 = another_cgt[1];

// get the inverse
CompositeGeographicTransformation inversed_cgt = another_cgt.GetInverse() as CompositeGeographicTransformation;
// inversed_cgt[0] is same as gt1
// inversed_cgt[1] is same as gt0

var wkt = gt0.Wkt;
// create from string
CompositeGeographicTransformation third_cgt =
ArcGIS.Core.Geometry.CompositeGeographicTransformation.Create(wkt, gt0.IsForward);
count = third_cgt.Count; // count = 1

// create from josn
string json = cgt.ToJson();
CompositeGeographicTransformation joson_cgt =
DatumTransformation.CreateFromJson(json) as CompositeGeographicTransformation;

创建投影转换

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
// methods need to be on the MCT
ArcGIS.Desktop.Framework.Threading.Tasks.QueuedTask.Run(() =>
{
SpatialReference sr4267 = SpatialReferenceBuilder.CreateSpatialReference(4267);
SpatialReference sr4326 = SpatialReferences.WGS84;
SpatialReference sr3857 = SpatialReferences.WebMercator;

// Create transformation from 4267 -> 3857
ProjectionTransformation projTransFromSRs =
ArcGIS.Core.Geometry.ProjectionTransformation.Create(sr4267, sr3857);

// create an envelope
Envelope env = EnvelopeBuilderEx.CreateEnvelope(
new Coordinate2D(2, 2), new Coordinate2D(3, 3), sr4267);

// Project with one geo transform 4267 -> 3857
Envelope projectedEnvEx = GeometryEngine.Instance.ProjectEx(
env, projTransFromSRs) as Envelope;

// Create inverse transformation, 3857 -> 4267
ProjectionTransformation projTransFromSRsInverse =
ArcGIS.Core.Geometry.ProjectionTransformation.Create(sr3857, sr4267);
// Project the projected envelope back using the inverse transformation
Envelope projectedEnvBack =
GeometryEngine.Instance.ProjectEx(
projectedEnvEx, projTransFromSRsInverse) as Envelope;

bool isEqual = env.IsEqual(projectedEnvBack);
});

创建高压基准变换

1
2
3
4
5
6
7
8
9
10
11
12
13
14
// Create from wkid
HVDatumTransformation hv110018 = HVDatumTransformation.Create(110018);
int wkid = hv110018.Wkid;
bool isForward = hv110018.IsForward; // isForward = true
string name = hv110018.Name; // Name = WGS_1984_To_WGS_1984_EGM2008_1x1_Height

// Create from wkt
string wkt = hv110018.Wkt;
HVDatumTransformation hv110018FromWkt = HVDatumTransformation.Create(wkt);

// Get the inverse
HVDatumTransformation hv110018Inverse =
hv110018.GetInverse() as HVDatumTransformation;
// hv110018Inverse.IsForward = false

创建复合高压基准变换

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
HVDatumTransformation hv1 = HVDatumTransformation.Create(108034);
HVDatumTransformation hv2 = HVDatumTransformation.Create(108033, false);
List<HVDatumTransformation> hvs = new List<HVDatumTransformation>() { hv1, hv2 };

// create from enumeration
CompositeHVDatumTransformation compositehv =
CompositeHVDatumTransformation.Create(hvs);
int count = compositehv.Count; // count = 2

List<HVDatumTransformation> transforms =
compositehv.Transformations as List<HVDatumTransformation>;
HVDatumTransformation tranform = transforms[0];
// transform.Wkid = 108034

// get inverse
CompositeHVDatumTransformation inverse_compositehv =
compositehv.GetInverse() as CompositeHVDatumTransformation;

// create from xml
string xml = compositehv.ToXml();
//At 2.x - CompositeHVDatumTransformation xml_compositehv =
// CompositeHVDatumTransformation.CreateFromXML(xml);

var xml_compositehv = CompositeHVDatumTransformation.CreateFromXml(xml);

// create from json
string json = compositehv.ToJson();
CompositeHVDatumTransformation json_compositehv =
DatumTransformation.CreateFromJson(json) as CompositeHVDatumTransformation;

确定转换

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
// methods need to run on the MCT
ArcGIS.Desktop.Framework.Threading.Tasks.QueuedTask.Run(() =>
{
//
// find the first transformation used between spatial references 4267 and 4326
//
SpatialReference sr4267 =
SpatialReferenceBuilder.CreateSpatialReference(4267);
SpatialReference sr4326 = SpatialReferences.WGS84;

List<ProjectionTransformation> transformations =
ProjectionTransformation.FindTransformations(sr4267, sr4326);
// transformations.Count = 1
ProjectionTransformation projTrans = transformations[0];
CompositeGeographicTransformation compositeGT =
projTrans.Transformation as CompositeGeographicTransformation;
GeographicTransformation gt = compositeGT[0];
// gt.Wkid = 15851
// gt.Name = "NAD_1927_To_WGS_1984_79_CONUS"
// gt.IsForward = true


//
// find the first five transformation used between spatial references 4267 and 4326
//
transformations = ProjectionTransformation.FindTransformations(
sr4267, sr4326, numResults: 5);
// transformations.Count = 5
projTrans = transformations[0];
compositeGT = projTrans.Transformation as CompositeGeographicTransformation;
// compositeGT.Count = 1
// compositeGT[0].Wkid = 15851
// compositeGT[0].Name = "NAD_1927_To_WGS_1984_79_CONUS"
// compositeGT[0].IsForward = true

projTrans = transformations[1];
compositeGT = projTrans.Transformation as CompositeGeographicTransformation;
// compositeGT.Count = 1
// compositeGT[0].Wkid = 1173
// compositeGT[0].Name = "NAD_1927_To_WGS_1984_4"
// compositeGT[0].IsForward = true

projTrans = transformations[2];
compositeGT = projTrans.Transformation as CompositeGeographicTransformation;
// compositeGT.Count = 1
// compositeGT[0].Wkid = 1172
// compositeGT[0].Name = "NAD_1927_To_WGS_1984_3"
// compositeGT[0].IsForward = true

projTrans = transformations[3];
compositeGT = projTrans.Transformation as CompositeGeographicTransformation;
// compositeGT.Count = 2
// compositeGT[0].Wkid = 1241
// compositeGT[0].Name = "NAD_1927_To_NAD_1983_NADCON"
// compositeGT[0].IsForward = true

// compositeGT[1].Wkid = 108190
// compositeGT[1].Name = "WGS_1984_(ITRF00)_To_NAD_1983"
// compositeGT[1].IsForward = false

projTrans = transformations[4];
compositeGT = projTrans.Transformation as CompositeGeographicTransformation;
// compositeGT.Count = 2
// compositeGT[0].Wkid = 1241
// compositeGT[0].Name = "NAD_1927_To_NAD_1983_NADCON"
// compositeGT[0].IsForward = true

// compositeGT[1].Wkid = 1515
// compositeGT[1].Name = "NAD_1983_To_WGS_1984_5"
// compositeGT[1].IsForward = true


//
// find the first transformation used between spatial
// references 4267 and 4326 within Alaska
//

// Alaska
Envelope envelope = EnvelopeBuilderEx.CreateEnvelope(-161, 61, -145, 69);
transformations = ProjectionTransformation.FindTransformations(
sr4267, sr4326, envelope);
// transformations.Count = 1
projTrans = transformations[0];
compositeGT = projTrans.Transformation as CompositeGeographicTransformation;
// compositeGT.Count = 2
// compositeGT[0].Wkid = 1243
// compositeGT[0].Name = "NAD_1927_To_NAD_1983_Alaska"
// compositeGT[0].IsForward = true

// compositeGT[1].Wkid = 108190
// compositeGT[1].Name = "WGS_1984_(ITRF00)_To_NAD_1983"
// compositeGT[1].IsForward = false


//
// find the first geographic transformation used between two spatial references with VCS (use vertical = false)
//
SpatialReference inSR =
SpatialReferenceBuilder.CreateSpatialReference(4269, 115702);
SpatialReference outSR =
SpatialReferenceBuilder.CreateSpatialReference(4326, 3855);

// Even though each spatial reference has a VCS,
// vertical = false should return geographic transformations.
transformations = ProjectionTransformation.FindTransformations(inSR, outSR);
// transformations.Count = 1
projTrans = transformations[0];
compositeGT = projTrans.Transformation as CompositeGeographicTransformation;
// compositeGT.Count = 1
// compositeGT[0].Wkid = 108190
// compositeGT[0].Name = ""WGS_1984_(ITRF00)_To_NAD_1983"
// compositeGT[0].IsForward = false

//
// find the first vertical transformation used between two spatial references with VCS (use vertical = true)
//

transformations =
ProjectionTransformation.FindTransformations(
inSR, outSR, vertical: true);
// transformations.Count = 1
projTrans = transformations[0];

CompositeHVDatumTransformation compositeHV =
projTrans.Transformation as CompositeHVDatumTransformation;
// compositeHV.Count = 2
// compositeHV[0].Wkid = 1188
// compositeHV[0].Name = "NAD_1983_To_WGS_1984_1"
// compositeHV[0].IsForward = true

// compositeHV[1].Wkid = 110019
// compositeHV[1].Name = "WGS_1984_To_WGS_1984_EGM2008_2.5x2.5_Height"
// compositeHV[1].IsForward = true
});

地图点地理坐标字符串

地图点 - 地理坐标字符串转换

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
SpatialReference sr = SpatialReferences.WGS84;
SpatialReference sr2 = SpatialReferences.WebMercator;

// create some points
MapPoint point0 = MapPointBuilderEx.CreateMapPoint(0, 0, sr);
MapPoint point1 = MapPointBuilderEx.CreateMapPoint(10, 20, sr);
MapPoint point2 = GeometryEngine.Instance.Project(point1, sr2) as MapPoint;
MapPoint pointEmpty = MapPointBuilderEx.CreateMapPoint(sr);
MapPoint pointwithNoSR = MapPointBuilderEx.CreateMapPoint(1, 1);
MapPoint pointZM = MapPointBuilderEx.CreateMapPoint(1, 2, 3, 4, sr);

// convert to MGRS
ToGeoCoordinateParameter mgrsParam =
new ToGeoCoordinateParameter(GeoCoordinateType.MGRS);
// 31NAA6602100000
string geoCoordString = point0.ToGeoCoordinateString(mgrsParam);

// use the builder to create a new point from the string.
// Coordinates are the same
// outPoint.x = 0; outPoint.Y = 0
MapPoint outPoint =
MapPointBuilderEx.FromGeoCoordinateString(
geoCoordString, sr, GeoCoordinateType.MGRS);

// 32QPH0460911794
// outPoint.X = 10; outPoint.Y = 20
geoCoordString = point1.ToGeoCoordinateString(mgrsParam);
outPoint = MapPointBuilderEx.FromGeoCoordinateString(
geoCoordString, sr, GeoCoordinateType.MGRS);

// z, m are not transformed
// outPoint.X = 1; outPoint.Y = 2; outPoint.Z = Nan; outPoint.M = Nan;
geoCoordString = pointZM.ToGeoCoordinateString(mgrsParam);
outPoint = MapPointBuilderEx.FromGeoCoordinateString(
geoCoordString, sr, GeoCoordinateType.MGRS);

// set the number of digits to 2 and convert
// 32QPH0512
// outPoint.X = 10; outPoint.Y = 20
mgrsParam.NumDigits = 2;
geoCoordString = point1.ToGeoCoordinateString(mgrsParam);
outPoint = MapPointBuilderEx.FromGeoCoordinateString(
geoCoordString, sr, GeoCoordinateType.MGRS);


// convert to UTM
ToGeoCoordinateParameter utmParam =
new ToGeoCoordinateParameter(GeoCoordinateType.UTM);
// 31N 166021 0000000
geoCoordString = point0.ToGeoCoordinateString(utmParam);
// 32Q 604609 2211793
geoCoordString = point1.ToGeoCoordinateString(utmParam);

// convert to DMS
ToGeoCoordinateParameter dmsParam =
new ToGeoCoordinateParameter(GeoCoordinateType.DMS);
// 00 00 00.00N 000 00 00.00E
geoCoordString = point0.ToGeoCoordinateString(dmsParam);
// 20 00 00.00N 010 00 00.00E
geoCoordString = point1.ToGeoCoordinateString(dmsParam);

// convert to DDM
ToGeoCoordinateParameter ddmParam =
new ToGeoCoordinateParameter(GeoCoordinateType.DDM);
// 00 00.0000N 000 00.0000E
geoCoordString = point0.ToGeoCoordinateString(ddmParam);
// 20 00.0000N 010 00.0000E
geoCoordString = point1.ToGeoCoordinateString(ddmParam);

// convert to DD
ToGeoCoordinateParameter ddParam =
new ToGeoCoordinateParameter(GeoCoordinateType.DD);
// 00.000000N 000.000000E
geoCoordString = point0.ToGeoCoordinateString(ddParam);
// 20.000000N 010.000000E
geoCoordString = point1.ToGeoCoordinateString(ddParam);

角度单元

角度单位 - 在度和弧度之间转换

1
2
3
4
5
// convert 45 degrees to radians
double radians = AngularUnit.Degrees.ConvertToRadians(45);

// convert PI to degrees
double degrees = AngularUnit.Degrees.ConvertFromRadians(Math.PI);

角度单位 - 使用工厂代码创建角度单位

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
try
{
// create a Grad unit
var grad = AngularUnit.CreateAngularUnit(9105);
string unitName = grad.Name; // Grad
double conversionFactor = grad.ConversionFactor; // 0.015708
double radiansPerUnit = grad.RadiansPerUnit;
int factoryCode = grad.FactoryCode; // 9105

// convert 10 grads to degrees
double val = grad.ConvertTo(10, AngularUnit.Degrees);

// convert 10 radians to grads
val = grad.ConvertFromRadians(10);
}
catch (ArgumentException)
{
// ArgumentException will be thrown by CreateAngularUnit in
// the following scenarios:
// - if the factory code used is a non-angular factory code
// (i.e. it corresponds to square meters which is an area unit code)
// - if the factory code used is invalid
// (i.e. it is negative or doesn't correspond to any factory code)
}

角度单位 - 创建自定义角度单位

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
// custom unit - 3 radians per unit
var myAngularUnit = AngularUnit.CreateAngularUnit("myCustomAngularUnit", 3);
string Name = myAngularUnit.Name; // myCustomAngularUnit
double Factor = myAngularUnit.ConversionFactor; // 3
int Code = myAngularUnit.FactoryCode; // 0 because it is a custom angular unit
double radiansUnit = myAngularUnit.RadiansPerUnit; // 3

// convert 10 degrees to my unit
double converted = AngularUnit.Degrees.ConvertTo(10, myAngularUnit);
// convert it back to degrees
converted = myAngularUnit.ConvertTo(converted, AngularUnit.Degrees);

// convert 1 radian into my angular units
converted = myAngularUnit.ConvertFromRadians(1);

// get the wkt
string wkt = myAngularUnit.Wkt;

// create an angular unit from this wkt
var anotherAngularUnit = AngularUnit.CreateAngularUnit(wkt);
// anotherAngularUnit.ConversionFactor = 3
// anotherAngularUnit.FactoryCode = 0
// anotherAngularUnit.RadiansPerUnit = 3

线性单位

线性单位 - 在英尺和米之间转换

1
2
3
4
5
// convert 10 feet to meters
double metres = LinearUnit.Feet.ConvertToMeters(10);

// convert 20 meters to feet
double feet = LinearUnit.Feet.ConvertFromMeters(20.0);

线性单位 - 在厘米和毫米之间转换

1
2
3
4
5
6
7
8
// convert 11 centimeters to millimeters
double mm = LinearUnit.Centimeters.ConvertTo(11, LinearUnit.Millimeters);

// convert the result back to centimeters
double cm = LinearUnit.Millimeters.ConvertTo(mm, LinearUnit.Centimeters);

// convert the millimeter result back to meters
double meters = LinearUnit.Millimeters.ConvertToMeters(mm);

线性单位 - 使用工厂代码创建线性单位

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
try
{
// create a british 1936 foot
var britFoot = LinearUnit.CreateLinearUnit(9095);
string unitName = britFoot.Name; // "Foot_British_1936"
double conversionFactor = britFoot.ConversionFactor; // 0.3048007491
double metersPerUnit = britFoot.MetersPerUnit;
int factoryCode = britFoot.FactoryCode; // 9095

// convert 10 british 1936 feet to centimeters
double val = britFoot.ConvertTo(10, LinearUnit.Centimeters);

// convert 10 m to british 1936 feet
val = britFoot.ConvertFromMeters(10);
}
catch (ArgumentException)
{
// ArgumentException will be thrown by CreateLinearUnit
// in the following scenarios:
// - if the factory code used is a non-linear factory code
// (i.e. it corresponds to square meters which is an area unit code)
// - if the factory code used is invalid
// (i.e. it is negative or doesn't correspond to any factory code)
}

线性单位 - 创建自定义线性单位

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
// create a custom linear unit - there are 0.33 meters per myLinearUnit
var myLinearUnit = LinearUnit.CreateLinearUnit("myCustomLinearUnit", 0.33);
string name = myLinearUnit.Name; // myCustomLinearUnit
double convFactor = myLinearUnit.ConversionFactor; // 0.33
int code = myLinearUnit.FactoryCode; // 0 for custom units
double metersUnit = myLinearUnit.MetersPerUnit; // 0.33
string toString = myLinearUnit.ToString(); // same as Name - myCustomLinearUnit

// convert 10 centimeters to myLinearUnit
double convertedVal = LinearUnit.Centimeters.ConvertTo(10, myLinearUnit);


// get the wkt
string lu_wkt = myLinearUnit.Wkt;

// create an angular unit from this wkt
var anotherLinearUnit = LinearUnit.CreateLinearUnit(lu_wkt);
// anotherLinearUnit.ConversionFactor = 0.33
// anotherLinearUnit.FactoryCode = 0
// anotherLinearUnit.MetersPerUnit = 0.33

面积单位

面积单位 - 在平方英尺和平方米之间转换

1
2
3
4
5
// convert 700 square meters to square feet
double sqFeet = AreaUnit.SquareFeet.ConvertFromSquareMeters(700);

// convert 1100 square feet to square meters
double sqMeters = AreaUnit.SquareFeet.ConvertToSquareMeters(1000);

面积单位 - 在公顷和英亩之间转换

1
2
// convert 2 hectares to acres
double acres = AreaUnit.Hectares.ConvertTo(2, AreaUnit.Acres);

面积单位 - 在公顷和平方英里之间转换

1
2
// convert 300 hectares to square miles
double sqMiles = AreaUnit.Hectares.ConvertTo(300, AreaUnit.SquareMiles);

面积单位 - 各种单位的平方米数

1
2
3
4
5
6
double sqMetersPerUnit = AreaUnit.Acres.SquareMetersPerUnit;
sqMetersPerUnit = AreaUnit.Ares.SquareMetersPerUnit;
sqMetersPerUnit = AreaUnit.Hectares.SquareMetersPerUnit;
sqMetersPerUnit = AreaUnit.SquareKilometers.SquareMetersPerUnit;
sqMetersPerUnit = AreaUnit.SquareMiles.SquareMetersPerUnit;
sqMetersPerUnit = AreaUnit.SquareYards.SquareMetersPerUnit;

面积单位 - 创建面积单位

1
2
3
4
5
6
7
8
9
10
11
12
13
14
try
{
var myFactoryCodeInit = AreaUnit.CreateAreaUnit(109439); // 109439 is the factory code for square miles

var myWktUnit = AreaUnit.CreateAreaUnit("HECTARE_AREAUNIT[\"H\",10000.0]");

var myCustomUnit = AreaUnit.CreateAreaUnit("myAreaUnit", 12);
}
catch (ArgumentException)
{
// ArgumentException will be thrown by CreateAreaUnit in the following scenarios
// - if the factory code used is a non-areal factory code (i.e. it corresponds to degrees which is an angular unit code)
// - if the factory code used is invalid (i.e. it is negative or doesn't correspond to any factory code)
}

几何引擎函数

加速几何图形

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
// Use acceleration to speed up relational operations.  Accelerate your source geometry only if you are going to test many other geometries against it. 
// Acceleration is applicable for polylines and polygons only. Note that accelerated geometries take more memory so if you aren't going to get any
// benefit from accelerating it, don't do it.

// The performance of the following GeometryEngine functions are the only ones which can be improved with an accelerated geometry.
// GeometryEngine.Instance.Contains
// GeometryEngine.Instance.Crosses
// GeometryEngine.Instance.Disjoint
// GeometryEngine.Instance.Disjoint3D
// GeometryEngine.Instance.Equals
// GeometryEngine.Instance.Intersects
// GeometryEngine.Instance.Relate
// GeometryEngine.Instance.Touches
// GeometryEngine.Instance.Within


// methods need to run on the MCT
ArcGIS.Desktop.Framework.Threading.Tasks.QueuedTask.Run(() =>
{
// accelerate the geometry to test
var acceleratedPoly = GeometryEngine.Instance.AccelerateForRelationalOperations(polygon);

// loop through all the geometries to test against
foreach (var testPolygon in testPolygons)
{
bool contains = GeometryEngine.Instance.Contains(acceleratedPoly, testPolygon);
bool within = GeometryEngine.Instance.Within(acceleratedPoly, testPolygon);
bool crosses = GeometryEngine.Instance.Crosses(acceleratedPoly, testPolygon);
}
});

确定面的面积

1
2
3
4
5
var g1 = PolygonBuilderEx.FromJson("{\"rings\": [ [ [0, 0], [10, 0], [10, 10], [0, 10] ] ] }");
double d = GeometryEngine.Instance.Area(g1);
// d = -100.0 //negative due to wrong ring orientation
d = GeometryEngine.Instance.Area(GeometryEngine.Instance.SimplifyAsFeature(g1));
// d = 100.0 // feature has been simplifed; ring orientation is correct

确定多部分多边形的边界

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
// create a donut polygon.  Must use the PolygonBuilderEx object

List<Coordinate2D> outerPts = new List<Coordinate2D>();
outerPts.Add(new Coordinate2D(10.0, 10.0));
outerPts.Add(new Coordinate2D(10.0, 20.0));
outerPts.Add(new Coordinate2D(20.0, 20.0));
outerPts.Add(new Coordinate2D(20.0, 10.0));

List<Coordinate2D> innerPts = new List<Coordinate2D>();
innerPts.Add(new Coordinate2D(13.0, 13.0));
innerPts.Add(new Coordinate2D(17.0, 13.0));
innerPts.Add(new Coordinate2D(17.0, 17.0));
innerPts.Add(new Coordinate2D(13.0, 17.0));

Polygon donut = null;

// add the outer points
PolygonBuilderEx pb = new PolygonBuilderEx(outerPts);
// add the inner points (note they are defined anticlockwise)
pb.AddPart(innerPts);
// get the polygon
donut = pb.ToGeometry();

// get the boundary
Geometry g = GeometryEngine.Instance.Boundary(donut);
Polyline boundary = g as Polyline;

缓冲地图点

1
2
3
4
// buffer a point
MapPoint pt = MapPointBuilderEx.CreateMapPoint(1.0, 1.0, SpatialReferences.WGS84);
Geometry ptBuffer = GeometryEngine.Instance.Buffer(pt, 5.0);
Polygon buffer = ptBuffer as Polygon;

缓冲圆弧

1
2
3
4
5
6
7
8
9
10
// create the circular arc
MapPoint fromPt = MapPointBuilderEx.CreateMapPoint(2, 1);
MapPoint toPt = MapPointBuilderEx.CreateMapPoint(1, 2);
Coordinate2D interiorPt = new Coordinate2D(1 + Math.Sqrt(2) / 2, 1 + Math.Sqrt(2) / 2);

EllipticArcSegment circularArc = EllipticArcBuilderEx.CreateCircularArc(fromPt, toPt, interiorPt);

// buffer the arc
Polyline polyline = PolylineBuilderEx.CreatePolyline(circularArc);
Geometry lineBuffer = GeometryEngine.Instance.Buffer(polyline, 10);

缓冲多个地图点

1
2
3
4
5
6
7
8
9
10
// creates a buffer around each MapPoint

List<MapPoint> pts = new List<MapPoint>();
pts.Add(MapPointBuilderEx.CreateMapPoint(1.0, 1.0));
pts.Add(MapPointBuilderEx.CreateMapPoint(1.0, 2.0));
pts.Add(MapPointBuilderEx.CreateMapPoint(2.0, 2.0));
pts.Add(MapPointBuilderEx.CreateMapPoint(2.0, 1.0));

Geometry ptsBuffer = GeometryEngine.Instance.Buffer(pts, 0.25);
Polygon bufferResult = ptsBuffer as Polygon; // bufferResult will have 4 parts

缓冲多种不同的几何类型

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
List<Coordinate2D> coords = new List<Coordinate2D>()
{
new Coordinate2D(1, 2), new Coordinate2D(3, 4), new Coordinate2D(4, 2),
new Coordinate2D(5, 6), new Coordinate2D(7, 8), new Coordinate2D(8, 4),
new Coordinate2D(9, 10), new Coordinate2D(11, 12), new Coordinate2D(12, 8),
new Coordinate2D(10, 8), new Coordinate2D(12, 12), new Coordinate2D(14, 10)
};

List<Geometry> manyGeometries = new List<Geometry>
{
MapPointBuilderEx.CreateMapPoint(coords[9]),
PolylineBuilderEx.CreatePolyline(new List<Coordinate2D>(){coords[0], coords[1], coords[2]}, SpatialReferences.WGS84),
PolylineBuilderEx.CreatePolyline(new List<Coordinate2D>(){coords[3], coords[4], coords[5]}),
PolygonBuilderEx.CreatePolygon(new List<Coordinate2D>(){coords[6], coords[7], coords[8]})
};

Geometry manyGeomBuffer = GeometryEngine.Instance.Buffer(manyGeometries, 0.25);

在折线上插值 Z 值

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
List<Coordinate3D> coords2 = new List<Coordinate3D>()
{
new Coordinate3D(0, 0, 0),
new Coordinate3D(0, 1000, double.NaN),
new Coordinate3D(1000, 1000, 50),
new Coordinate3D(1000, 1000, 76),
new Coordinate3D(0, 1000, double.NaN),
new Coordinate3D(0, 0, 0)
};

SpatialReference sr = SpatialReferences.WebMercator;

Polyline polyline = PolylineBuilderEx.CreatePolyline(coords2, sr);

// polyline.HasZ = true
// polyline.Points[1].HasZ = true
// polyline.Points[1].Z = NaN
// polyline.Points[4].HasZ = true
// polyline.Points[4].Z = NaN

Polyline polylineNoNaNZs = GeometryEngine.Instance.CalculateNonSimpleZs(polyline, 0) as Polyline;

// polylineNoNaNZs.Points[1].HasZ = true
// polylineNoNaNZs.Points[1].Z = 25 (halfway between 0 and 50)
// polylineNoNaNZs.Points[4].HasZ = true
// polylineNoNaNZs.Points[4].Z = 38 (halfway between 76 and 0)

在多边形上插值 M 值

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
List<MapPoint> coords = new List<MapPoint>()
{
MapPointBuilderEx.CreateMapPoint(0, 0, 0, 0),
MapPointBuilderEx.CreateMapPoint(0, 1000),
MapPointBuilderEx.CreateMapPoint(1000, 1000, 10, 50)
};

SpatialReference sr = SpatialReferences.WebMercator;

Polygon polygon = PolygonBuilderEx.CreatePolygon(coords, sr);

// polygon.HasM = true
// polygon.Points[1].HasM = true
// polygon.Points[1].M = NaN

Polygon polygonNoNaNMs = GeometryEngine.Instance.CalculateNonSimpleMs(polygon, 0) as Polygon;

// polygonNoNaNMs.Points[1].HasM = true
// polygonNoNaNMs.Points[1].M = 25 (halfway between 0 and 50)

将封套在 X,Y 周围居中

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
Envelope env = EnvelopeBuilderEx.CreateEnvelope(1.0, 1.0, 5.0, 5.0);
Envelope centered = GeometryEngine.Instance.CenterAt(env, 2.0, 2.0);

// centered.Center.X = 2.0
// centered.Center.Y = 2.0
// centered.XMin = 0
// centered.YMin = 0
// centered.XMax = 4
// centered.YMax = 4

centered = env.CenterAt(4.0, 3.0);
// centered.Center.X == 4.0
// centered.Center.Y == 3.0
// centered.XMin == 2.0
// centered.YMin == 1.0
// centered.XMax == 6.0
// centered.YMax == 5.0

查找几何体的质心

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
// simple polygon
List<Coordinate2D> list2D = new List<Coordinate2D>();
list2D.Add(new Coordinate2D(0, 0));
list2D.Add(new Coordinate2D(0, 2));
list2D.Add(new Coordinate2D(2, 2));
list2D.Add(new Coordinate2D(2, 0));

Polygon polygon = PolygonBuilderEx.CreatePolygon(list2D, SpatialReferences.WGS84);

// verify it is simple
bool isSimple = GeometryEngine.Instance.IsSimpleAsFeature(polygon);
// find the centroid
MapPoint centroid = GeometryEngine.Instance.Centroid(polygon);
// centroid.X = 1
// centroid.Y = 1

// map Point
MapPoint pt1 = MapPointBuilderEx.CreateMapPoint(1, 2, 3, 4, SpatialReferences.WGS84);
MapPoint pt2 = MapPointBuilderEx.CreateMapPoint(5, 2, double.NaN, 7);

// pt1.HasZ = true
// pt1.HasM = true
centroid = GeometryEngine.Instance.Centroid(pt1);
// centroid.HasZ = true
// centroid.HasM = true
// pt1.IsEqual(centroid) = true

// multipoint
List<MapPoint> list = new List<MapPoint>() { pt1, pt2 };
Multipoint multipoint = MultipointBuilderEx.CreateMultipoint(list);
// multipoint.HasZ = true
// multipoint.HasM = true

centroid = GeometryEngine.Instance.Centroid(multipoint);
// centroid.X = 3
// centroid.Y = 2
// centroid.HasZ = false
// centroid.HasM = false

剪裁折线

1
2
3
4
5
6
7
// clip a polyline by an envelope

Envelope env = EnvelopeBuilderEx.CreateEnvelope(2.0, 2.0, 4.0, 4.0);
LineSegment line = LineBuilderEx.CreateLineSegment(new Coordinate2D(0, 3), new Coordinate2D(5.0, 3.0));
Polyline polyline = PolylineBuilderEx.CreatePolyline(line);

Geometry clipGeom = GeometryEngine.Instance.Clip(polyline, env);

按多边形裁剪折线

1
2
3
4
5
6
7
8
9
10
11
12
13
// clip a polyline by a polygon

List<Coordinate2D> list = new List<Coordinate2D>();
list.Add(new Coordinate2D(1.0, 1.0));
list.Add(new Coordinate2D(1.0, 4.0));
list.Add(new Coordinate2D(4.0, 4.0));
list.Add(new Coordinate2D(4.0, 1.0));

Polygon polygon = PolygonBuilderEx.CreatePolygon(list, SpatialReferences.WGS84);

LineSegment crossingLine = LineBuilderEx.CreateLineSegment(MapPointBuilderEx.CreateMapPoint(0, 3), MapPointBuilderEx.CreateMapPoint(5.0, 3.0));
Polyline p = PolylineBuilderEx.CreatePolyline(crossingLine);
Geometry geometry = GeometryEngine.Instance.Clip(p, polygon.Extent);

构建具有指定距离和方位角的大地测量线

1
2
3
4
5
var sr = SpatialReferenceBuilder.CreateSpatialReference(4326);
var mapPoint = MapPointBuilderEx.CreateMapPoint(15, 60, sr);

// calculate
var polylineGeodetic = GeometryEngine.Instance.ConstructGeodeticLineFromDistance(GeodeticCurveType.Loxodrome, mapPoint, 5000000, 45, null, CurveDensifyMethod.ByLength, 300000);

构建连接点的大地测量线

1
2
3
4
5
6
7
8
9
10
var sr = SpatialReferenceBuilder.CreateSpatialReference(4326);

var pt1 = MapPointBuilderEx.CreateMapPoint(60, 180, sr);
var pt2 = MapPointBuilderEx.CreateMapPoint(60, 0, sr);

// densify by length
var gl = GeometryEngine.Instance.ConstructGeodeticLineFromPoints(GeodeticCurveType.Geodesic, pt1, pt2, null, CurveDensifyMethod.ByLength, -3.356);

// densify by deviation
gl = GeometryEngine.Instance.ConstructGeodeticLineFromPoints(GeodeticCurveType.Geodesic, pt1, pt2, null, CurveDensifyMethod.ByDeviation, -0.0026);

在距现有点一定距离和一定角度处构造点

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
MapPoint inPoint = MapPointBuilderEx.CreateMapPoint(3, 4);
double angle = 0;
double distance = 10;

MapPoint outPoint = GeometryEngine.Instance.ConstructPointFromAngleDistance(inPoint, angle, distance);
// outPoint.X = 13
// outPoint.Y = 4

SpatialReference sr = SpatialReferences.WGS84;
inPoint = MapPointBuilderEx.CreateMapPoint(0, 0, sr);
angle = Math.PI;
distance = 1;

outPoint = GeometryEngine.Instance.ConstructPointFromAngleDistance(inPoint, angle, distance, sr);
// outPoint.X = -1
// outPoint.Y = 0

从一组折线构造多边形

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
List<Coordinate2D> firstLinePts = new List<Coordinate2D>();
firstLinePts.Add(new Coordinate2D(1.0, 1.0));
firstLinePts.Add(new Coordinate2D(1.0, 4.0));

List<Coordinate2D> secondLinePts = new List<Coordinate2D>();
secondLinePts.Add(new Coordinate2D(4.0, 4.0));
secondLinePts.Add(new Coordinate2D(4.0, 1.0));

List<Coordinate2D> thirdLinePts = new List<Coordinate2D>();
thirdLinePts.Add(new Coordinate2D(0.0, 2.0));
thirdLinePts.Add(new Coordinate2D(5.0, 2.0));

List<Coordinate2D> fourthLinePts = new List<Coordinate2D>();
fourthLinePts.Add(new Coordinate2D(0.0, 3.0));
fourthLinePts.Add(new Coordinate2D(5.0, 3.0));

// build the polylines
List<Polyline> polylines = new List<Polyline>();
polylines.Add(PolylineBuilderEx.CreatePolyline(firstLinePts));
polylines.Add(PolylineBuilderEx.CreatePolyline(secondLinePts));
polylines.Add(PolylineBuilderEx.CreatePolyline(thirdLinePts));
polylines.Add(PolylineBuilderEx.CreatePolyline(fourthLinePts));

// construct polygons from the polylines
var polygons = GeometryEngine.Instance.ConstructPolygonsFromPolylines(polylines);

// polygons.Count = 1
// polygon coordinates are (1.0, 2.0), (1.0, 3.0), (4.0, 3.0), (4.0, 2.0)

多边形包含地图点、折线、多边形

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
// build a polygon      
List<MapPoint> pts = new List<MapPoint>();
pts.Add(MapPointBuilderEx.CreateMapPoint(1.0, 1.0));
pts.Add(MapPointBuilderEx.CreateMapPoint(1.0, 2.0));
pts.Add(MapPointBuilderEx.CreateMapPoint(2.0, 2.0));
pts.Add(MapPointBuilderEx.CreateMapPoint(2.0, 1.0));

Polygon poly = PolygonBuilderEx.CreatePolygon(pts);

// test if an inner point is contained
MapPoint innerPt = MapPointBuilderEx.CreateMapPoint(1.5, 1.5);
bool contains = GeometryEngine.Instance.Contains(poly, innerPt); // contains = true

// test a point on a boundary
contains = GeometryEngine.Instance.Contains(poly, poly.Points[0]); // contains = false

// test an interior line
MapPoint innerPt2 = MapPointBuilderEx.CreateMapPoint(1.25, 1.75);
List<MapPoint> innerLinePts = new List<MapPoint>();
innerLinePts.Add(innerPt);
innerLinePts.Add(innerPt2);

// test an inner polyline
Polyline polyline = PolylineBuilderEx.CreatePolyline(innerLinePts);
contains = GeometryEngine.Instance.Contains(poly, polyline); // contains = true

// test a line that crosses the boundary
MapPoint outerPt = MapPointBuilderEx.CreateMapPoint(3, 1.5);
List<MapPoint> crossingLinePts = new List<MapPoint>();
crossingLinePts.Add(innerPt);
crossingLinePts.Add(outerPt);

polyline = PolylineBuilderEx.CreatePolyline(crossingLinePts);
contains = GeometryEngine.Instance.Contains(poly, polyline); // contains = false

// test a polygon in polygon
Envelope env = EnvelopeBuilderEx.CreateEnvelope(innerPt, innerPt2);
contains = GeometryEngine.Instance.Contains(poly, env); // contains = true

确定凸包

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
//
// convex hull around a point - returns a point
//

MapPoint pt = MapPointBuilderEx.CreateMapPoint(2.0, 2.0);
Geometry hull = GeometryEngine.Instance.ConvexHull(pt);
MapPoint hullPt = hull as MapPoint;
// nullPt.X = 2
// hullPt.Y = 2


List<MapPoint> list = new List<MapPoint>();
list.Add(MapPointBuilderEx.CreateMapPoint(1.0, 1.0));
list.Add(MapPointBuilderEx.CreateMapPoint(1.0, 2.0));
list.Add(MapPointBuilderEx.CreateMapPoint(2.0, 2.0));
list.Add(MapPointBuilderEx.CreateMapPoint(2.0, 1.0));

//
// convex hull around a multipoint - returns a polygon
//

// build a multiPoint
Multipoint multiPoint = MultipointBuilderEx.CreateMultipoint(list);

hull = GeometryEngine.Instance.ConvexHull(multiPoint);
Polygon hullPoly = hull as Polygon;
// hullPoly.Area = 1
// hullPoly.PointCount = 5

//
// convex hull around a line - returns a polyline or polygon
//

List<MapPoint> polylineList = new List<MapPoint>();
polylineList.Add(MapPointBuilderEx.CreateMapPoint(1.0, 1.0));
polylineList.Add(MapPointBuilderEx.CreateMapPoint(2.0, 2.0));

// 2 point straight line
Polyline polyline = PolylineBuilderEx.CreatePolyline(polylineList);
hull = GeometryEngine.Instance.ConvexHull(polyline);
Polyline hullPolyline = hull as Polyline;
// hullPolyline.Length = Math.Sqrt(2)
// hullPolyline.PointCount = 2

// 3 point angular line
polylineList.Add(MapPointBuilderEx.CreateMapPoint(2.0, 1.0));
polyline = PolylineBuilderEx.CreatePolyline(polylineList);
hull = GeometryEngine.Instance.ConvexHull(polyline);
hullPoly = hull as Polygon;
// hullPoly.Length = 2 + Math.Sqrt(2)
// hullPoly.Area = 0.5
// hullPoly.PointCount = 4

//
// convex hull around a polygon - returns a polygon
//

// simple polygon
Polygon poly = PolygonBuilderEx.CreatePolygon(list);
hull = GeometryEngine.Instance.ConvexHull(poly);
hullPoly = hull as Polygon;

// hullPoly.Length = 4.0
// hullPoly.Area = 1.0
// hullPoly.PointCount = 5

// polygon with concave angles
List<MapPoint> funkyList = new List<MapPoint>();
funkyList.Add(MapPointBuilderEx.CreateMapPoint(1.0, 1.0));
funkyList.Add(MapPointBuilderEx.CreateMapPoint(1.5, 1.5));
funkyList.Add(MapPointBuilderEx.CreateMapPoint(1.0, 2.0));
funkyList.Add(MapPointBuilderEx.CreateMapPoint(2.0, 2.0));
funkyList.Add(MapPointBuilderEx.CreateMapPoint(1.5, 1.5));
funkyList.Add(MapPointBuilderEx.CreateMapPoint(2.0, 1.0));
funkyList.Add(MapPointBuilderEx.CreateMapPoint(1.0, 1.0));

Polygon funkyPoly = PolygonBuilderEx.CreatePolygon(funkyList);
hull = GeometryEngine.Instance.ConvexHull(funkyPoly);
hullPoly = hull as Polygon;
// hullPoly.Length = 4.0
// hullPoly.Area = 1.0
// hullPoly.PointCount = 5
// hullPoly.Points[0] = 1.0, 1.0
// hullPoly.Points[1] = 1.0, 2.0
// hullPoly.Points[2] = 2.0, 2.0
// hullPoly.Points[3] = 2.0, 1.0
// hullPoly.Points[4] = 1.0, 1.0

确定两个几何图形是否相交

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
//
// pt on pt
//

MapPoint pt = MapPointBuilderEx.CreateMapPoint(1.0, 1.0);
MapPoint pt2 = MapPointBuilderEx.CreateMapPoint(2.0, 2.0);

bool crosses = GeometryEngine.Instance.Crosses(pt, pt2); // crosses = false
crosses = GeometryEngine.Instance.Crosses(pt, pt); // crosses = false

//
// pt and line
//

List<MapPoint> list = new List<MapPoint>();
list.Add(MapPointBuilderEx.CreateMapPoint(1.0, 1.0));
list.Add(MapPointBuilderEx.CreateMapPoint(3.0, 3.0));
list.Add(MapPointBuilderEx.CreateMapPoint(5.0, 1.0));

Polyline line1 = PolylineBuilderEx.CreatePolyline(list);
crosses = GeometryEngine.Instance.Crosses(line1, pt2); // crosses = false
crosses = GeometryEngine.Instance.Crosses(pt2, line1); // crosses = false
// end pt of line
crosses = GeometryEngine.Instance.Crosses(line1, pt); // crosses = false

//
// pt and polygon
//
List<MapPoint> polyPts = new List<MapPoint>();
polyPts.Add(MapPointBuilderEx.CreateMapPoint(3.0, 2.0));
polyPts.Add(MapPointBuilderEx.CreateMapPoint(3.0, 6.0));
polyPts.Add(MapPointBuilderEx.CreateMapPoint(6.0, 6.0));
polyPts.Add(MapPointBuilderEx.CreateMapPoint(6.0, 2.0));

Polygon poly1 = PolygonBuilderEx.CreatePolygon(polyPts);
crosses = GeometryEngine.Instance.Crosses(poly1, pt); // crosses = false
crosses = GeometryEngine.Instance.Crosses(pt, poly1); // crosses = false

//
// line and line
//
List<MapPoint> list2 = new List<MapPoint>();
list2.Add(MapPointBuilderEx.CreateMapPoint(1.0, 3.0));
list2.Add(MapPointBuilderEx.CreateMapPoint(3.0, 1.0));
list2.Add(MapPointBuilderEx.CreateMapPoint(5.0, 3.0));

Polyline line2 = PolylineBuilderEx.CreatePolyline(list2);
crosses = GeometryEngine.Instance.Crosses(line1, line2); // crosses = true

//
// line and polygon
//
crosses = GeometryEngine.Instance.Crosses(poly1, line1); // crosses = true

//
// polygon and polygon
//
Envelope env = EnvelopeBuilderEx.CreateEnvelope(MapPointBuilderEx.CreateMapPoint(1.0, 1.0), MapPointBuilderEx.CreateMapPoint(4, 4));
Polygon poly2 = PolygonBuilderEx.CreatePolygon(env);
crosses = GeometryEngine.Instance.Crosses(poly1, poly2); // crosses = false

使用折线切割几何图形

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
SpatialReference sr = SpatialReferences.WGS84;

List<MapPoint> list = new List<MapPoint>();
list.Add(MapPointBuilderEx.CreateMapPoint(1.0, 1.0, sr));
list.Add(MapPointBuilderEx.CreateMapPoint(1.0, 4.0, sr));
list.Add(MapPointBuilderEx.CreateMapPoint(4.0, 4.0, sr));
list.Add(MapPointBuilderEx.CreateMapPoint(4.0, 1.0, sr));

List<Geometry> cutGeometries;

LineSegment line = LineBuilderEx.CreateLineSegment(MapPointBuilderEx.CreateMapPoint(0, 0, sr), MapPointBuilderEx.CreateMapPoint(3, 6, sr));
Polyline cutter = PolylineBuilderEx.CreatePolyline(line);

// polyline
Polyline polyline = PolylineBuilderEx.CreatePolyline(list);
bool isSimple = GeometryEngine.Instance.IsSimpleAsFeature(polyline);
cutGeometries = GeometryEngine.Instance.Cut(polyline, cutter) as List<Geometry>;

Polyline leftPolyline = cutGeometries[0] as Polyline;
Polyline rightPolyline = cutGeometries[1] as Polyline;

// leftPolyline.Points[0] = 1, 2
// leftPolyline.Points[1] = 1, 4
// leftPolyline.Points[2] = 2, 4

// rightPolyline.Points.Count = 5
// rightPolyline.Parts.Count = 2

ReadOnlySegmentCollection segments0 = rightPolyline.Parts[0];
// segments0[0].StartCoordinate = 1, 1
// segments0[0].EndCoordinate = 1, 2

ReadOnlySegmentCollection segments1 = rightPolyline.Parts[1];
// segments1.Count = 2
// segments1[0].StartCoordinate = 2, 4
// segments1[0].EndCoordinate = 4, 4
// segments1[1].StartCoordinate = 4, 4
// segments1[1].EndCoordinate = 4, 1

// polygon
Polygon polygon = PolygonBuilderEx.CreatePolygon(list);
isSimple = GeometryEngine.Instance.IsSimpleAsFeature(polygon);
cutGeometries = GeometryEngine.Instance.Cut(polygon, cutter) as List<Geometry>;

按长度致密

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
// densify a line segment
MapPoint startPt = MapPointBuilderEx.CreateMapPoint(1.0, 1.0);
MapPoint endPt = MapPointBuilderEx.CreateMapPoint(1, 21);
LineSegment line = LineBuilderEx.CreateLineSegment(startPt, endPt);
Polyline polyline = PolylineBuilderEx.CreatePolyline(line);

Geometry geom = GeometryEngine.Instance.DensifyByLength(polyline, 2);
Polyline result = geom as Polyline;


// densify a circular arc
MapPoint fromPt = MapPointBuilderEx.CreateMapPoint(2, 1);
MapPoint toPt = MapPointBuilderEx.CreateMapPoint(1, 2);
Coordinate2D interiorPt = new Coordinate2D(1 + Math.Sqrt(2) / 2, 1 + Math.Sqrt(2) / 2);

EllipticArcBuilderEx cab = new EllipticArcBuilderEx(fromPt, toPt, interiorPt);
EllipticArcSegment circularArc = cab.ToSegment();
polyline = PolylineBuilderEx.CreatePolyline(circularArc);
geom = GeometryEngine.Instance.DensifyByLength(polyline, 2);
result = geom as Polyline;

两个多边形之间的差异

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
List<MapPoint> polyPts = new List<MapPoint>();
polyPts.Add(MapPointBuilderEx.CreateMapPoint(3.0, 2.0));
polyPts.Add(MapPointBuilderEx.CreateMapPoint(3.0, 6.0));
polyPts.Add(MapPointBuilderEx.CreateMapPoint(6.0, 6.0));
polyPts.Add(MapPointBuilderEx.CreateMapPoint(6.0, 2.0));

Polygon poly1 = PolygonBuilderEx.CreatePolygon(polyPts);

Envelope env = EnvelopeBuilderEx.CreateEnvelope(MapPointBuilderEx.CreateMapPoint(1.0, 1.0), MapPointBuilderEx.CreateMapPoint(4, 4));
Polygon poly2 = PolygonBuilderEx.CreatePolygon(env);

Geometry result = GeometryEngine.Instance.Difference(poly1, poly2);
Polygon polyResult = result as Polygon;
// polyResult.Area = 10.0

result = GeometryEngine.Instance.Difference(poly2, poly1);
polyResult = result as Polygon;
// polyResult.Area = 7.0

确定两个几何是否不相交

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
//
// pt on pt
//

MapPoint pt = MapPointBuilderEx.CreateMapPoint(1.0, 1.0);
MapPoint pt2 = MapPointBuilderEx.CreateMapPoint(2.0, 2.5);

bool disjoint = GeometryEngine.Instance.Disjoint(pt, pt2); // result is true

MultipointBuilderEx mpb = new MultipointBuilderEx();
mpb.AddPoint(pt);
mpb.AddPoint(pt2);
Multipoint multiPoint = mpb.ToGeometry();

disjoint = GeometryEngine.Instance.Disjoint(multiPoint, pt); // result is false

//
// pt and line
//

List<MapPoint> list = new List<MapPoint>();
list.Add(MapPointBuilderEx.CreateMapPoint(1.0, 1.0));
list.Add(MapPointBuilderEx.CreateMapPoint(3.0, 3.0));
list.Add(MapPointBuilderEx.CreateMapPoint(5.0, 1.0));

Polyline line1 = PolylineBuilderEx.CreatePolyline(list);
disjoint = GeometryEngine.Instance.Disjoint(line1, pt2); // result is true

disjoint = GeometryEngine.Instance.Disjoint(pt2, line1); // result is true

// end pt of line
disjoint = GeometryEngine.Instance.Disjoint(line1, pt); // result is false

//
// pt and polygon
//
List<MapPoint> polyPts = new List<MapPoint>();
polyPts.Add(MapPointBuilderEx.CreateMapPoint(3.0, 2.0));
polyPts.Add(MapPointBuilderEx.CreateMapPoint(3.0, 6.0));
polyPts.Add(MapPointBuilderEx.CreateMapPoint(6.0, 6.0));
polyPts.Add(MapPointBuilderEx.CreateMapPoint(6.0, 2.0));

Polygon poly1 = PolygonBuilderEx.CreatePolygon(polyPts);
disjoint = GeometryEngine.Instance.Disjoint(poly1, pt); // result is true
disjoint = GeometryEngine.Instance.Disjoint(pt, poly1); // result is true

//
// line and line
//

List<MapPoint> list2 = new List<MapPoint>();
list2.Add(MapPointBuilderEx.CreateMapPoint(1.0, 3.0));
list2.Add(MapPointBuilderEx.CreateMapPoint(3.0, 1.0));
list2.Add(MapPointBuilderEx.CreateMapPoint(5.0, 3.0));

Polyline line2 = PolylineBuilderEx.CreatePolyline(list2);
disjoint = GeometryEngine.Instance.Disjoint(line1, line2); // result is false

//
// line and polygon
//
disjoint = GeometryEngine.Instance.Disjoint(poly1, line1); // result is false
disjoint = GeometryEngine.Instance.Disjoint(line1, poly1); // result is false

//
// polygon and polygon
//
Envelope env = EnvelopeBuilderEx.CreateEnvelope(MapPointBuilderEx.CreateMapPoint(1.0, 1.0), MapPointBuilderEx.CreateMapPoint(4, 4));
Polygon poly2 = PolygonBuilderEx.CreatePolygon(env);

disjoint = GeometryEngine.Instance.Disjoint(poly1, poly2); // result is false


// disjoint3D

SpatialReference sr = SpatialReferences.WGS84;

MapPoint pt3D_1 = MapPointBuilderEx.CreateMapPoint(1, 1, 1, sr);
MapPoint pt3D_2 = MapPointBuilderEx.CreateMapPoint(2, 2, 2, sr);
MapPoint pt3D_3 = MapPointBuilderEx.CreateMapPoint(1, 1, 2, sr);

MultipointBuilderEx mpbEx = new MultipointBuilderEx();
mpbEx.AddPoint(pt3D_1);
mpbEx.AddPoint(pt3D_2);
mpbEx.HasZ = true;

multiPoint = mpbEx.ToGeometry();
disjoint = GeometryEngine.Instance.Disjoint3D(multiPoint, pt3D_2); // disjoint = false
disjoint = GeometryEngine.Instance.Disjoint3D(multiPoint, pt3D_3); // disjoint = true

确定两个几何之间的距离

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
MapPoint pt1 = MapPointBuilderEx.CreateMapPoint(1.0, 1.0);
MapPoint pt2 = MapPointBuilderEx.CreateMapPoint(2.0, 2.0);
MapPoint pt3 = MapPointBuilderEx.CreateMapPoint(4.0, 2.0);

//
// pt and pt
//
double d = GeometryEngine.Instance.Distance(pt1, pt2); // d = Math.Sqrt(2)

//
// pt and multipoint
//
List<MapPoint> multiPts = new List<MapPoint>();
multiPts.Add(pt2);
multiPts.Add(pt3);
Multipoint multiPoint = MultipointBuilderEx.CreateMultipoint(multiPts);
d = GeometryEngine.Instance.Distance(pt1, multiPoint); // d = Math.Sqrt(2)

//
// pt and envelope
//
Envelope env = EnvelopeBuilderEx.CreateEnvelope(pt1, pt2);
d = GeometryEngine.Instance.Distance(pt1, env); // d = 0

//
// pt and polyline
//
List<MapPoint> polylinePts = new List<MapPoint>();
polylinePts.Add(MapPointBuilderEx.CreateMapPoint(2.0, 1.0));
polylinePts.Add(pt2);
Polyline polyline = PolylineBuilderEx.CreatePolyline(polylinePts);

d = GeometryEngine.Instance.Distance(pt1, polyline); // d = 1.0

//
// pt and polygon
//
Envelope env2 = EnvelopeBuilderEx.CreateEnvelope(MapPointBuilderEx.CreateMapPoint(3.0, 3.0), MapPointBuilderEx.CreateMapPoint(5.0, 5.0));
Polygon poly = PolygonBuilderEx.CreatePolygon(env2);
d = GeometryEngine.Instance.Distance(pt1, poly); // d = Math.Sqrt(8)

//
// envelope and polyline
//
d = GeometryEngine.Instance.Distance(env, polyline); // d = 0

//
// polyline and polyline
//
List<MapPoint> polylineList = new List<MapPoint>();
polylineList.Add(MapPointBuilderEx.CreateMapPoint(4, 3));
polylineList.Add(MapPointBuilderEx.CreateMapPoint(4, 4));
Polyline polyline2 = PolylineBuilderEx.CreatePolyline(polylineList);

d = GeometryEngine.Instance.Distance(polyline, polyline2); // d = Math.Sqrt(5)


//
// polygon and polygon
//
Polygon poly2 = PolygonBuilderEx.CreatePolygon(env);
d = GeometryEngine.Instance.Distance(poly, poly2); // d = Math.Sqrt(2)

确定两个几何体之间的 3D 距离

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
// between points 
MapPoint pt1 = MapPointBuilderEx.CreateMapPoint(1, 1, 1);
MapPoint pt2 = MapPointBuilderEx.CreateMapPoint(2, 2, 2);
MapPoint pt3 = MapPointBuilderEx.CreateMapPoint(10, 2, 1);

// pt1 to pt2
double d = GeometryEngine.Instance.Distance3D(pt1, pt2); // d = Math.Sqrt(3)

// pt1 to pt3
d = GeometryEngine.Instance.Distance3D(pt1, pt3); // d = Math.Sqrt(82)

// pt2 to pt3
d = GeometryEngine.Instance.Distance3D(pt2, pt3); // d = Math.Sqrt(65)

// intersecting lines

List<MapPoint> list = new List<MapPoint>();
list.Add(MapPointBuilderEx.CreateMapPoint(1.0, 1.0, 1.0));
list.Add(MapPointBuilderEx.CreateMapPoint(3.0, 3.0, 1.0));
list.Add(MapPointBuilderEx.CreateMapPoint(5.0, 1.0, 1.0));

Polyline line1 = PolylineBuilderEx.CreatePolyline(list);

List<MapPoint> list2 = new List<MapPoint>();
list2.Add(MapPointBuilderEx.CreateMapPoint(1.0, 3.0, 1.0));
list2.Add(MapPointBuilderEx.CreateMapPoint(3.0, 1.0, 1.0));
list2.Add(MapPointBuilderEx.CreateMapPoint(5.0, 3.0, 1.0));

Polyline line2 = PolylineBuilderEx.CreatePolyline(list2);

bool intersects = GeometryEngine.Instance.Intersects(line1, line2); // intersects = true
d = GeometryEngine.Instance.Distance3D(line1, line2); // d = 0 (distance is 0 when geomtries intersect)

展开信封

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
Envelope env = EnvelopeBuilderEx.CreateEnvelope(100.0, 100.0, 500.0, 500.0);
// env.HasZ = false

Envelope result = GeometryEngine.Instance.Expand(env, 0.5, 0.5, true);
// result.Center = 300, 300
// result.XMin = 200
// result.YMin = 200
// result.XMax = 400
// result.YMax = 400

result = GeometryEngine.Instance.Expand(env, 100, 200, false);
// result.Center = 300, 300
// result.XMin = 0
// result.YMin = -100
// result.XMax = 600
// result.YMax = 700

try
{
// expand in 3 dimensions
result = GeometryEngine.Instance.Expand(env, 0.5, 0.5, 0.5, true);
}
catch (InvalidOperationException e)
{
// the geometry is not Z-Aware
}

// expand a 3d envelope
MapPoint pt1 = MapPointBuilderEx.CreateMapPoint(100, 100, 100);
MapPoint pt2 = MapPointBuilderEx.CreateMapPoint(200, 200, 200);

env = EnvelopeBuilderEx.CreateEnvelope(pt1, pt2);
// env.HasZ = true

result = GeometryEngine.Instance.Expand(env, 0.5, 0.5, 0.5, true);

// result.Center = 150, 150, 150
// result.XMin = 125
// result.YMin = 125
// result.ZMin = 125
// result.XMax = 175
// result.YMax = 175
// result.ZMax = 175

扩展折线

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
// build a polyline
var polyline = PolylineBuilderEx.CreatePolyline(new[]
{
MapPointBuilderEx.CreateMapPoint(1, 1, 10, 20),
MapPointBuilderEx.CreateMapPoint(0, 0, 10, 20),
MapPointBuilderEx.CreateMapPoint(1, -1, 10, 20)
});

// build the extender line
var extender = PolylineBuilderEx.CreatePolyline(new[]
{
MapPointBuilderEx.CreateMapPoint(2, 2),
MapPointBuilderEx.CreateMapPoint(2, -2),
});

// extend
var result = GeometryEngine.Instance.Extend(polyline, extender, ExtendFlags.KeepEndAttributes);
Polyline extendedLine = result as Polyline;
// result.Parts[0].Points[0] = 2, 2, 10, 20
// result.parts[0].Points[1] = 1, 1, 10, 20
// result.Parts[0].Points[2] = 0, 0, 10, 20
// result.Parts[0].Points[3] = 1, -1, 10, 20
// result.Parts[0].Points[4] = 2, -2, 10, 20

// change the flags
result = GeometryEngine.Instance.Extend(polyline, extender, ExtendFlags.NoEndAttributes);
extendedLine = result as Polyline;
// result.Parts[0].Points[0] = 2, 2, 0
// result.parts[0].Points[1] = 1, 1, 10, 20
// result.Parts[0].Points[2] = 0, 0, 10, 20
// result.Parts[0].Points[3] = 1, -1, 10, 20
// result.Parts[0].Points[4] = 2, -2, 0

// extend
result = GeometryEngine.Instance.Extend(polyline, extender, ExtendFlags.KeepEndAttributes | ExtendFlags.NoExtendAtTo);
extendedLine = result as Polyline;
// result.Parts[0].Points[0] = 2, 2, 10, 20
// result.parts[0].Points[1] = 1, 1, 10, 20
// result.Parts[0].Points[2] = 0, 0, 10, 20
// result.Parts[0].Points[3] = 1, -1, 10, 20

// extend with no intersection

polyline = PolylineBuilderEx.CreatePolyline(new[]
{
MapPointBuilderEx.CreateMapPoint(1, 1),
MapPointBuilderEx.CreateMapPoint(3, 1)
});

extender = PolylineBuilderEx.CreatePolyline(new[]
{
MapPointBuilderEx.CreateMapPoint(1, 4),
MapPointBuilderEx.CreateMapPoint(3, 4)
});

result = GeometryEngine.Instance.Extend(polyline, extender, ExtendFlags.Default);
// result = null

概括

1
2
3
4
5
6
7
8
Polyline generalizedPolyline = GeometryEngine.Instance.Generalize(polylineWithZ, 200) as Polyline;
// generalizedPolyline.HasZ = true

Polygon generalized3DPolyline = GeometryEngine.Instance.Generalize3D(polylineWithZ, 200) as Polygon;
// generalized3DPolyline.HasZ = true

// note that generalized3DPolyline and generalizedPolyline will have different definitions
// ie generalizedPolyline.IsEqual(generalized3DPolyline) = false

计算面的测地线面积

1
2
3
4
5
6
7
8
9
10
11
12
13
var polygon = PolygonBuilderEx.CreatePolygon(new[]
{
MapPointBuilderEx.CreateMapPoint(-10018754.1713946, 10018754.1713946),
MapPointBuilderEx.CreateMapPoint(10018754.1713946, 10018754.1713946),
MapPointBuilderEx.CreateMapPoint(10018754.1713946, -10018754.1713946),
MapPointBuilderEx.CreateMapPoint(-10018754.1713946, -10018754.1713946)
}, SpatialReferences.WebMercator);
var area = GeometryEngine.Instance.GeodesicArea(polygon);

// area is close to 255032810857732.31

area = GeometryEngine.Instance.GeodesicArea(polygon, AreaUnit.SquareKilometers);
// area is close to 255032810.85953,

在指定的测地线距离处创建缓冲区面

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
// buffer a point
MapPoint pt = MapPointBuilderEx.CreateMapPoint(1.0, 1.0, SpatialReferences.WGS84);
Polygon outPolygon = GeometryEngine.Instance.GeodesicBuffer(pt, 5) as Polygon;

double delta = SpatialReferences.WGS84.XYTolerance * 2 * Math.Sqrt(2);
ReadOnlyPointCollection points = outPolygon.Points;
foreach (MapPoint p in points)
{
double d = GeometryEngine.Instance.GeodesicDistance(pt, p);
// d = 5 (+- delta)
}

// specify a unit for the distance
outPolygon = GeometryEngine.Instance.GeodesicBuffer(pt, 5000, LinearUnit.Millimeters) as Polygon;

// buffer of 0 distance produces an empty geometry
Geometry g = GeometryEngine.Instance.GeodesicBuffer(pt, 0);
// g.IsEmpty = true

// buffer many points
List<MapPoint> list = new List<MapPoint>();
list.Add(MapPointBuilderEx.CreateMapPoint(1.0, 1.0, SpatialReferences.WGS84));
list.Add(MapPointBuilderEx.CreateMapPoint(10.0, 20.0));
list.Add(MapPointBuilderEx.CreateMapPoint(40.0, 40.0));
list.Add(MapPointBuilderEx.CreateMapPoint(60.0, 60.0));

outPolygon = GeometryEngine.Instance.GeodesicBuffer(list, 10000) as Polygon;
// outPolygon.PartCount = 4

// buffer different geometry types
List<Coordinate2D> coords = new List<Coordinate2D>()
{
new Coordinate2D(1, 2), new Coordinate2D(10, 20), new Coordinate2D(20, 30),
new Coordinate2D(50, 60), new Coordinate2D(70, 80), new Coordinate2D(80, 40),
new Coordinate2D(90, 10), new Coordinate2D(110, 15), new Coordinate2D(120, 30),
new Coordinate2D(10, 40), new Coordinate2D(-10, 40), new Coordinate2D(-10, 50)
};

List<Geometry> manyGeometries = new List<Geometry>
{
MapPointBuilderEx.CreateMapPoint(1.0, 1.0, SpatialReferences.WGS84),
PolylineBuilderEx.CreatePolyline(new List<Coordinate2D>(){coords[0], coords[1], coords[2]}, SpatialReferences.WGS84),
PolylineBuilderEx.CreatePolyline(new List<Coordinate2D>(){coords[3], coords[4], coords[5]}),
PolygonBuilderEx.CreatePolygon(new List<Coordinate2D>(){coords[9], coords[10], coords[11]})
};

outPolygon = GeometryEngine.Instance.GeodesicBuffer(manyGeometries, 20000) as Polygon;

// specify unit types
outPolygon = GeometryEngine.Instance.GeodesicBuffer(manyGeometries, 20, LinearUnit.Miles) as Polygon;

确定两个几何之间的测地线距离

1
2
3
4
5
6
7
8
var point1 = MapPointBuilderEx.CreateMapPoint(-170, 45, SpatialReferences.WGS84);
var point2 = MapPointBuilderEx.CreateMapPoint(170, 45, SpatialReferences.WGS84);

var distances_meters = GeometryEngine.Instance.GeodesicDistance(point1, point2);
// distance is approximately 1572912.2066940258 in meters

var distance_feet = GeometryEngine.Instance.GeodesicDistance(point1, point2, LinearUnit.Feet);
// distance is approximately 5160473.11904786 in feet

测地线椭圆

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
GeodesicEllipseParameter param = new GeodesicEllipseParameter();
param.AxisDirection = 4 * Math.PI / 3;
param.Center = new Coordinate2D(-120, 60);
param.LinearUnit = LinearUnit.Meters;
param.OutGeometryType = GeometryType.Polyline;
param.SemiAxis1Length = 6500000;
param.SemiAxis2Length = 1500000;
param.VertexCount = 800;

Geometry geometry = GeometryEngine.Instance.GeodesicEllipse(param, SpatialReferences.WGS84);
// geometry.IsEmpty = false

Polyline polyline = geometry as Polyline;
// polyline.PointCount = 801
// polyline.PartCount = 1

确定线的测地线长度

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
var polyline = PolylineBuilderEx.CreatePolyline(new[]
{
MapPointBuilderEx.CreateMapPoint(-10018754.1713946, 10018754.1713946),
MapPointBuilderEx.CreateMapPoint(10018754.1713946, 10018754.1713946)
}, SpatialReferences.WebMercator);

var length = GeometryEngine.Instance.GeodesicLength(polyline);
// length is approx 5243784.5551844323 in meters

length = GeometryEngine.Instance.GeodesicLength(polyline, LinearUnit.Miles);
// length is approx 3258.33666089067 in miles

var polyline2 = GeometryEngine.Instance.Project(polyline, SpatialReferences.WGS84);
length = GeometryEngine.Instance.GeodesicLength(polyline2);
// length is approx 5243784.55518443 in meters after projecting

测地线扇区

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
GeodesicSectorParameter param = new GeodesicSectorParameter();
param.ArcVertexCount = 50;
param.AxisDirection = Math.PI / 4;
param.Center = new Coordinate2D(0, 0);
param.LinearUnit = LinearUnit.Meters;
param.OutGeometryType = GeometryType.Polygon;
param.RadiusVertexCount = 10;
param.SectorAngle = 5 * Math.PI / 3;
param.SemiAxis1Length = 100000;
param.SemiAxis2Length = 20000;
param.StartDirection = 11 * Math.PI / 6;

Geometry geometry = GeometryEngine.Instance.GeodesicSector(param, SpatialReferences.WGS84);
// geometry.IsEmpty = false

Polygon polygon = geometry as Polygon;
// polygon.PointCount = 68
// polygon.PartCount = 1

大地测量致密化偏差 - 折线

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
List<Coordinate2D> coords = new List<Coordinate2D>()
{
new Coordinate2D(-80, 0),
new Coordinate2D(-20, 60),
new Coordinate2D(40, 20),
new Coordinate2D(0, -20),
new Coordinate2D(-80, 0)
};

SpatialReference sr = SpatialReferences.WGS84;

// create a polyline
Polyline polyline = PolylineBuilderEx.CreatePolyline(coords, sr);

// densify in km
Polyline geodesicPolyline = GeometryEngine.Instance.GeodeticDensifyByDeviation(polyline, 200, LinearUnit.Kilometers, GeodeticCurveType.Geodesic) as Polyline;
// densify in m
geodesicPolyline = GeometryEngine.Instance.GeodeticDensifyByDeviation(polyline, 200, LinearUnit.Meters, GeodeticCurveType.Geodesic) as Polyline;

// Change curve type to Loxodrome
Polyline loxodromePolyline = GeometryEngine.Instance.GeodeticDensifyByDeviation(polyline, 200, LinearUnit.Meters, GeodeticCurveType.Loxodrome) as Polyline;

大地测量致密按长度 - 多边形

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
List<Coordinate2D> coords = new List<Coordinate2D>()
{
new Coordinate2D(-80, 0),
new Coordinate2D(-20, 60),
new Coordinate2D(40, 20),
new Coordinate2D(0, -20),
new Coordinate2D(-80, 0)
};

SpatialReference sr = SpatialReferences.WGS84;

// create a polygon
Polygon polygon = PolygonBuilderEx.CreatePolygon(coords, sr);

// get the geodesic lengths of the polygon segments
ReadOnlySegmentCollection segments = polygon.Parts[0];
List<Double> geoLengths = new List<Double>(segments.Count);
foreach (Segment s in segments)
{
Polyline line = PolylineBuilderEx.CreatePolyline(s, sr);
double geoLen = GeometryEngine.Instance.GeodesicLength(line);
geoLengths.Add(geoLen);
}

// find the max length
geoLengths.Sort();
double maxLen = geoLengths[geoLengths.Count - 1];

// densify the polygon (in meters)
Polygon densifiedPoly = GeometryEngine.Instance.GeodeticDensifyByLength(polygon, maxLen, LinearUnit.Meters, GeodeticCurveType.Geodesic) as Polygon;

// densify the polygon (in km)
double maxSegmentLength = maxLen / 10000;
densifiedPoly = GeometryEngine.Instance.GeodeticDensifyByLength(polygon, maxSegmentLength, LinearUnit.Kilometers, GeodeticCurveType.Geodesic) as Polygon;

计算大地测量距离,两点之间的方位角

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
SpatialReference sr = SpatialReferences.WGS84;

MapPoint p1 = MapPointBuilderEx.CreateMapPoint(111, 55, sr);
MapPoint p2 = MapPointBuilderEx.CreateMapPoint(95.5845, 64.2285, sr);

double distance, az12, az21;

distance = GeometryEngine.Instance.GeodeticDistanceAndAzimuth(p1, p2, GeodeticCurveType.Geodesic, out az12, out az21);
// distance - 1339728.0303777338
// az12 - 326.235780421405
// az21 - 132.87425637913955

distance = GeometryEngine.Instance.GeodeticDistanceAndAzimuth(p1, p2, GeodeticCurveType.Loxodrome, out az12, out az21);
// distance - 1342745.9687172563
// az12 - 319.966400332104
// az21- 139.96640033210397

distance = GeometryEngine.Instance.GeodeticDistanceAndAzimuth(p1, p2, GeodeticCurveType.GreatElliptic, out az12, out az21);
// distance - 1339728.038837946
// az12 - 326.22479262335418
// az21 - 132.88558894347742



MapPoint p3 = MapPointBuilderEx.CreateMapPoint(0, 0, sr);
MapPoint p4 = MapPointBuilderEx.CreateMapPoint(1, 0, sr);

distance = GeometryEngine.Instance.GeodeticDistanceAndAzimuth(p3, p4, GeodeticCurveType.Geodesic, out az12, out az21);
// distance - 111319.49079327342
// az12 - 90
// az21 - 270

distance = GeometryEngine.Instance.GeodeticDistanceAndAzimuth(p3, p4, GeodeticCurveType.Geodesic, LinearUnit.Miles, out az12, out az21);
// distance - 69.1707247134693
// az12 - 90
// az21 - 270

对一组地图点执行大地测量移动

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
SpatialReference sr = SpatialReferences.WebMercator;
var points = new[] { MapPointBuilderEx.CreateMapPoint(0, 0, sr) };
double distance = 10;
double azimuth = Math.PI / 2;
var resultPoints = GeometryEngine.Instance.GeodeticMove(points, sr, distance, LinearUnit.Meters, azimuth, GeodeticCurveType.Geodesic);

// resultPoints.First().X = 10
// resultPoints.First().Y = 0
// resultPoints.First().SpatialReference.Wkid = sr.Wkid

// Change LinearUnit to Miles
resultPoints = GeometryEngine.Instance.GeodeticMove(points, sr, distance, LinearUnit.Miles, azimuth, GeodeticCurveType.Geodesic);
// resultPoints.First().X = 16093.44
// resultPoints.First().Y = 0

// Change curve type
resultPoints = GeometryEngine.Instance.GeodeticMove(points, sr, distance, LinearUnit.Miles, azimuth, GeodeticCurveType.Loxodrome);
// resultPoints.First().X = 16093.44
// resultPoints.First().Y = 0

检索坐标系

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
// get all the geographic coordinate systems
IReadOnlyList<CoordinateSystemListEntry> gcs_list = GeometryEngine.Instance.GetPredefinedCoordinateSystemList(CoordinateSystemFilter.GeographicCoordinateSystem);

// get the projected coordinate systems
IReadOnlyList<CoordinateSystemListEntry> proj_list = GeometryEngine.Instance.GetPredefinedCoordinateSystemList(CoordinateSystemFilter.ProjectedCoordinateSystem);

// get the vertical coordinate systems
IReadOnlyList<CoordinateSystemListEntry> vert_list = GeometryEngine.Instance.GetPredefinedCoordinateSystemList(CoordinateSystemFilter.VerticalCoordinateSystem);

// get geographic and projected coordinate systems
IReadOnlyList<CoordinateSystemListEntry> combined_list = GeometryEngine.Instance.GetPredefinedCoordinateSystemList(CoordinateSystemFilter.GeographicCoordinateSystem | CoordinateSystemFilter.ProjectedCoordinateSystem);

// investigate one of the entries
CoordinateSystemListEntry entry = gcs_list[0];
int wkid = entry.Wkid;
string category = entry.Category;
string name = entry.Name;

检索系统地理变换

1
2
3
4
5
6
7
8
9
10
// a geographic transformation is the definition of how to project from one spatial reference to another
IReadOnlyList<GeographicTransformationListEntry> list = GeometryEngine.Instance.GetPredefinedGeographicTransformationList();

// a GeographicTransformationListEntry consists of Name, Wkid, the From SpatialReference Wkid, the To SpatialReference Wkid
GeographicTransformationListEntry entry = list[0];

int fromWkid = entry.FromSRWkid;
int toWkid = entry.ToSRWkid;
int wkid = entry.Wkid;
string name = entry.Name;

获取折线或多边形的子曲线

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
SpatialReference sr = SpatialReferences.WGS84;

List<Coordinate2D> coords = new List<Coordinate2D>()
{
new Coordinate2D(-111, 72),
new Coordinate2D(-108, 68),
new Coordinate2D(-114, 68)
};

Polyline polyline = PolylineBuilderEx.CreatePolyline(coords, sr);

Polyline subCurve = GeometryEngine.Instance.GetSubCurve(polyline, 0, 5, AsRatioOrLength.AsLength);
// subCurve.PartCount = 1
// subCurve.PointCount = 2

ReadOnlyPointCollection points = subCurve.Points;
// points[0] = -111, 72
// points[1] = -108, 68

subCurve = GeometryEngine.Instance.GetSubCurve(polyline, 0, 0.5, AsRatioOrLength.AsRatio);
// subCurve.PointCount = 3

points = subCurve.Points;
// points[0] = -111, 72
// points[1] = -108, 68
// points[2] = -108.5, 68


List<Coordinate3D> coords3D = new List<Coordinate3D>()
{
new Coordinate3D(0, 0, 0),
new Coordinate3D(0, 1, 1),
new Coordinate3D(1, 1, 2),
new Coordinate3D(1, 0, 3)
};

Polygon polygon = PolygonBuilderEx.CreatePolygon(coords3D, sr);

subCurve = GeometryEngine.Instance.GetSubCurve3D(polygon, 0, 1, AsRatioOrLength.AsLength);
// subCurve.HasZ = true

points = subCurve.Points;
// points.Count = 2
// points[0] = 0, 0, 0
// points[1] = 0, 0.70710678118654746, 0.70710678118654746

图形缓冲区

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
// mitered join and butt caps
SpatialReference sr = SpatialReferenceBuilder.CreateSpatialReference(102010);
List<Coordinate2D> coords = new List<Coordinate2D>()
{
new Coordinate2D(1400,6200),
new Coordinate2D(1600,6300),
new Coordinate2D(1800,6200)
};

Polyline polyline = PolylineBuilderEx.CreatePolyline(coords, sr);

Polygon polygon = GeometryEngine.Instance.GraphicBuffer(polyline, 50, LineJoinType.Miter, LineCapType.Butt, 10, 0, -1) as Polygon;

// bevelled join and round caps
Envelope envelope = EnvelopeBuilderEx.CreateEnvelope(0, 0, 10000, 10000, SpatialReferences.WebMercator);

Polygon outPolygon = GeometryEngine.Instance.GraphicBuffer(envelope, 1000, LineJoinType.Bevel, LineCapType.Round, 4, 0, 96) as Polygon;

图形缓冲器很多

1
2
3
4
5
6
7
// round join and round caps
MapPoint point1 = MapPointBuilderEx.CreateMapPoint(0, 0);
MapPoint point2 = MapPointBuilderEx.CreateMapPoint(1, 1, SpatialReferences.WGS84);
MapPoint point3 = MapPointBuilderEx.CreateMapPoint(1000000, 1200000, SpatialReferences.WebMercator);
List<MapPoint> points = new List<MapPoint>() { point1, point2, point3 };

IReadOnlyList<Geometry> geometries = GeometryEngine.Instance.GraphicBuffer(points, 5, LineJoinType.Round, LineCapType.Round, 0, 0, 3000);

两条折线之间的交点

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
// determine intersection between two polylines

List<MapPoint> pts = new List<MapPoint>();
pts.Add(MapPointBuilderEx.CreateMapPoint(1.0, 1.0));
pts.Add(MapPointBuilderEx.CreateMapPoint(3.0, 3.0));
pts.Add(MapPointBuilderEx.CreateMapPoint(5.0, 1.0));

Polyline line1 = PolylineBuilderEx.CreatePolyline(pts);

List<MapPoint> pts2 = new List<MapPoint>();
pts2.Add(MapPointBuilderEx.CreateMapPoint(1.0, 3.0));
pts2.Add(MapPointBuilderEx.CreateMapPoint(3.0, 1.0));
pts2.Add(MapPointBuilderEx.CreateMapPoint(5.0, 3.0));

Polyline line2 = PolylineBuilderEx.CreatePolyline(pts2);

bool intersects = GeometryEngine.Instance.Intersects(line1, line2); // intersects = true
Geometry g = GeometryEngine.Instance.Intersection(line1, line2, GeometryDimensionType.EsriGeometry0Dimension);
Multipoint resultMultipoint = g as Multipoint;

// result is a multiPoint that intersects at (2,2) and (4,2)

两个多边形之间的交点

1
2
3
4
5
6
7
8
9
// determine intersection between two polygons

Envelope env1 = EnvelopeBuilderEx.CreateEnvelope(new Coordinate2D(3.0, 2.0), new Coordinate2D(6.0, 6.0));
Polygon poly1 = PolygonBuilderEx.CreatePolygon(env1);

Envelope env2 = EnvelopeBuilderEx.CreateEnvelope(new Coordinate2D(1.0, 1.0), new Coordinate2D(4.0, 4.0));
Polygon poly2 = PolygonBuilderEx.CreatePolygon(env2);

Polygon polyResult = GeometryEngine.Instance.Intersection(poly1, poly2) as Polygon;

确定多边形的标注点

1
2
3
4
5
6
7
8
9
10
// create a polygon
List<Coordinate2D> list2D = new List<Coordinate2D>();
list2D.Add(new Coordinate2D(1.0, 1.0));
list2D.Add(new Coordinate2D(1.0, 2.0));
list2D.Add(new Coordinate2D(2.0, 2.0));
list2D.Add(new Coordinate2D(2.0, 1.0));

Polygon polygon = PolygonBuilderEx.CreatePolygon(list2D);
bool isSimple = GeometryEngine.Instance.IsSimpleAsFeature(polygon);
MapPoint pt = GeometryEngine.Instance.LabelPoint(polygon);

确定线的长度,长度3D

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
MapPoint c1 = MapPointBuilderEx.CreateMapPoint(1, 2, 3);
MapPoint c2 = MapPointBuilderEx.CreateMapPoint(4, 2, 4);

// line segment
LineSegment line = LineBuilderEx.CreateLineSegment(c1, c2);
double len = line.Length; // = 3
double len3D = line.Length3D; // = Math.Sqrt(10)

// polyline
Polyline p = PolylineBuilderEx.CreatePolyline(line);
double p_len = p.Length; // = len = 3
double p_len3D = p.Length3D; // = len3D = Math.Sqrt(10)

double ge_len = GeometryEngine.Instance.Length(p); // = p_len = len = 3
double ge_len3d = GeometryEngine.Instance.Length3D(p); // = p_len3D = len3D = Math.Sqrt(10)

获取最小和最大 M 值 - GetMinMaxM

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
string json = "{\"hasM\":true,\"rings\":[[[-3000,-2000,10],[-2000,-2000,15],[-1000,-2000,20],[0,-2000,0],[1000,-2000,-20],[2000,-2000,-30],[3000,-2000,10],[4000,-2000,5]]],\"spatialReference\":{\"wkid\":3857}}";
Polygon polygon = PolygonBuilderEx.FromJson(json);

double minM, maxM;
GeometryEngine.Instance.GetMinMaxM(polygon, out minM, out maxM);
// minM = -30
// maxM = 20

json = "{\"hasM\":true,\"paths\":[[[-3000,-2000,10],[-2000,-2000,null],[-1000,-2000,null]]]}";
Polyline polyline = PolylineBuilderEx.FromJson(json);

GeometryEngine.Instance.GetMinMaxM(polyline, out minM, out maxM);
// minM = 10
// maxM = 10

json = "{\"hasM\":true,\"paths\":[[[-3000,-2000,null],[-2000,-2000,null],[-1000,-2000,null]]]}";
polyline = PolylineBuilderEx.FromJson(json);

GeometryEngine.Instance.GetMinMaxM(polyline, out minM, out maxM);
// minM = double.Nan
// maxM = double.Nan

确定 M 是单调的,是升序还是降序 - GetMMonotonic

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
string json = "{\"hasM\":true,\"paths\":[[[-3000,-2000,10],[-2000,-2000,15],[-1000,-2000,20]]]}";
Polyline polyline = PolylineBuilderEx.FromJson(json);

MonotonicType monotonic = GeometryEngine.Instance.GetMMonotonic(polyline);
// monotonic = Monotonic.Ascending

json = "{\"hasM\":true,\"paths\":[[[-3000,-2000,10],[-2000,-2000,5],[-1000,-2000,0]]]}";
polyline = PolylineBuilderEx.FromJson(json);

monotonic = GeometryEngine.Instance.GetMMonotonic(polyline);
// monotonic = Monotonic.Descending

json = "{\"hasM\":true,\"paths\":[[[-3000,-2000,10],[-2000,-2000,15],[-1000,-2000,0]]]}";
polyline = PolylineBuilderEx.FromJson(json);

monotonic = GeometryEngine.Instance.GetMMonotonic(polyline);
// monotonic = Monotonic.NotMonotonic

获取与几何图形中指定 M 值出现的位置相对应的多点 - GetPointsAtM

1
2
3
4
5
6
7
8
9
string json = "{\"hasM\":true,\"paths\":[[[-3000,-2000,10],[-2000,-2000,15],[-1000,-2000,20],[0,-2000,0],[1000,-2000,20],[2000,-2000,30],[3000,-2000,10],[4000,-2000,5]]],\"spatialReference\":{\"wkid\":3857}}";
Polyline polyline = PolylineBuilderEx.FromJson(json);

Multipoint multipoint = GeometryEngine.Instance.GetPointsAtM(polyline, 10, 500);
// multiPoint.PointCount = 4
// multipoint.Points[0] X= -3000, Y= -2500 M= 10
// multipoint.Points[1] X= -500, Y= -2500 M= 10
// multipoint.Points[2] X= 500, Y= -2500 M= 10
// multipoint.Points[3] X= 3000, Y= -2500 M= 10

获取与指定 M 值之间的子曲线对应的折线 - GetSubCurveBetweenMs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
string json = "{\"hasM\":true,\"paths\":[[[-2000,0,1],[-1000,1000,2],[-1000,0,3],[1000,1000,4],[2000,1000,5],[2000,2000,6],[3000,2000,7],[4000,0,8]]],\"spatialReference\":{\"wkid\":3857}}";
Polyline polyline = PolylineBuilderEx.FromJson(json);

Polyline subCurve = GeometryEngine.Instance.GetSubCurveBetweenMs(polyline, 2, 6);
// subCurve.PointCount = 5
// subCurve.Points[0] X= --1000, Y= 1000 M= 2
// subCurve.Points[1] X= --1000, Y= 0 M= 3
// subCurve.Points[2] X= 1000, Y= 1000 M= 4
// subCurve.Points[3] X= 2000, Y= -1000 M= 5
// subCurve.Points[4] X= 2000, Y= -2000 M= 6

subCurve = GeometryEngine.Instance.GetSubCurveBetweenMs(polyline, double.NaN, 5);
// subCurve.PointCount = 0
// subCurve.IsEmpty = true

获取与沿几何图形中出现指定 M 值的位置处的法线对应的线段 - GetNormalsAtM

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
IList<MapPoint> inPoints = new List<MapPoint>()
{
MapPointBuilderEx.CreateMapPoint(-3000, -2000, 0, 100),
MapPointBuilderEx.CreateMapPoint(-3000, 0, 0, 200),
MapPointBuilderEx.CreateMapPoint(-1000, 0, 0, 300),
MapPointBuilderEx.CreateMapPoint(-1000, 2000, 0, 100),
MapPointBuilderEx.CreateMapPoint(3000, 2000, 0, 200),
MapPointBuilderEx.CreateMapPoint(3000, 0, 0, 300),
MapPointBuilderEx.CreateMapPoint(1000, 0, 0, 100),
MapPointBuilderEx.CreateMapPoint(1000, -2000, 0, 200),
MapPointBuilderEx.CreateMapPoint(-3000, -2000, 0, 300)
};

Polygon polygon = PolygonBuilderEx.CreatePolygon(inPoints);
// polygon.HasM = true

Polyline polyline = GeometryEngine.Instance.GetNormalsAtM(polygon, 150, 100);
// polyline.PartCount = 5
// polyline.PointCount = 10
// polyline.HasM = false

ReadOnlyPartCollection parts = polyline.Parts;
ReadOnlySegmentCollection segments = parts[0];
LineSegment line = segments[0] as LineSegment;
// line.StartCoordinate = (-3000, -1000)
// line.EndCoordinate = (-2900, -1000)

segments = parts[1];
line = segments[0] as LineSegment;
// line.StartCoordinate = (-1000, 1500)
// line.EndCoordinate = (-900, 1500)

segments = parts[2];
line = segments[0] as LineSegment;
// line.StartCoordinate = (1000, 2000)
// line.EndCoordinate = (1000, 1900)

segments = parts[3];
line = segments[0] as LineSegment;
// line.StartCoordinate = (1500, 0)
// line.EndCoordinate = (1500, 100)

segments = parts[4];
line = segments[0] as LineSegment;
// line.StartCoordinate = (1000, -1000)
// line.EndCoordinate = (900, -1000)

获取沿多部分的指定距离处的 M 值

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
string json = "{\"hasM\":true,\"paths\":[[[-3000,-2000,-3],[-2000,-2000,-2]],[[-2000,-2000,1],[-2000,1000,2]]],\"spatialReference\":{\"wkid\":3857}}";
Polyline polyline = PolylineBuilderEx.FromJson(json);

// polyline has 2 parts

double m1, m2;
GeometryEngine.Instance.GetMsAtDistance(polyline, 0, AsRatioOrLength.AsLength, out m1, out m2);
// m1 = -3
// m2 = NaN

GeometryEngine.Instance.GetMsAtDistance(polyline, 500, AsRatioOrLength.AsLength, out m1, out m2);
// m1 = -2.5
// m2 = NaN

GeometryEngine.Instance.GetMsAtDistance(polyline, 1000, AsRatioOrLength.AsLength, out m1, out m2);
// m1 = -2
// m2 = 1 // m2 has a value because distance 1000 is at the end of the first part, beginning of the second part

将 M 值设置为从多部分开始的累积长度 - SetMsAsDistance

1
2
3
4
5
6
string json = "{\"hasM\":true,\"rings\":[[[0,0],[0,3000],[4000,3000],[4000,0],[0,0]]],\"spatialReference\":{\"wkid\":3857}}";
Polygon polygon = PolygonBuilderEx.FromJson(json);

Polygon outPolygon = GeometryEngine.Instance.SetMsAsDistance(polygon, AsRatioOrLength.AsLength) as Polygon;
ReadOnlyPointCollection outPoints = outPolygon.Points;
// outPoints M values are { 0, 3000, 7000, 10000, 14000 };

在给定距离处插入 M 值 - 插入距离

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
string json = "{\"hasM\":true,\"paths\":[[[-3000,-2000,-3],[-2000,-2000,-2],[-1000,-2000,null]]]}";
Polyline polyline = PolylineBuilderEx.FromJson(json);
bool splitHappened;
int partIndex, segmentIndex;

// A point already exists at the given distance
double m = -1;
double distance = 2000;
bool createNewPart = false;
Polyline outputPolyline = GeometryEngine.Instance.InsertMAtDistance(polyline, m, distance, AsRatioOrLength.AsLength, createNewPart, out splitHappened, out partIndex, out segmentIndex) as Polyline;

// splitHappened = false, partIndex = 0, segmentIndex = 2
// outputPolyline.Points[2].M = -1

json = "{\"hasM\":true,\"paths\":[[[-3000,-2000,-3],[-2000,-2000,-2],[-1000,-2000,-1]],[[0,0,0],[0,1000,0],[0,2000,2]]],\"spatialReference\":{\"wkid\":3857}}";
polyline = PolylineBuilderEx.FromJson(json);

// A point already exists at the given distance, but createNewPart = true
m = 1;
distance = 3000;
createNewPart = true;
outputPolyline = GeometryEngine.Instance.InsertMAtDistance(polyline, m, distance, AsRatioOrLength.AsLength, createNewPart, out splitHappened, out partIndex, out segmentIndex) as Polyline;
string outputJson = outputPolyline.ToJson();

// splitHappened = true, partIndex = 2, segmentIndex = 0
// outputJson = {"hasM":true,"paths":[[[-3000,-2000,-3],[-2000,-2000,-2],[-1000,-2000,-1]],[[0,0,0],[0,1000,1]],[[0,1000,1],[0,2000,2]]]}}
// A new part has been created and the M values for outputPolyline.Points[4] and outputPolyline.Points[5] have been modified

// A point does not exist at the given distance
m = 1;
distance = 3500;
createNewPart = false;
outputPolyline = GeometryEngine.Instance.InsertMAtDistance(polyline, m, distance, AsRatioOrLength.AsLength, createNewPart, out splitHappened, out partIndex, out segmentIndex) as Polyline;
outputJson = outputPolyline.ToJson();

// splitHappened = true even though createNewPart = false because a new point was created
// partIndex = 1, segmentIndex = 2
// outputJson = {"hasM":true,"paths":[[[-3000,-2000,-3],[-2000,-2000,-2],[-1000,-2000,-1]],[[0,0,0],[0,1000,0],[0,1500,1],[0,2000,2]]]}
// A new point has been inserted (0, 1500, 1) by interpolating the X and Y coordinates and M value set to the input M value.

使用输入点的 M 值校准 M 值 - CalibrateByMs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
string json = "{\"hasM\":true,\"paths\":[[[0,0,-1],[1,0,0],[1,1,1],[1,2,2],[3,1,3],[5,3,4],[9,5,5],[7,6,6]]],\"spatialReference\":{\"wkid\":4326}}";
Polyline polyline = PolylineBuilderEx.FromJson(json);

// Interpolate using points (0, 0, 17), (1, 0, 42), (7, 6, 18)
List<MapPoint> updatePoints = new List<MapPoint>(3);
MapPointBuilderEx builder = new MapPointBuilderEx(0, 0);
builder.M = 17;
updatePoints.Add(builder.ToGeometry() as MapPoint);

builder.X = 1;
builder.M = 42;
updatePoints.Add(builder.ToGeometry() as MapPoint);

builder.X = 7;
builder.Y = 6;
builder.M = 18;
updatePoints.Add(builder.ToGeometry() as MapPoint);

// Calibrate all the points in the polyline
double cutOffDistance = polyline.Length;

Polyline updatedPolyline = GeometryEngine.Instance.CalibrateByMs(polyline, updatePoints, UpdateMMethod.Interpolate, cutOffDistance) as Polyline;
// The points in the updated polyline are
// (0, 0, 17 ), ( 1, 0, 42 ), ( 1, 1, 38 ), ( 1, 2, 34 ), ( 3, 1, 30 ), ( 5, 3, 26 ), ( 9, 5, 22 ), ( 7, 6, 18 )

// ExtrapolateBefore using points (1, 2, 42), (9, 5, 18)
builder.X = 1;
builder.Y = 2;
builder.M = 42;
updatePoints[0] = builder.ToGeometry() as MapPoint;

builder.X = 9;
builder.Y = 5;
builder.M = 18;
updatePoints[1] = builder.ToGeometry() as MapPoint;

updatePoints.RemoveAt(2);

updatedPolyline = GeometryEngine.Instance.CalibrateByMs(polyline, updatePoints, UpdateMMethod.ExtrapolateBefore, cutOffDistance) as Polyline;
// The points in the updated polyline are
// ( 0, 0, 66 ), ( 1, 0, 58 ), ( 1, 1, 50 ), ( 1, 2, 42 ), ( 3, 1, 3 ), ( 5, 3, 4 ), ( 9, 5, 18 ), ( 7, 6, 6 )

// ExtrapolateAfter using points (0, 0, 17), (1, 2, 42)
builder.X = 0;
builder.Y = 0;
builder.M = 17;
updatePoints.Insert(0, builder.ToGeometry() as MapPoint);

updatePoints.RemoveAt(2);

updatedPolyline = GeometryEngine.Instance.CalibrateByMs(polyline, updatePoints, UpdateMMethod.ExtrapolateAfter, cutOffDistance) as Polyline;
// The points in the updated polyline are
// ( 0, 0, 17 ), ( 1, 0, 0 ), ( 1, 1, 1 ), ( 1, 2, 42 ), ( 3, 1, 50.333333333333333 ), ( 5, 3, 58.666666666666671 ), ( 9, 5, 67 ), ( 7, 6, 75.333333333333343 )

// ExtrapolateAfter and Interpolate using points (0, 0, 17), (1, 2, 42)
updatedPolyline = GeometryEngine.Instance.CalibrateByMs(polyline, updatePoints, UpdateMMethod.ExtrapolateAfter | UpdateMMethod.Interpolate, cutOffDistance) as Polyline;
// The points in the updated polyline are
// (0,0,17),(1,0,25.333333333333336),(1,1,33.666666666666671),(1,2,42),(3,1,50.333333333333336),(5,3,58.666666666666671),(9,5,67),(7,6,75.333333333333343)

通过对一系列点进行线性插值生成 M 值 - 插值MsBetween

1
2
3
4
5
6
7
string json = "{\"hasM\":true,\"paths\":[[[0,0,-1],[1,0,0],[1,1,1],[1,2,2],[3,1,3],[5,3,4],[9,5,5],[7,6,6]]],\"spatialReference\":{\"wkid\":4326}}";
Polyline polyline = PolylineBuilderEx.FromJson(json);

// Interpolate between points 2 and 6
Polyline outPolyline = GeometryEngine.Instance.InterpolateMsBetween(polyline, 0, 2, 0, 6) as Polyline;
// The points of the output polyline are
// (0, 0, -1), (1, 0, 0), (1, 1, 1), (1, 2, 1.3796279833912741), (3, 1, 2.2285019604153242), (5, 3, 3.3022520459518998), (9, 5, 5), (7, 6, 6)

在几何图形的开头和结尾设置 Ms,并在两个值之间插值 M 值 - SetAndIntervalateMsBetween

1
2
3
4
5
6
string json = "{\"hasM\":true,\"paths\":[[[-3000,-2000],[-2000,-2000],[-1000,-2000],[0,-2000],[1000,-2000],[2000,-2000],[3000,-2000],[4000,-2000]]],\"spatialReference\":{\"wkid\":3857}}";
Polyline polyline = PolylineBuilderEx.FromJson(json);

Polyline outPolyline = GeometryEngine.Instance.SetAndInterpolateMsBetween(polyline, 100, 800) as Polyline;
ReadOnlyPointCollection outPoints = outPolyline.Points;
// outPoints M values are { 100, 200, 300, 400, 500, 600, 700, 800 };

移动地图点

1
2
3
MapPoint pt = MapPointBuilderEx.CreateMapPoint(1.0, 3.0);
MapPoint ptResult = GeometryEngine.Instance.Move(pt, -3.5, 2.5) as MapPoint;
// ptResult is (-2.5, 5.5)

移动 z 感知地图点

1
2
3
MapPoint zPt = MapPointBuilderEx.CreateMapPoint(1.0, 3.0, 2.0);
MapPoint zPtResult = GeometryEngine.Instance.Move(zPt, 4, 0.25, 0.5) as MapPoint;
// zPtResult is (5.0, 3.25, 2.5);

移动折线

1
2
3
4
5
6
7
8
9
10
11
12
13
14
List<MapPoint> pts = new List<MapPoint>();
pts.Add(MapPointBuilderEx.CreateMapPoint(1.0, 1.0, 3.0));
pts.Add(MapPointBuilderEx.CreateMapPoint(3.0, 3.0, 3.0));
pts.Add(MapPointBuilderEx.CreateMapPoint(3, 2, 3.0));
pts.Add(MapPointBuilderEx.CreateMapPoint(4.0, 2.0, 3.0));

Polyline polyline = PolylineBuilderEx.CreatePolyline(pts);

Geometry geometry = GeometryEngine.Instance.Move(polyline, 3, 2);
Polyline polylineResult = geometry as Polyline;
// polylineResult.Points[0] = 4.0, 3.0, 3.0
// polylineResult.Points[1] = 6.0, 5.0, 3.0
// polylineResult.Points[2] = 6.0, 4.0, 3.0
// polylineResult.Points[3] = 7.0, 4.0, 3.0

移动点沿线

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
LineSegment line = LineBuilderEx.CreateLineSegment(MapPointBuilderEx.CreateMapPoint(0, 3), MapPointBuilderEx.CreateMapPoint(5.0, 3.0));
Polyline polyline = PolylineBuilderEx.CreatePolyline(line);
bool simple = GeometryEngine.Instance.IsSimpleAsFeature(polyline);

// ratio = false
MapPoint pt = GeometryEngine.Instance.MovePointAlongLine(polyline, 1.0, false, 0.0, SegmentExtensionType.NoExtension);
// pt = 1.0, 3.0

pt = GeometryEngine.Instance.MovePointAlongLine(polyline, 1.0, false, -1.0, SegmentExtensionType.NoExtension);
// pt = 1.0, 4.0

pt = GeometryEngine.Instance.MovePointAlongLine(polyline, 1.0, false, 2.0, SegmentExtensionType.NoExtension);
// pt = 1.0, 1.0

// ratio = true
pt = GeometryEngine.Instance.MovePointAlongLine(polyline, 0.5, true, 0, SegmentExtensionType.NoExtension);
// pt = 2.5, 3.0

// move past the line
pt = GeometryEngine.Instance.MovePointAlongLine(polyline, 7, false, 0, SegmentExtensionType.NoExtension);
// pt = 5.0, 3.0

// move past the line with extension at "to" point
pt = GeometryEngine.Instance.MovePointAlongLine(polyline, 7, false, 0, SegmentExtensionType.ExtendEmbeddedAtTo);
// pt = 7.0, 3.0

// negative distance with extension at "from" point
pt = GeometryEngine.Instance.MovePointAlongLine(polyline, -2, false, 0, SegmentExtensionType.ExtendEmbeddedAtFrom);
// pt = -2.0, 3.0

// ratio = true
pt = GeometryEngine.Instance.MovePointAlongLine(polyline, 0.5, true, 0, SegmentExtensionType.NoExtension);
// pt = 2.5, 3.0

// line with Z
List<Coordinate3D> coords3D = new List<Coordinate3D> { new Coordinate3D(0, 0, 0), new Coordinate3D(1113195, 1118890, 5000) };
Polyline polylineZ = PolylineBuilderEx.CreatePolyline(coords3D, SpatialReferences.WebMercator);
// polylineZ.HasZ = true

// ratio = true, no offset
pt = GeometryEngine.Instance.MovePointAlongLine(polylineZ, 0.5, true, 0, SegmentExtensionType.NoExtension);
// pt.X = 556597.5
// pt.Y = 559445
// pt.Z = 2500

// ratio = true, past the line with "to" extension, no offset
pt = GeometryEngine.Instance.MovePointAlongLine(polylineZ, 1.5, true, 0, SegmentExtensionType.ExtendEmbeddedAtTo);
// pt.X = 1669792.5
// pt.Y = 1678335
// pt.Z = 7500

// ratio = true, negative distance past the line with no extension, no offset
pt = GeometryEngine.Instance.MovePointAlongLine(polylineZ, -1.5, true, 0, SegmentExtensionType.NoExtension);
// pt.X = 0
// pt.Y = 0
// pt.Z = -7500

// polyline with Z but 2d distance = 0
MapPoint pt3 = MapPointBuilderEx.CreateMapPoint(5, 5, 0);
MapPoint pt4 = MapPointBuilderEx.CreateMapPoint(5, 5, 10);
List<MapPoint> pts = new List<MapPoint>() { pt3, pt4 };

polyline = PolylineBuilderEx.CreatePolyline(pts);
// polyline.HasZ = true
// polyline.Length3D = 10
// polyline.Length = 0

MapPoint result = GeometryEngine.Instance.MovePointAlongLine(polyline, 2, false, 0, SegmentExtensionType.NoExtension);
// result = 5, 5, 2

// polyline with length2d = 0 and length3d = 0
MapPoint pt5 = MapPointBuilderEx.CreateMapPoint(5, 5, 10);
MapPoint pt6 = MapPointBuilderEx.CreateMapPoint(5, 5, 10);
pts.Clear();
pts.Add(pt5);
pts.Add(pt6);

polyline = PolylineBuilderEx.CreatePolyline(pts);
// polyline.HasZ = true
// polyline.Length3D = 0
// polyline.Length = 0

result = GeometryEngine.Instance.MovePointAlongLine(polyline, 3, true, 0, SegmentExtensionType.NoExtension);
// result = 5, 5, 10

result = GeometryEngine.Instance.MovePointAlongLine(polyline, 3, true, 0, SegmentExtensionType.ExtendEmbeddedAtFrom);
// result = 5, 5, 10

// polyline with Z and M
List<MapPoint> inputPoints = new List<MapPoint>()
{
MapPointBuilderEx.CreateMapPoint(1, 2, 3, 4),
MapPointBuilderEx.CreateMapPoint(1, 2, 33, 44),
};

Polyline polylineZM = PolylineBuilderEx.CreatePolyline(inputPoints, SpatialReferences.WGS84);
// polylineZM.HasZ = true
// polylineZM.HasM = true

// ratio = true, no offset
MapPoint pointAlong = GeometryEngine.Instance.MovePointAlongLine(polylineZM, 0.5, true, 0, SegmentExtensionType.NoExtension);
// pointAlong = 1, 2, 18, 24

// ratio = true with offset
pointAlong = GeometryEngine.Instance.MovePointAlongLine(polylineZM, 0.2, true, 2.23606797749979, SegmentExtensionType.NoExtension);
// pointAlong = 1, 2, 9, 12

将几何体的组件分离为单个组件几何图形

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
List<Coordinate2D> coords2D = new List<Coordinate2D>()
{
new Coordinate2D(0, 0),
new Coordinate2D(1, 4),
new Coordinate2D(2, 7),
new Coordinate2D(-10, 3)
};

Multipoint multipoint = MultipointBuilderEx.CreateMultipoint(coords2D, SpatialReferences.WGS84);

IReadOnlyList<Geometry> result = GeometryEngine.Instance.MultipartToSinglePart(multipoint);
// result.Count = 4,


// 'explode' a multipart polygon
result = GeometryEngine.Instance.MultipartToSinglePart(multipartPolygon);


// create a bag of geometries
Polygon polygon = PolygonBuilderEx.CreatePolygon(coords2D, SpatialReferences.WGS84);
//At 2.x - GeometryBag bag = GeometryBagBuilder.CreateGeometryBag(new List<Geometry>() { multipoint, polygon });
var bag = GeometryBagBuilderEx.CreateGeometryBag(new List<Geometry>() { multipoint, polygon });
// bag.PartCount = =2

result = GeometryEngine.Instance.MultipartToSinglePart(bag);
// result.Count == 2
// result[0] is MultiPoint
// result[1] is Polygon

最近点与最近顶点

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
SpatialReference sr = SpatialReferences.WGS84;
MapPoint pt = MapPointBuilderEx.CreateMapPoint(5, 5, sr);

List<Coordinate2D> coords = new List<Coordinate2D>()
{
new Coordinate2D(10, 1),
new Coordinate2D(10, -4),
new Coordinate2D(0, -4),
new Coordinate2D(0, 1),
new Coordinate2D(10, 1)
};

Polygon polygon = PolygonBuilderEx.CreatePolygon(coords);

// find the nearest point in the polygon geomtry to the pt
ProximityResult result = GeometryEngine.Instance.NearestPoint(polygon, pt);
// result.Point = 5, 1
// result.SegmentIndex = 3
// result.PartIndex = 0
// result.PointIndex = null
//result.Distance = 4
//result.RightSide = false

// find the nearest vertex in the polgyon geometry to the pt
result = GeometryEngine.Instance.NearestVertex(polygon, pt);
// result.Point = 10, 1
// result.PointIndex = 0
// result.SegmentIndex = null
// result.PartIndex = 0
// result.Distance = Math.Sqrt(41)
// result.RightSide = false

确定 3D 中的最近点

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
MapPoint pt1 = MapPointBuilderEx.CreateMapPoint(1, 1, 1);
MapPoint pt2 = MapPointBuilderEx.CreateMapPoint(2, 2, 2);
MapPoint pt3 = MapPointBuilderEx.CreateMapPoint(10, 2, 1);

//
// test pt1 to pt2
//
ProximityResult result = GeometryEngine.Instance.NearestPoint3D(pt1, pt2);
// result.Point = 1,1,1
// result.Distance = Math.Sqrt(3)
// result.SegmentIndex = null
// result.PartIndex = 0
// result.PointIndex = 0
// result.RightSide = false

//
// multipoint built from pt1, pt2. should be closer to pt2
//
Multipoint multipoint = MultipointBuilderEx.CreateMultipoint(new List<MapPoint>() { pt1, pt2 });
result = GeometryEngine.Instance.NearestPoint3D(multipoint, pt3);
// result.Point = 2, 2, 2
// result.Distance = Math.Sqrt(65)
// result.SegmentIndex = null
// result.PartIndex = 1
// result.PointIndex = 1
// result.RightSide = false

计算与源的几何偏移

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
List<MapPoint> linePts = new List<MapPoint>();
linePts.Add(MapPointBuilderEx.CreateMapPoint(1.0, 1.0, SpatialReferences.WGS84));
linePts.Add(MapPointBuilderEx.CreateMapPoint(10.0, 1.0, SpatialReferences.WGS84));

Polyline polyline = PolylineBuilderEx.CreatePolyline(linePts);

Geometry g = GeometryEngine.Instance.Offset(polyline, 10, OffsetType.Square, 0);
Polyline gResult = g as Polyline;
// gResult.PointCount = 2
// gResult.Points[0] = (1, -9)
// gResult.Points[1] = (10, -9)

g = GeometryEngine.Instance.Offset(polyline, -10, OffsetType.Round, 0.5);
gResult = g as Polyline;
// gResult.PointCount = 2
// gResult.Points[0] = (1, -11
// gResult.Points[1] = (10, 11)


//
// elliptic arc curve
//
Coordinate2D fromPt = new Coordinate2D(2, 1);
Coordinate2D toPt = new Coordinate2D(1, 2);
Coordinate2D interiorPt = new Coordinate2D(1 + Math.Sqrt(2) / 2, 1 + Math.Sqrt(2) / 2);

EllipticArcSegment circularArc = EllipticArcBuilderEx.CreateCircularArc(fromPt.ToMapPoint(), toPt.ToMapPoint(), interiorPt);

polyline = PolylineBuilderEx.CreatePolyline(circularArc);
g = GeometryEngine.Instance.Offset(polyline, -0.25, OffsetType.Miter, 0.5);
gResult = g as Polyline;

g = GeometryEngine.Instance.Offset(polyline, 0.25, OffsetType.Bevel, 0.5);
gResult = g as Polyline;


//
// offset for a polygon
//
List<MapPoint> list = new List<MapPoint>();
list.Add(MapPointBuilderEx.CreateMapPoint(10.0, 10.0, SpatialReferences.WGS84));
list.Add(MapPointBuilderEx.CreateMapPoint(10.0, 20.0, SpatialReferences.WGS84));
list.Add(MapPointBuilderEx.CreateMapPoint(20.0, 20.0, SpatialReferences.WGS84));
list.Add(MapPointBuilderEx.CreateMapPoint(20.0, 10.0, SpatialReferences.WGS84));

Polygon polygon = PolygonBuilderEx.CreatePolygon(list);

g = GeometryEngine.Instance.Offset(polygon, 2, OffsetType.Square, 0);
Polygon gPolygon = g as Polygon;

g = GeometryEngine.Instance.Offset(polygon, -2, OffsetType.Round, 0.3);
gPolygon = g as Polygon;

g = GeometryEngine.Instance.Offset(polygon, -0.5, OffsetType.Miter, 0.6);
gPolygon = g as Polygon;

确定几何图形是否重叠

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
MapPoint pt1 = MapPointBuilderEx.CreateMapPoint(1.5, 1.5);
MapPoint pt2 = MapPointBuilderEx.CreateMapPoint(1.25, 1.75);
MapPoint pt3 = MapPointBuilderEx.CreateMapPoint(3, 1.5);
MapPoint pt4 = MapPointBuilderEx.CreateMapPoint(1.5, 2);

//
// point and point overlap
//
bool overlaps = GeometryEngine.Instance.Overlaps(pt1, pt2); // overlaps = false
overlaps = GeometryEngine.Instance.Overlaps(pt1, pt1); // overlaps = false
// Two geometries overlap if the region of their intersection is of the same dimension as the geometries involved and
// is not equivalent to either of the geometries.

List<MapPoint> pts = new List<MapPoint>();
pts.Add(pt1);
pts.Add(pt2);
pts.Add(pt3);

List<MapPoint> pts2 = new List<MapPoint>();
pts2.Add(pt2);
pts2.Add(pt3);
pts2.Add(pt4);

//
// pt and line overlap
//
Polyline polyline = PolylineBuilderEx.CreatePolyline(pts);
bool isSimple = GeometryEngine.Instance.IsSimpleAsFeature(polyline); // isSimple = true
overlaps = GeometryEngine.Instance.Overlaps(polyline, pt1); // overlaps = false

//
// line and line
//
Polyline polyline2 = PolylineBuilderEx.CreatePolyline(pts2);
isSimple = GeometryEngine.Instance.IsSimpleAsFeature(polyline2); // isSimple = true
overlaps = GeometryEngine.Instance.Overlaps(polyline, polyline2); // overlaps = true

从 WGS84 到 Web墨卡托的项目

1
2
3
MapPoint pt = MapPointBuilderEx.CreateMapPoint(1.0, 3.0, SpatialReferences.WGS84);
Geometry result = GeometryEngine.Instance.Project(pt, SpatialReferences.WebMercator);
MapPoint projectedPt = result as MapPoint;

WGS84的项目

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// create the polygon
List<MapPoint> pts = new List<MapPoint>();
pts.Add(MapPointBuilderEx.CreateMapPoint(1.0, 1.0, SpatialReferences.WGS84));
pts.Add(MapPointBuilderEx.CreateMapPoint(1.0, 2.0, SpatialReferences.WGS84));
pts.Add(MapPointBuilderEx.CreateMapPoint(2.0, 2.0, SpatialReferences.WGS84));
pts.Add(MapPointBuilderEx.CreateMapPoint(2.0, 1.0, SpatialReferences.WGS84));

Polygon polygon = PolygonBuilderEx.CreatePolygon(pts);
// ensure it is simple
bool isSimple = GeometryEngine.Instance.IsSimpleAsFeature(polygon);

// create the spatial reference to project to
SpatialReference northPole = SpatialReferenceBuilder.CreateSpatialReference(102018); // north pole stereographic

// project
Geometry geometry = GeometryEngine.Instance.Project(polygon, northPole);

查询正常

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
string json = "{\"curvePaths\":[[[-13046586.8335,4036570.6796000004]," +
"{\"c\":[[-13046645.107099999,4037152.5873000026]," +
"[-13046132.776277589,4036932.1325614937]]}]],\"spatialReference\":{\"wkid\":3857}}";
Polyline polyline = PolylineBuilderEx.FromJson(json);

EllipticArcSegment arc = polyline.Parts[0][0] as EllipticArcSegment;

// No extension, distanceAlongCurve = 0.5

// use the polyline
Polyline poly_normal = GeometryEngine.Instance.QueryNormal(polyline, SegmentExtensionType.NoExtension, 0.5, AsRatioOrLength.AsRatio, 1000);
// or a segment
LineSegment seg_normal = GeometryEngine.Instance.QueryNormal(arc, SegmentExtensionType.NoExtension, 0.5, AsRatioOrLength.AsRatio, 1000);

// TangentAtFrom, distanceAlongCurve = -1.2
poly_normal = GeometryEngine.Instance.QueryNormal(polyline, SegmentExtensionType.ExtendTangentAtFrom, -1.2, AsRatioOrLength.AsRatio, 1000);
seg_normal = GeometryEngine.Instance.QueryNormal(arc, SegmentExtensionType.ExtendTangentAtFrom, -1.2, AsRatioOrLength.AsRatio, 1000);

// TangentAtTo (ignored because distanceAlongCurve < 0), distanceAlongCurve = -1.2
poly_normal = GeometryEngine.Instance.QueryNormal(polyline, SegmentExtensionType.ExtendTangentAtTo, -1.2, AsRatioOrLength.AsRatio, 1000);
seg_normal = GeometryEngine.Instance.QueryNormal(arc, SegmentExtensionType.ExtendTangentAtTo, -1.2, AsRatioOrLength.AsRatio, 1000);

// TangentAtTo, distanceAlongCurve = 1.2
poly_normal = GeometryEngine.Instance.QueryNormal(polyline, SegmentExtensionType.ExtendTangentAtTo, 1.2, AsRatioOrLength.AsRatio, 1000);
seg_normal = GeometryEngine.Instance.QueryNormal(arc, SegmentExtensionType.ExtendTangentAtTo, 1.2, AsRatioOrLength.AsRatio, 1000);

// TangentAtFrom (ignored because distanceAlongCurve > 0), distanceAlongCurve = 1.2
poly_normal = GeometryEngine.Instance.QueryNormal(polyline, SegmentExtensionType.ExtendTangentAtFrom, 1.2, AsRatioOrLength.AsRatio, 1000);
seg_normal = GeometryEngine.Instance.QueryNormal(arc, SegmentExtensionType.ExtendTangentAtFrom, 1.2, AsRatioOrLength.AsRatio, 1000);

// EmbeddedAtTo, distanceAlongCurve = 1.2
poly_normal = GeometryEngine.Instance.QueryNormal(polyline, SegmentExtensionType.ExtendEmbeddedAtTo, 1.2, AsRatioOrLength.AsRatio, 1000);
seg_normal = GeometryEngine.Instance.QueryNormal(arc, SegmentExtensionType.ExtendEmbeddedAtTo, 1.2, AsRatioOrLength.AsRatio, 1000);

// EmbeddedAtFrom, distanceAlongCurve = -0.2
poly_normal = GeometryEngine.Instance.QueryNormal(polyline, SegmentExtensionType.ExtendEmbeddedAtFrom, -0.2, AsRatioOrLength.AsRatio, 1000);
seg_normal = GeometryEngine.Instance.QueryNormal(arc, SegmentExtensionType.ExtendEmbeddedAtFrom, -0.2, AsRatioOrLength.AsRatio, 1000);

查询点

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
SpatialReference sr = SpatialReferences.WGS84;

// Horizontal line segment
Coordinate2D start = new Coordinate2D(1, 1);
Coordinate2D end = new Coordinate2D(11, 1);
LineSegment line = LineBuilderEx.CreateLineSegment(start, end, sr);

Polyline polyline = PolylineBuilderEx.CreatePolyline(line);

// Don't extend the segment

MapPoint outPoint = GeometryEngine.Instance.QueryPoint(polyline, SegmentExtensionType.NoExtension, 1.0, AsRatioOrLength.AsLength);
// outPoint = (2, 1)

// or the segment
MapPoint outPoint_seg = GeometryEngine.Instance.QueryPoint(line, SegmentExtensionType.NoExtension, 1.0, AsRatioOrLength.AsLength);
// outPoint_seg = (2, 1)

// Extend infinitely in both directions
outPoint = GeometryEngine.Instance.QueryPoint(polyline, SegmentExtensionType.ExtendTangents, 1.5, AsRatioOrLength.AsRatio);
// outPoint = (16, 1)
outPoint_seg = GeometryEngine.Instance.QueryPoint(line, SegmentExtensionType.ExtendTangents, 1.5, AsRatioOrLength.AsRatio);
// outPoint_seg = (16, 1)

查询点和距离

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
// Horizontal line segment
List<MapPoint> linePts = new List<MapPoint>();
linePts.Add(MapPointBuilderEx.CreateMapPoint(1.0, 1.0, SpatialReferences.WGS84));
linePts.Add(MapPointBuilderEx.CreateMapPoint(11.0, 1.0, SpatialReferences.WGS84));
Polyline polyline = PolylineBuilderEx.CreatePolyline(linePts);
bool isSimple = GeometryEngine.Instance.IsSimpleAsFeature(polyline);

// Don't extent the segment
SegmentExtensionType extension = SegmentExtensionType.NoExtension;

// A point on the line segment
MapPoint inPoint = MapPointBuilderEx.CreateMapPoint(2, 1, SpatialReferences.WGS84);

double distanceAlongCurve, distanceFromCurve;
LeftOrRightSide whichSide;
AsRatioOrLength asRatioOrLength = AsRatioOrLength.AsLength;

MapPoint outPoint = GeometryEngine.Instance.QueryPointAndDistance(polyline, extension, inPoint, asRatioOrLength, out distanceAlongCurve, out distanceFromCurve, out whichSide);
// outPoint = 2, 1
// distanceAlongCurve = 1
// distanceFromCurve = 0
// whichSide = GeometryEngine.Instance.LeftOrRightSide.LeftSide


// Extend infinitely in both directions
extension = SegmentExtensionType.ExtendTangents;

// A point on the left side
inPoint = MapPointBuilderEx.CreateMapPoint(16, 6, SpatialReferences.WGS84);
asRatioOrLength = AsRatioOrLength.AsRatio;

outPoint = GeometryEngine.Instance.QueryPointAndDistance(polyline, extension, inPoint, asRatioOrLength, out distanceAlongCurve, out distanceFromCurve, out whichSide);
// outPoint = 16, 1
// distanceAlongCurve = 1.5
// distanceFromCurve = 5
// whichSide = GeometryEngine.Instance.LeftOrRightSide.LeftSide

查询切线

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
LineSegment line = LineBuilderEx.CreateLineSegment(new Coordinate2D(0, 0), new Coordinate2D(1, 0));

// No extension, distanceAlongCurve = 0.5
LineSegment tangent = GeometryEngine.Instance.QueryTangent(line, SegmentExtensionType.NoExtension, 0.5, AsRatioOrLength.AsRatio, 1);
// tangent.StartCoordinate = (0.5, 0.0)
// tangent.EndCoordinate = (1.5, 0.0)

tangent = GeometryEngine.Instance.QueryTangent(line, SegmentExtensionType.NoExtension, 1.5, AsRatioOrLength.AsLength, 1);
// tangent.StartCoordinate = (1.0, 0.0)
// tangent.EndCoordinate = (2.0, 0.0)

tangent = GeometryEngine.Instance.QueryTangent(line, SegmentExtensionType.ExtendTangentAtTo, 1.5, AsRatioOrLength.AsLength, 1);
// tangent.StartCoordinate = (1.5, 0.0)
// tangent.EndCoordinate = (2.5, 0.0)

tangent = GeometryEngine.Instance.QueryTangent(line, SegmentExtensionType.ExtendTangentAtFrom, -1.5, AsRatioOrLength.AsLength, 1);
// tangent.StartCoordinate = (-1.5, 0.0)
// tangent.EndCoordinate = (-0.5, 0.0)

tangent = GeometryEngine.Instance.QueryTangent(line, SegmentExtensionType.ExtendTangentAtFrom, -0.5, AsRatioOrLength.AsRatio, 1);
// tangent.StartCoordinate = (-0.5, 0.0)
// tangent.EndCoordinate = (0.5, 0.0)

围绕线反射多边形

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
SpatialReference sr = SpatialReferences.WGS84;

Coordinate2D start = new Coordinate2D(0, 0);
Coordinate2D end = new Coordinate2D(4, 4);
LineSegment line = LineBuilderEx.CreateLineSegment(start, end, sr);

Coordinate2D[] coords = new Coordinate2D[]
{
new Coordinate2D(-1, 2),
new Coordinate2D(-1, 4),
new Coordinate2D(1, 4),
new Coordinate2D(-1, 2)
};

Polygon polygon = PolygonBuilderEx.CreatePolygon(coords, sr);

// reflect a polygon about the line
Polygon reflectedPolygon = GeometryEngine.Instance.ReflectAboutLine(polygon, line) as Polygon;

// reflectedPolygon points are
// (2, -1), (4, -1), (4, 1), (2, -1)

确定两个几何图形之间的关系

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
// set up some geometries

// points
MapPoint point0 = MapPointBuilderEx.CreateMapPoint(0, 0, SpatialReferences.WGS84);
MapPoint point1 = MapPointBuilderEx.CreateMapPoint(1, 1, SpatialReferences.WGS84);
MapPoint point2 = MapPointBuilderEx.CreateMapPoint(-5, 5, SpatialReferences.WGS84);

// multipoint
List<MapPoint> points = new List<MapPoint>() { point0, point1, point2 };
Multipoint multipoint = MultipointBuilderEx.CreateMultipoint(points, SpatialReferences.WGS84);

// polygon
List<Coordinate2D> polygonCoords = new List<Coordinate2D>()
{
new Coordinate2D(-10, 0),
new Coordinate2D(0, 10),
new Coordinate2D(10, 0),
new Coordinate2D(-10, 0)
};
Polygon polygon = PolygonBuilderEx.CreatePolygon(polygonCoords, SpatialReferences.WGS84);

// polylines
Polyline polyline1 = PolylineBuilderEx.CreatePolyline(LineBuilderEx.CreateLineSegment(new Coordinate2D(-9.1, 0.1), new Coordinate2D(0, 9)), SpatialReferences.WGS84);
Polyline polyline2 = PolylineBuilderEx.CreatePolyline(LineBuilderEx.CreateLineSegment(new Coordinate2D(-5, 5), new Coordinate2D(0, 5)), SpatialReferences.WGS84);
Polyline polyline3 = PolylineBuilderEx.CreatePolyline(LineBuilderEx.CreateLineSegment(new Coordinate2D(2.09, -2.04), new Coordinate2D(5, 10)), SpatialReferences.WGS84);
Polyline polyline4 = PolylineBuilderEx.CreatePolyline(LineBuilderEx.CreateLineSegment(new Coordinate2D(10, -5), new Coordinate2D(10, 5)), SpatialReferences.WGS84);

List<Segment> segments = new List<Segment>()
{
LineBuilderEx.CreateLineSegment(new Coordinate2D(5.05, -2.87), new Coordinate2D(6.35, 1.57)),
LineBuilderEx.CreateLineSegment(new Coordinate2D(6.35, 1.57), new Coordinate2D(4.13, 2.59)),
LineBuilderEx.CreateLineSegment(new Coordinate2D(4.13, 2.59), new Coordinate2D(5, 5))
};
Polyline polyline5 = PolylineBuilderEx.CreatePolyline(segments, SpatialReferences.WGS84);

segments.Add(LineBuilderEx.CreateLineSegment(new Coordinate2D(5, 5), new Coordinate2D(10, 10)));

Polyline polyline6 = PolylineBuilderEx.CreatePolyline(segments, SpatialReferences.WGS84);
Polyline polyline7 = PolylineBuilderEx.CreatePolyline(polyline5);
Polyline polyline8 = PolylineBuilderEx.CreatePolyline(LineBuilderEx.CreateLineSegment(new Coordinate2D(5, 5), new Coordinate2D(10, 10)), SpatialReferences.WGS84);

segments.Clear();
segments.Add(LineBuilderEx.CreateLineSegment(new Coordinate2D(0.6, 3.5), new Coordinate2D(0.7, 7)));
segments.Add(LineBuilderEx.CreateLineSegment(new Coordinate2D(0.7, 7), new Coordinate2D(3, 9)));

Polyline polyline9 = PolylineBuilderEx.CreatePolyline(segments, SpatialReferences.WGS84);

// now do the Related tests

// Interior/Interior Intersects
string scl = "T********";
bool related = GeometryEngine.Instance.Relate(polygon, polyline1, scl); // related = true
related = GeometryEngine.Instance.Relate(point0, point1, scl); // related = false
related = GeometryEngine.Instance.Relate(point0, multipoint, scl); // related = true
related = GeometryEngine.Instance.Relate(multipoint, polygon, scl); // related = true
related = GeometryEngine.Instance.Relate(multipoint, polyline1, scl); // related = false
related = GeometryEngine.Instance.Relate(polyline2, point2, scl); // related = false
related = GeometryEngine.Instance.Relate(point1, polygon, scl); // related = true

// Interior/Boundary Intersects
scl = "*T*******";
related = GeometryEngine.Instance.Relate(polygon, polyline2, scl); // related = true
related = GeometryEngine.Instance.Relate(polygon, polyline3, scl); // related = false
related = GeometryEngine.Instance.Relate(point1, polygon, scl); // related = false

// Boundary/Boundary Interior intersects
scl = "***T*****";
related = GeometryEngine.Instance.Relate(polygon, polyline4, scl); // related = true

// Overlaps Dim1
scl = "1*T***T**";
related = GeometryEngine.Instance.Relate(polygon, polyline5, scl); // related = true

// Crosses Area/Line (LineB crosses PolygonA)
scl = "1020F1102";
related = GeometryEngine.Instance.Relate(polygon, polyline6, scl); // related = false
related = GeometryEngine.Instance.Relate(polygon, polyline9, scl); // related = true

// Boundary/Boundary Touches
scl = "F***T****";
related = GeometryEngine.Instance.Relate(polygon, polyline7, scl); // related = false
related = GeometryEngine.Instance.Relate(polygon, polyline8, scl); // related = true

替换多边形中的 NaN Z

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
List<Coordinate3D> coordsZ = new List<Coordinate3D>()
{
new Coordinate3D(1, 2, double.NaN),
new Coordinate3D(4, 5, 3),
new Coordinate3D(7, 8, double.NaN)
};

Polygon polygon = PolygonBuilderEx.CreatePolygon(coordsZ);
// polygon.HasZ = true

Polygon polygonZReplaced = GeometryEngine.Instance.ReplaceNaNZs(polygon, -1) as Polygon;

// polygonZReplaced.Points[0].Z = -1
// polygonZReplaced.Points[1].Z = 3
// polygonZReplaced.Points[2].Z = -1

改变多边形的形状

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
List<Coordinate2D> polygon1Coords = new List<Coordinate2D>()
{
new Coordinate2D(0, -11000),
new Coordinate2D(1000, -11000),
new Coordinate2D(1000, -12000),
new Coordinate2D(0, -12000),
new Coordinate2D(0, -11000)
};

// reshaper coordinates intersect the polygon
List<Coordinate2D> reshaperCoords = new List<Coordinate2D>()
{
new Coordinate2D(1500, -11800),
new Coordinate2D(-2600, -11800)
};

SpatialReference sr = SpatialReferenceBuilder.CreateSpatialReference(102010);
Polygon polygon1 = PolygonBuilderEx.CreatePolygon(polygon1Coords, sr);
Polyline reshaper = PolylineBuilderEx.CreatePolyline(reshaperCoords, sr);

Polygon outPolygon = GeometryEngine.Instance.Reshape(polygon1, reshaper) as Polygon;
// outPolygon.PartCount = 1

ReadOnlySegmentCollection segments = outPolygon.Parts[0];
// segments.Count = 4
// outPolygon.PointCount = 5

string json = GeometryEngine.Instance.ExportToJson(JsonExportFlags.JsonExportSkipCRS, outPolygon);
// json = "{\"rings\":[[[0,-11800],[0,-11000],[1000,-11000],[1000,-11800],[0,-11800]]]}";


// example where the Reshaper polyline doesn't intersect the input

reshaperCoords.Clear();
reshaperCoords.Add(new Coordinate2D(1000, 1000));
reshaperCoords.Add(new Coordinate2D(2000, 1000));

reshaper = PolylineBuilderEx.CreatePolyline(reshaperCoords, sr);

outPolygon = GeometryEngine.Instance.Reshape(polygon1, reshaper) as Polygon;
// outPolygon = null

反转多边形中点的顺序

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
List<Coordinate2D> list2D = new List<Coordinate2D>();
list2D.Add(new Coordinate2D(1.0, 1.0));
list2D.Add(new Coordinate2D(1.0, 2.0));
list2D.Add(new Coordinate2D(2.0, 2.0));
list2D.Add(new Coordinate2D(2.0, 1.0));

Polygon polygon = PolygonBuilderEx.CreatePolygon(list2D);

Geometry g = GeometryEngine.Instance.ReverseOrientation(polygon);
Polygon gPolygon = g as Polygon;

// gPolygon.Points[0] = 1.0, 1.0
// gPolygon.Points[1] = 2.0, 1.0
// gPolygon.Points[2] = 2.0, 2.0
// gPolygon.Points[3] = 1.0, 2.0
// gPolygon.Points[4] = 1.0, 1.0
// gPolygon.Area = -1 * polygon.Area

旋转地图点

1
2
3
4
5
MapPoint pt = MapPointBuilderEx.CreateMapPoint(1.0, 3.0);
MapPoint rotatePt = MapPointBuilderEx.CreateMapPoint(3.0, 3.0);

Geometry result = GeometryEngine.Instance.Rotate(pt, rotatePt, Math.PI / 2);
// result point is (3, 1)

旋转折线

1
2
3
4
5
6
7
8
9
10
11
12
// rotate a polyline

MapPoint fixedPt = MapPointBuilderEx.CreateMapPoint(3.0, 3.0);

List<MapPoint> pts = new List<MapPoint>();
pts.Add(MapPointBuilderEx.CreateMapPoint(1.0, 1.0));
pts.Add(MapPointBuilderEx.CreateMapPoint(1.0, 5.0));
pts.Add(MapPointBuilderEx.CreateMapPoint(5, 5));
pts.Add(MapPointBuilderEx.CreateMapPoint(5.0, 1.0));
Polyline polyline = PolylineBuilderEx.CreatePolyline(pts);

Polyline rotated = GeometryEngine.Instance.Rotate(polyline, fixedPt, Math.PI / 4) as Polyline; // rotate 45 deg

缩放几何图形

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
List<MapPoint> pts = new List<MapPoint>();
pts.Add(MapPointBuilderEx.CreateMapPoint(1.0, 1.0, 3.0));
pts.Add(MapPointBuilderEx.CreateMapPoint(1.0, 3.0, 3.0));
pts.Add(MapPointBuilderEx.CreateMapPoint(3, 3, 3.0));
pts.Add(MapPointBuilderEx.CreateMapPoint(3.0, 1.0, 3.0));

MapPoint midPt = MapPointBuilderEx.CreateMapPoint(1.5, 1.5);

// polyline
Polyline polyline = PolylineBuilderEx.CreatePolyline(pts);
// polyline.Length = 6
// polyline.Length3D = 0
Geometry g = GeometryEngine.Instance.Scale(polyline, midPt, 0.5, 0.5);
Polyline resultPolyline = g as Polyline;
// resultPolyline.length = 3
// resultPolyline.Points[0] = 1.25, 1.25, 3
// resultPolyline.Points[1] = 1.25, 2.25, 3
// resultPolyline.Points[2] = 2.25, 2.25, 3
// resultPolyline.Points[3] = 2.25, 1.25, 3

// 3D point - scale in 3d
MapPoint midPtZ = MapPointBuilderEx.CreateMapPoint(1.5, 1.5, 1);
g = GeometryEngine.Instance.Scale(polyline, midPtZ, 0.5, 0.5, 0.25);
resultPolyline = g as Polyline;
// resultPolyline.Points[0] = 1.25, 1.25, 1.5
// resultPolyline.Points[1] = 1.25, 2.25, 1.5
// resultPolyline.Points[2] = 2.25, 2.25, 1.5
// resultPolyline.Points[3] = 2.25, 1.25, 1.5

设置折线中的所有 Z

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
List<Coordinate3D> coordsZ = new List<Coordinate3D>()
{
new Coordinate3D(1, 2, 3),
new Coordinate3D(4, 5, 6),
new Coordinate3D(7, 8, double.NaN)
};

Polyline polyline = PolylineBuilderEx.CreatePolyline(coordsZ);
// polyline.HasZ = true

Polyline polylineSetZ = GeometryEngine.Instance.SetConstantZ(polyline, -1) as Polyline;
// polylineSetZ.Points[0].Z = -1
// polylineSetZ.Points[1].Z = -1
// polylineSetZ.Points[2].Z = -1

polylineSetZ = GeometryEngine.Instance.SetConstantZ(polyline, double.NaN) as Polyline;
// polyline.HasZ = true
// polylineSetZ.Points[0].HasZ = true
// polylineSetZ.Points[0].Z = NaN
// polylineSetZ.Points[1].HasZ = true
// polylineSetZ.Points[1].Z = NaN
// polylineSetZ.Points[2].HasZ = true
// polylineSetZ.Points[2].Z = NaN

polylineSetZ = GeometryEngine.Instance.SetConstantZ(polyline, double.PositiveInfinity) as Polyline;
// polyline.HasZ = true
// polylineSetZ.Points[0].HasZ = true
// polylineSetZ.Points[0].Z = double.PositiveInfinity
// polylineSetZ.Points[1].HasZ = true
// polylineSetZ.Points[1].Z = double.PositiveInfinity
// polylineSetZ.Points[2].HasZ = true
// polylineSetZ.Points[2].Z = double.PositiveInfinity

计算地球椭球体表面上的几何面积 - 形状保存面积

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
// pt
MapPoint pt = MapPointBuilderEx.CreateMapPoint(1.0, 3.0, SpatialReferences.WebMercator);
double area = GeometryEngine.Instance.ShapePreservingArea(pt); // area = 0

List<MapPoint> pts = new List<MapPoint>();
pts.Add(MapPointBuilderEx.CreateMapPoint(1.0, 1.0, 3.0));
pts.Add(MapPointBuilderEx.CreateMapPoint(1.0, 3.0, 3.0));
pts.Add(MapPointBuilderEx.CreateMapPoint(3, 3, 3.0));
pts.Add(MapPointBuilderEx.CreateMapPoint(3.0, 1.0, 3.0));

// multipoint
Multipoint mPt = MultipointBuilderEx.CreateMultipoint(pts);
area = GeometryEngine.Instance.ShapePreservingArea(mPt); // area = 0

// polyline
Polyline polyline = PolylineBuilderEx.CreatePolyline(pts);
area = GeometryEngine.Instance.ShapePreservingArea(polyline); // area = 0

// polygon
Polygon polygon = PolygonBuilderEx.CreatePolygon(pts, SpatialReferences.WGS84);
area = GeometryEngine.Instance.ShapePreservingArea(polygon);

polygon = PolygonBuilderEx.CreatePolygon(pts, SpatialReferences.WebMercator);
area = GeometryEngine.Instance.ShapePreservingArea(polygon);


polygon = PolygonBuilderEx.CreatePolygon(new[]
{
MapPointBuilderEx.CreateMapPoint( -170, 45),
MapPointBuilderEx.CreateMapPoint( 170, 45),
MapPointBuilderEx.CreateMapPoint( 170, -45),
MapPointBuilderEx.CreateMapPoint( -170, -54)
}, SpatialReferences.WGS84);

var area_meters = GeometryEngine.Instance.ShapePreservingArea(polygon);// , AreaUnits.SquareMeters);
var area_miles = GeometryEngine.Instance.ShapePreservingArea(polygon, AreaUnit.SquareMiles);

// area_meters - 352556425383104.37
// area_miles - 136122796.848425

计算地球椭球体表面几何形状的长度 - 形状保存长度

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
// pt
MapPoint pt = MapPointBuilderEx.CreateMapPoint(1.0, 3.0, SpatialReferences.WebMercator);
double len = GeometryEngine.Instance.ShapePreservingLength(pt); // len = 0

List<MapPoint> pts = new List<MapPoint>();
pts.Add(MapPointBuilderEx.CreateMapPoint(1.0, 1.0, 3.0));
pts.Add(MapPointBuilderEx.CreateMapPoint(1.0, 3.0, 3.0));
pts.Add(MapPointBuilderEx.CreateMapPoint(3, 3, 3.0));
pts.Add(MapPointBuilderEx.CreateMapPoint(3.0, 1.0, 3.0));

// multipoint
Multipoint mPt = MultipointBuilderEx.CreateMultipoint(pts);
len = GeometryEngine.Instance.ShapePreservingLength(mPt); // len = 0

// polyline
Polyline polyline = PolylineBuilderEx.CreatePolyline(pts, SpatialReferences.WGS84);
len = GeometryEngine.Instance.ShapePreservingLength(polyline);

// polygon
Polygon polygon = PolygonBuilderEx.CreatePolygon(pts, SpatialReferences.WGS84);
len = GeometryEngine.Instance.ShapePreservingLength(polygon);



polyline = PolylineBuilderEx.CreatePolyline(new[]
{
MapPointBuilderEx.CreateMapPoint( -170, 0),
MapPointBuilderEx.CreateMapPoint( 170, 0)
}, SpatialReferences.WGS84);


var length_meters = GeometryEngine.Instance.ShapePreservingLength(polyline); // , LinearUnits.Meters);
var length_miles = GeometryEngine.Instance.ShapePreservingLength(polyline, LinearUnit.Miles);

// length_meters - 37848626.869713023
// length_miles - 23518.046402579574

侧缓冲器

1
2
3
4
5
6
7
8
9
10
11
12
13
// right side, round caps
SpatialReference sr = SpatialReferenceBuilder.CreateSpatialReference(102010);
List<Coordinate2D> coords = new List<Coordinate2D>()
{
new Coordinate2D(1200, 5800),
new Coordinate2D(1400, 5800),
new Coordinate2D(1400, 6000),
new Coordinate2D(1300, 6000),
new Coordinate2D(1300, 5700)
};

Polyline polyline = PolylineBuilderEx.CreatePolyline(coords, sr);
Polygon output = GeometryEngine.Instance.SideBuffer(polyline, 20, LeftOrRightSide.RightSide, LineCapType.Round) as Polygon;

侧缓冲器很多

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
SpatialReference spatialReference = SpatialReferenceBuilder.CreateSpatialReference(102010);
List<Coordinate2D> coordinates = new List<Coordinate2D>()
{
new Coordinate2D(1200, 5800),
new Coordinate2D(1400, 5800),
new Coordinate2D(1400, 6000),
new Coordinate2D(1300, 6000),
new Coordinate2D(1300, 5700)
};

Polyline polyline1 = PolylineBuilderEx.CreatePolyline(coordinates, spatialReference);

coordinates.Clear();
coordinates.Add(new Coordinate2D(1400, 6050));
coordinates.Add(new Coordinate2D(1600, 6150));
coordinates.Add(new Coordinate2D(1800, 6050));

Polyline polyline2 = PolylineBuilderEx.CreatePolyline(coordinates, spatialReference);
List<Polyline> polylines = new List<Polyline>() { polyline1, polyline2 };
IReadOnlyList<Geometry> outGeometries = GeometryEngine.Instance.SideBuffer(polylines, 10, LeftOrRightSide.RightSide, LineCapType.Round);

简化多边形

1
2
3
4
5
var g1 = PolygonBuilderEx.FromJson("{\"rings\": [ [ [0, 0], [10, 0], [10, 10], [0, 10] ] ] }");
var result = GeometryEngine.Instance.Area(g1); // result = -100.0 - negative due to wrong ring orientation
// simplify it
var result2 = GeometryEngine.Instance.Area(GeometryEngine.Instance.SimplifyAsFeature(g1, true));
// result2 = 100.0 - positive due to correct ring orientation (clockwise)

简化具有相交、重叠的折线

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
List<Coordinate2D> coords = new List<Coordinate2D>()
{
new Coordinate2D(8, 0),
new Coordinate2D(8, 4),
new Coordinate2D(6, 4),
new Coordinate2D(8, 4),
new Coordinate2D(10, 4),
new Coordinate2D(8, 4)
};

SpatialReference sr = SpatialReferences.WGS84;

// build a line that has segments that cross over each other
Polyline polyline = PolylineBuilderEx.CreatePolyline(coords, sr);
// polyline.PartCount = 1
ReadOnlyPartCollection parts = polyline.Parts;
ReadOnlySegmentCollection segments = parts[0];
// segments.Count = 5

// note there is a difference between SimpleAsFeature (doesn't detect intersections and overlaps, determines if it's simple enough for gdb storage)
// and SimplifyPolyline (does detect intersections etc)
bool isSimple = GeometryEngine.Instance.IsSimpleAsFeature(polyline, false);
// isSimple = true

// simplify it (with force = false)
// because it has already been deemed 'simple' (previous IsSimpleAsFeature call) no detection of intersections, overlaps occur
Polyline simplePolyline = GeometryEngine.Instance.SimplifyPolyline(polyline, SimplifyType.Planar, false);
// simplePolyline.PartCount = 1
ReadOnlyPartCollection simpleParts = simplePolyline.Parts;
ReadOnlySegmentCollection simpleSegments = simpleParts[0];
// simpleSegments.Count = 5

// simplify it (with force = true)
// detection of intersections, overlaps occur
simplePolyline = GeometryEngine.Instance.SimplifyPolyline(polyline, SimplifyType.Planar, true);
// simplePolyline.PartCount = 3
simpleParts = simplePolyline.Parts;
simpleSegments = simpleParts[0];
// simpleSegments.Count = 1

将多边形切成相等的部分

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
var slices = GeometryEngine.Instance.SlicePolygonIntoEqualParts(polygon, 3, 0, SliceType.Blocks);
// slices.Count = 3


// simple polygon
List<Coordinate2D> list2D = new List<Coordinate2D>();
list2D.Add(new Coordinate2D(1.0, 1.0));
list2D.Add(new Coordinate2D(1.0, 2.0));
list2D.Add(new Coordinate2D(2.0, 2.0));
list2D.Add(new Coordinate2D(2.0, 1.0));

Polygon p = PolygonBuilderEx.CreatePolygon(list2D);
slices = GeometryEngine.Instance.SlicePolygonIntoEqualParts(p, 2, 0, SliceType.Strips);

// slice[0] coordinates - (1.0, 1.0), (1.0, 1.5), (2.0, 1.5), (2.0, 1.0), (1.0, 1.0)
// slice[1] coordinates - (1.0, 1.5), (1.0, 2.0), (2.0, 2.0), (2.0, 1.5), (1.0, 1.5)

slices = GeometryEngine.Instance.SlicePolygonIntoEqualParts(p, 2, Math.PI / 4, SliceType.Strips);

// slice[0] coordinates - (1.0, 1.0), (1.0, 2.0), (2.0, 1.0), (1.0, 1.0)
// slice[1] coordinates - (1.0, 2.0), (2.0, 2.0), (2.0, 1.0), (1.0, 2.0)

在点拆分多部分

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
// define a polyline
MapPoint startPointZ = MapPointBuilderEx.CreateMapPoint(1, 1, 5);
MapPoint endPointZ = MapPointBuilderEx.CreateMapPoint(20, 1, 5);

Polyline polylineZ = PolylineBuilderEx.CreatePolyline(new List<MapPoint>() { startPointZ, endPointZ });

// define a split point
MapPoint splitPointAboveLine = MapPointBuilderEx.CreateMapPoint(10, 10, 10);

bool splitOccurred;
int partIndex;
int segmentIndex;

// split the polyline at the point. dont project the split point onto the line, don't create a new part
var splitPolyline = GeometryEngine.Instance.SplitAtPoint(polylineZ, splitPointAboveLine, false, false, out splitOccurred, out partIndex, out segmentIndex);

// splitOccurred = true
// partIndex = 0
// segmentIndex = 1
// splitPolyline.PointCount = 3
// splitPolyline.PartCount = 1
// splitPolyline coordinates are (1, 1, 5), (10, 10, 10), (20, 1, 5)

// split the polyline at the point. dont project the split point onto the line, do create a new part
splitPolyline = GeometryEngine.Instance.SplitAtPoint(polylineZ, splitPointAboveLine, false, false, out splitOccurred, out partIndex, out segmentIndex);

// splitOccurred = true
// partIndex = 1
// segmentIndex = 0
// splitPolyline.PointCount = 4
// splitPolyline.PartCount = 2
// splitPolyline first part coordinates are (1, 1, 5), (10, 10, 10)
// splitPolyline second part coordinates are (10, 10, 10), (20, 1, 5)


// split the polyline at the point. do project the split point onto the line, don't create a new part
splitPolyline = GeometryEngine.Instance.SplitAtPoint(polylineZ, splitPointAboveLine, false, false, out splitOccurred, out partIndex, out segmentIndex);

// splitOccurred = true
// partIndex = 0
// segmentIndex = 1
// splitPolyline.PointCount = 3
// splitPolyline.PartCount = 1
// splitPolyline coordinates are (1, 1, 5), (10, 10, 5), (20, 1, 5)

// split the polyline at the point. do project the split point onto the line, do create a new part
splitPolyline = GeometryEngine.Instance.SplitAtPoint(polylineZ, splitPointAboveLine, false, false, out splitOccurred, out partIndex, out segmentIndex);

// splitOccurred = true
// partIndex = 1
// segmentIndex = 0
// splitPolyline.PointCount = 4
// splitPolyline.PartCount = 2
// splitPolyline first part coordinates are (1, 1, 5), (10, 10, 5)
// splitPolyline second part coordinates are (10, 10, 5), (20, 1, 5)


//
// try to split with a point that won't split the line - pt extends beyond the line
//

var pointAfterLine = MapPointBuilderEx.CreateMapPoint(50, 1, 10);
splitPolyline = GeometryEngine.Instance.SplitAtPoint(polylineZ, pointAfterLine, false, false, out splitOccurred, out partIndex, out segmentIndex);

// splitOccurred = false
// ignore partIndex, sgementIndex
// splitPolyline is the same as polylineZ


///
/// multipart polygon
///
List<Coordinate3D> coordsZ = new List<Coordinate3D>()
{
new Coordinate3D(10,10,5),
new Coordinate3D(10,20,5),
new Coordinate3D(20,20,5),
new Coordinate3D(20,10,5)
};

List<Coordinate3D> coordsZ_2ndPart = new List<Coordinate3D>()
{
new Coordinate3D(30,20,10),
new Coordinate3D(30,30,10),
new Coordinate3D(35,28,10),
new Coordinate3D(40,30,10),
new Coordinate3D(40,20,10),
};

var builder = new PolygonBuilderEx();
builder.HasZ = true;
builder.AddPart(coordsZ);
builder.AddPart(coordsZ_2ndPart);

Polygon multipart = builder.ToGeometry();

// pointA is closer to the first part of the multipart - the split occurs in the first part
var pointA = MapPointBuilderEx.CreateMapPoint(22, 18, 7);
var splitPolygon = GeometryEngine.Instance.SplitAtPoint(multipart, pointA, false, false, out splitOccurred, out partIndex, out segmentIndex);

// splitPolygon.PointCount = 12
// splitPolygon.PartCount = 2
// splitPolygon first part coordinates (10, 10, 5), (10, 20, 5), (20, 20, 5), (22, 18, 7), (20, 10, 5), (10, 10, 5)


// pointB is midPoint between the 2 parts - no split will occur
var pointB = MapPointBuilderEx.CreateMapPoint(25, 20, 7);
splitPolygon = GeometryEngine.Instance.SplitAtPoint(multipart, pointB, true, false, out splitOccurred, out partIndex, out segmentIndex);

// splitOccurred = false
// ignore partIndex, sgementIndex
// splitPolyline is the same as polylineZ

多边形接触另一个多边形

1
2
3
4
5
6
7
8
9
10
11
12
13
14
// two disjoint polygons
Envelope env = EnvelopeBuilderEx.CreateEnvelope(MapPointBuilderEx.CreateMapPoint(4.0, 4.0), MapPointBuilderEx.CreateMapPoint(8, 8));
Polygon poly1 = PolygonBuilderEx.CreatePolygon(env);

Envelope env2 = EnvelopeBuilderEx.CreateEnvelope(MapPointBuilderEx.CreateMapPoint(1.0, 1.0), MapPointBuilderEx.CreateMapPoint(5, 5));
Polygon poly2 = PolygonBuilderEx.CreatePolygon(env2);

bool touches = GeometryEngine.Instance.Touches(poly1, poly2); // touches = false

// another polygon that touches the first
Envelope env3 = EnvelopeBuilderEx.CreateEnvelope(MapPointBuilderEx.CreateMapPoint(1.0, 1.0), MapPointBuilderEx.CreateMapPoint(4, 4));
Polygon poly3 = PolygonBuilderEx.CreatePolygon(env3);

touches = GeometryEngine.Instance.Touches(poly1, poly3); // touches = true

转换2D

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
// Not all of the input points are transformed as some of them are outside of the GCS horizon.
Coordinate2D[] inCoords2D = new Coordinate2D[]
{
new Coordinate2D(-1, -1),
new Coordinate2D(-2, -5),
new Coordinate2D(-5, -11),
new Coordinate2D(-10, -19),
new Coordinate2D(-17, -29),
new Coordinate2D(-26, -41),
new Coordinate2D(-37, -5),
new Coordinate2D(-50, -21),
new Coordinate2D(-65, -39),
new Coordinate2D(-82, -9)
};

int arraySize = inCoords2D.Length;

ProjectionTransformation projTrans = ProjectionTransformation.Create(SpatialReferences.WGS84, SpatialReferenceBuilder.CreateSpatialReference(24891));

Coordinate2D[] outCoords2D = new Coordinate2D[arraySize];

// transform and choose to remove the clipped coordinates
int numPointsTransformed = GeometryEngine.Instance.Transform2D(inCoords2D, projTrans, ref outCoords2D, true);

// numPointsTransformed = 4
// outCoords2D.Length = 4

// outCoords2D[0] = {5580417.6876455201, 1328841.2376554986}
// outCoords2D[1] = {3508774.290814558, -568027.23444226268}
// outCoords2D[2] = {1568096.0886155984, -2343435.4394415971}
// outCoords2D[3] = {57325.827391741652, 1095146.8917508761}

// transform and don't remove the clipped coordinates
numPointsTransformed = GeometryEngine.Instance.Transform2D(inCoords2D, projTrans, ref outCoords2D, false);

// numPointsTransformed = 4
// outCoords2D.Length = 10

// outCoords2D[0] = {double.Nan, double.Nan}
// outCoords2D[1] = {double.Nan, double.Nan}
// outCoords2D[2] = {double.Nan, double.Nan}
// outCoords2D[3] = {double.Nan, double.Nan}
// outCoords2D[4] = {double.Nan, double.Nan}
// outCoords2D[5] = {double.Nan, double.Nan}
// outCoords2D[6] = {5580417.6876455201, 1328841.2376554986}
// outCoords2D[7] = {3508774.290814558, -568027.23444226268}
// outCoords2D[8] = {1568096.0886155984, -2343435.4394415971}
// outCoords2D[9] = {57325.827391741652, 1095146.8917508761}

转换3D

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
// Not all of the input points are transformed as some of them are outside of the GCS horizon.
Coordinate3D[] inCoords3D = new Coordinate3D[]
{
new Coordinate3D(-1, -1, 0),
new Coordinate3D(-2, -5, 1),
new Coordinate3D(-5, -11, 2),
new Coordinate3D(-10, -19, 3),
new Coordinate3D(-17, -29, 4),
new Coordinate3D(-26, -41, 5),
new Coordinate3D(-37, -5, 6),
new Coordinate3D(-50, -21, 7),
new Coordinate3D(-65, -39, 8),
new Coordinate3D(-82, -9, 9)
};

int arraySize = inCoords3D.Length;

ProjectionTransformation projTrans = ProjectionTransformation.Create(SpatialReferences.WGS84, SpatialReferenceBuilder.CreateSpatialReference(24891));

Coordinate3D[] outCoords3D = new Coordinate3D[arraySize];

// transform and choose to remove the clipped coordinates
int numPointsTransformed = GeometryEngine.Instance.Transform3D(inCoords3D, projTrans, ref outCoords3D);

// numPointsTransformed = 4
// outCoords2D.Length = 4

// outCoords2D[0] = {5580417.6876455201, 1328841.2376554986, 7}
// outCoords2D[1] = {3508774.290814558, -568027.23444226268, 8}
// outCoords2D[2] = {1568096.0886155984, -2343435.4394415971, 9}
// outCoords2D[3] = {57325.827391741652, 1095146.8917508761, 10}

合并两个地图点 - 创建一个多点

1
2
3
4
5
MapPoint pt1 = MapPointBuilderEx.CreateMapPoint(1.0, 1.0);
MapPoint pt2 = MapPointBuilderEx.CreateMapPoint(2.0, 2.5);

Geometry geometry = GeometryEngine.Instance.Union(pt1, pt2);
Multipoint multipoint = geometry as Multipoint; // multipoint has point count of 2

并集两个多边形

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
// union two polygons

List<MapPoint> polyPts = new List<MapPoint>();
polyPts.Add(MapPointBuilderEx.CreateMapPoint(3.0, 2.0));
polyPts.Add(MapPointBuilderEx.CreateMapPoint(3.0, 6.0));
polyPts.Add(MapPointBuilderEx.CreateMapPoint(6.0, 6.0));
polyPts.Add(MapPointBuilderEx.CreateMapPoint(6.0, 2.0));

Polygon poly1 = PolygonBuilderEx.CreatePolygon(polyPts);
bool isSimple = GeometryEngine.Instance.IsSimpleAsFeature(poly1);

Envelope env = EnvelopeBuilderEx.CreateEnvelope(MapPointBuilderEx.CreateMapPoint(4.0, 4.0), MapPointBuilderEx.CreateMapPoint(8, 8));
Polygon poly2 = PolygonBuilderEx.CreatePolygon(env);
isSimple = GeometryEngine.Instance.IsSimpleAsFeature(poly2);

Geometry g = GeometryEngine.Instance.Union(poly1, poly2);
Polygon polyResult = g as Polygon;

联合许多折线

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
// union many polylines

List<Coordinate2D> coords = new List<Coordinate2D>()
{
new Coordinate2D(1, 2), new Coordinate2D(3, 4), new Coordinate2D(4, 2),
new Coordinate2D(5, 6), new Coordinate2D(7, 8), new Coordinate2D(8, 4),
new Coordinate2D(9, 10), new Coordinate2D(11, 12), new Coordinate2D(12, 8),
new Coordinate2D(10, 8), new Coordinate2D(12, 12), new Coordinate2D(14, 10)
};

// create Disjoint lines
List<Polyline> manyLines = new List<Polyline>
{
PolylineBuilderEx.CreatePolyline(new List<Coordinate2D>(){coords[0], coords[1], coords[2]}, SpatialReferences.WGS84),
PolylineBuilderEx.CreatePolyline(new List<Coordinate2D>(){coords[3], coords[4], coords[5]}),
PolylineBuilderEx.CreatePolyline(new List<Coordinate2D>(){coords[6], coords[7], coords[8]})
};

Polyline polyline = GeometryEngine.Instance.Union(manyLines) as Polyline;

联合多个多边形

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
// union many polygons

List<Coordinate3D> coordsZ = new List<Coordinate3D>()
{
new Coordinate3D(1, 2, 0), new Coordinate3D(3, 4, 1), new Coordinate3D(4, 2, 2),
new Coordinate3D(5, 6, 3), new Coordinate3D(7, 8, 4), new Coordinate3D(8, 4, 5),
new Coordinate3D(9, 10, 6), new Coordinate3D(11, 12, 7), new Coordinate3D(12, 8, 8),
new Coordinate3D(10, 8, 9), new Coordinate3D(12, 12, 10), new Coordinate3D(14, 10, 11)
};

// create polygons
List<Polygon> manyPolygonsZ = new List<Polygon>
{
PolygonBuilderEx.CreatePolygon(new List<Coordinate3D>(){coordsZ[0], coordsZ[1], coordsZ[2]}, SpatialReferences.WGS84),
PolygonBuilderEx.CreatePolygon(new List<Coordinate3D>(){coordsZ[3], coordsZ[4], coordsZ[5]}),
PolygonBuilderEx.CreatePolygon(new List<Coordinate3D>(){coordsZ[6], coordsZ[7], coordsZ[8]})
};

Polygon polygon = GeometryEngine.Instance.Union(manyPolygonsZ) as Polygon;

地图点、折线、多边形内的多边形

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
// build a polygon      
List<MapPoint> pts = new List<MapPoint>();
pts.Add(MapPointBuilderEx.CreateMapPoint(1.0, 1.0));
pts.Add(MapPointBuilderEx.CreateMapPoint(1.0, 2.0));
pts.Add(MapPointBuilderEx.CreateMapPoint(2.0, 2.0));
pts.Add(MapPointBuilderEx.CreateMapPoint(2.0, 1.0));

Polygon poly = PolygonBuilderEx.CreatePolygon(pts);

// an inner point
MapPoint innerPt = MapPointBuilderEx.CreateMapPoint(1.5, 1.5);
bool within = GeometryEngine.Instance.Within(innerPt, poly); // within = true

// point on a boundary
within = GeometryEngine.Instance.Within(pts[0], poly); // within = false

// an interior line
MapPoint innerPt2 = MapPointBuilderEx.CreateMapPoint(1.25, 1.75);
List<MapPoint> innerLinePts = new List<MapPoint>();
innerLinePts.Add(innerPt);
innerLinePts.Add(innerPt2);

Polyline polyline = PolylineBuilderEx.CreatePolyline(innerLinePts);
within = GeometryEngine.Instance.Within(polyline, poly); // within = true

// a line that crosses the boundary
MapPoint outerPt = MapPointBuilderEx.CreateMapPoint(3, 1.5);
List<MapPoint> crossingLinePts = new List<MapPoint>();
crossingLinePts.Add(innerPt);
crossingLinePts.Add(outerPt);

polyline = PolylineBuilderEx.CreatePolyline(crossingLinePts);
within = GeometryEngine.Instance.Within(polyline, poly); // within = false


// polygon in polygon
Envelope env = EnvelopeBuilderEx.CreateEnvelope(innerPt, innerPt2);
within = GeometryEngine.Instance.Within(env, poly); // within = true

地理处理

常规

如何执行模型工具

1
2
3
4
5
6
7
8
9
10
11
12
// get the model tool's parameter syntax from the model's help
string input_roads = @"C:\data\Input.gdb\PlanA_Roads";
string buff_dist_field = "Distance"; // use values from a field
string input_vegetation = @"C:\data\Input.gdb\vegetation";
string output_data = @"C:\data\Output.gdb\ClippedFC2";

// the model name is ExtractVegetation
string tool_path = @"C:\data\MB\Models.tbx\ExtractVegetation";

var args = Geoprocessing.MakeValueArray(input_roads, buff_dist_field, input_vegetation, output_data);

var result = await Geoprocessing.ExecuteToolAsync(tool_path, args);

设置地理处理范围环境

1
2
3
var parameters = Geoprocessing.MakeValueArray(@"C:\data\data.gdb\HighwaysUTM11", @"C:\data\data.gdb\Highways_extent");
var ext = Geoprocessing.MakeEnvironmentArray(extent: "460532 3773964 525111 3827494");
var gp_result = await Geoprocessing.ExecuteToolAsync("management.CopyFeatures", parameters, ext);

在地理处理窗格中打开脚本工具对话框

1
2
3
4
5
6
7
8
9
string input_data = @"C:\data\data.gdb\Population";
string out_pdf = @"C:\temp\Reports.pdf";
string field_name = "INCOME";
// use defaults for other parameters - no need to pass any value
var arguments = Geoprocessing.MakeValueArray(input_data, out_pdf, field_name);

string toolpath = @"C:\data\WorkflowTools.tbx\MakeHistogram";

Geoprocessing.OpenToolDialog(toolpath, arguments);

获取地理处理工程项目

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
var gpItems = CoreModule.CurrentProject.Items.OfType<GeoprocessingProjectItem>();

// go through all the available toolboxes
foreach (var gpItem in gpItems)
{
var itemsInsideToolBox = gpItem.GetItems();

// then for each toolbox list the tools inside
foreach (var toolItem in itemsInsideToolBox)
{
string newTool = String.Join(";", new string[] { toolItem.Path, toolItem.Name });
// do something with the newTool
// for example, add to a list to track or use them later
}
}

阻止使用 GP 创建的要素类自动添加到地图

1
2
3
4
5
// However, settings in Pro App's Geoprocessing Options will override option set in code
// for example, in Pro App's Options > Geoprocessing dialog, if you check 'Add output datasets to an open map'
// then the output WILL BE added to history overriding settings in code
var CopyfeaturesParams = Geoprocessing.MakeValueArray("C:\\data\\Input.gdb\\PlanA_Roads", "C:\\data\\Input.gdb\\Roads_copy");
IGPResult gpResult = await Geoprocessing.ExecuteToolAsync("management.CopyFeatures", CopyfeaturesParams, null, null, null, GPExecuteToolFlags.None);

GPExecuteToolFlags.AddToHistory 会将执行消息添加到 Hisotry

1
2
3
4
5
// However, settings in Pro App's Geoprocessing Options will override option set in code
// for example, if in Options > Geoprocessing dialog, if you uncheck 'Write geoprocessing operations to Geoprocessing History'
// then the output will not be added to history.
var args2 = Geoprocessing.MakeValueArray("C:\\data\\Vegetation.shp", "NewField", "TEXT");
var result2 = await Geoprocessing.ExecuteToolAsync("management.AddField", args2, null, null, null, GPExecuteToolFlags.AddToHistory);

多环缓冲器

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
//The data referenced in this snippet can be downloaded from the arcgis-pro-sdk-community-samples repo
//https://github.com/Esri/arcgis-pro-sdk-community-samples
async Task<IGPResult> CreateRings(EditingTemplate currentTemplate)
{
var paramsArray = Geoprocessing.MakeValueArray(currentTemplate.MapMember.Name,
@"C:\Data\FeatureTest\FeatureTest.gdb\Points_MultipleRingBuffer",
new List<string> { "1000", "2000" }, "Meters", "Distance",
"ALL", "FULL");

IGPResult ringsResult = await Geoprocessing.ExecuteToolAsync("Analysis.MultipleRingBuffer", paramsArray);
var messages = string.IsNullOrEmpty(gpResult.ReturnValue)
? $@"Error in gp tool: {gpResult.ErrorMessages}"
: $@"Ok: {gpResult.ReturnValue}";

return ringsResult;
}

地理处理工具的非阻塞执行

1
2
3
4
5
6
7
8
9
10
11
12
//The data referenced in this snippet can be downloaded from the arcgis-pro-sdk-community-samples repo
//https://github.com/Esri/arcgis-pro-sdk-community-samples
string in_data = @"C:\tools\data.gdb\cities";
string cities_buff = @"E:\data\data.gdb\cities_2km";

var valueArray = Geoprocessing.MakeValueArray(in_data, cities_buff, "2000 Meters");

// to let the GP tool run asynchronously without blocking the main thread
// use the GPThread option of GPExecuteToolFlasgs
//
GPExecuteToolFlags flags = GPExecuteToolFlags.GPThread; // instruct the tool run non-blocking GPThread
IGPResult bufferResult = await Geoprocessing.ExecuteToolAsync("Analysis.Buffer", valueArray, null, null, null, flags);

如何传递具有多个或复杂输入值的参数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
var environments = Geoprocessing.MakeEnvironmentArray(overwriteoutput: true);

string toolName = "Snap_edit"; // or use edit.Snap

// Snap tool takes multiple inputs each of which has
// Three (3) parts: a feature class or layer, a string value and a distance
// Each part is separated by a semicolon - you can get example of sytax from the tool documentation page
var snapEnv = @"'C:/SnapProject/fgdb.gdb/line_1' END '2 Meters';'C:/SnapProject/fgdb.gdb/points_1' VERTEX '1 Meters';'C:/SnapProject/fgdb.gdb/otherline_1' END '20 Meters'";

var infc = @"C:/SnapProject/fgdb.gdb/poly_1";

var snapParams = Geoprocessing.MakeValueArray(infc, snapEnv);

GPExecuteToolFlags tokens = GPExecuteToolFlags.RefreshProjectItems | GPExecuteToolFlags.GPThread | GPExecuteToolFlags.AddToHistory;

IGPResult snapResult = await Geoprocessing.ExecuteToolAsync(toolName, parameters, environments, null, null, tokens);

//return gpResult;

地理处理选项

获取地理处理选项

1
2
3
4
5
6
//These options are for behavior of interactive GP tools _only_.

var overwrite_gp = ApplicationOptions.GeoprocessingOptions.OverwriteExistingDatasets;
var remove_gp = ApplicationOptions.GeoprocessingOptions.RemoveOverwrittenLayers;
var addoutput_gp = ApplicationOptions.GeoprocessingOptions.AddOutputDatasetsToOpenMap;
var history_gp = ApplicationOptions.GeoprocessingOptions.WriteGPOperationsToHistory;

设置地理处理选项

1
2
3
4
5
6
7
8
9
10
11
12
//Note: changing these options modifies behavior of interactive GP tools _only_.
//Use the ArcGIS.Desktop.Core.Geoprocessing.GPExecuteToolFlags enum parameter
//to modify the behavior of Geoprocessing.ExecuteToolAsync(...)

//Note: setting GeoprocessingOptions requires the QueuedTask
QueuedTask.Run(() =>
{
ApplicationOptions.GeoprocessingOptions.SetOverwriteExistingDatasets(true);
ApplicationOptions.GeoprocessingOptions.SetRemoveOverwrittenLayers(false);
ApplicationOptions.GeoprocessingOptions.SetAddOutputDatasetsToOpenMap(true);
ApplicationOptions.GeoprocessingOptions.SetWriteGPOperationsToHistory(false);
});

图形图层

常规

创建图形图层

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
var map = MapView.Active.Map;
if (map.MapType != MapType.Map)
return;// not 2D

var gl_param = new GraphicsLayerCreationParams { Name = "Graphics Layer" };
QueuedTask.Run(() =>
{
//By default will be added to the top of the TOC
var graphicsLayer = LayerFactory.Instance.CreateLayer<ArcGIS.Desktop.Mapping.GraphicsLayer>(gl_param, map);

//Add to the bottom of the TOC
gl_param.MapMemberIndex = -1; //bottom
LayerFactory.Instance.CreateLayer<ArcGIS.Desktop.Mapping.GraphicsLayer>(gl_param, map);

//Add a graphics layer to a group layer...
var group_layer = map.GetLayersAsFlattenedList().OfType<GroupLayer>().First();
LayerFactory.Instance.CreateLayer<ArcGIS.Desktop.Mapping.GraphicsLayer>(gl_param, group_layer);

//TODO...use the graphics layer
//

// or use the specific CreateGroupLayer method
LayerFactory.Instance.CreateGroupLayer(map, -1, "Graphics Layer");
});

访问图形层

1
2
3
4
5
6
//get the first graphics layer in the map's collection of graphics layers
var graphicsLayer = map.GetLayersAsFlattenedList().OfType<ArcGIS.Desktop.Mapping.GraphicsLayer>().FirstOrDefault();
if (graphicsLayer != null)
{
//TODO...use the graphics layer
}

复制图形元素

1
2
3
//on the QueuedTask
var elems = sourceGraphicsLayer.FindElements(new List<string>() { "Point 1", "Line 3", "Text 1" });
var copiedElements = targetGraphicsLayer.CopyElements(elems);

删除图形元素

1
2
//on the QueuedTask      
graphicsLayer.RemoveElements(graphicsLayer.GetSelectedElements());

创建图形元素

使用 CIMG 图形元素的点图形元素

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
var graphicsLayer = MapView.Active.Map.GetLayersAsFlattenedList()
.OfType<ArcGIS.Desktop.Mapping.GraphicsLayer>().FirstOrDefault();
if (graphicsLayer == null)
return;
QueuedTask.Run(() =>
{
//Place symbol in the center of the map
var extent = MapView.Active.Extent;
var location = extent.Center;

//specify a symbol
var pt_symbol = SymbolFactory.Instance.ConstructPointSymbol(
ColorFactory.Instance.GreenRGB);

//create a CIMGraphic
var graphic = new CIMPointGraphic()
{
Symbol = pt_symbol.MakeSymbolReference(),
Location = location //center of map
};
graphicsLayer.AddElement(graphic);
});

使用 CIMG 的线条图形元素

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
//On the QueuedTask
//Place a line symbol using the extent's lower left and upper right corner.
var extent = MapView.Active.Extent;
//get the lower left corner of the extent
var pointFromCoordinates = new Coordinate2D(extent.XMin, extent.YMin);
//get the upper right corner of the extent
var pointToCoordinates = new Coordinate2D(extent.XMax, extent.YMax);
List<Coordinate2D> points = new List<Coordinate2D> { pointFromCoordinates, pointToCoordinates };
//create the polyline
var lineSegment = PolylineBuilderEx.CreatePolyline(points);

//specify a symbol
var line_symbol = SymbolFactory.Instance.ConstructLineSymbol(
ColorFactory.Instance.GreenRGB);

//create a CIMGraphic
var graphic = new CIMLineGraphic()
{
Symbol = line_symbol.MakeSymbolReference(),
Line = lineSegment,
};
graphicsLayer.AddElement(graphic);

使用 CIMG 的多边形图形元素

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
//On the QueuedTask
//Place a polygon symbol using the mapview extent geometry
var extent = MapView.Active.Extent;
//Contract the extent
var polygonEnv = extent.Expand(-100000, -90000, false);
//create a polygon using the envelope
var polygon = PolygonBuilderEx.CreatePolygon(polygonEnv);

//specify a symbol
var poly_symbol = SymbolFactory.Instance.ConstructPolygonSymbol(
ColorFactory.Instance.GreenRGB);

//create a CIMGraphic
var graphic = new CIMPolygonGraphic()
{
Symbol = poly_symbol.MakeSymbolReference(),
Polygon = polygon,
};
graphicsLayer.AddElement(graphic);

使用 CIMG 的多点图形元素

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
//On the QueuedTask
//Place a multipoint graphic using the mapview extent geometry
var extent = MapView.Active.Extent;
//Contract the extent
var polygonEnv = extent.Expand(-100000, -90000, false);
//create a polygon using the envelope
var polygon = PolygonBuilderEx.CreatePolygon(polygonEnv);
//Create MultipPoints from the polygon
var multiPoints = MultipointBuilderEx.CreateMultipoint(polygon);
//specify a symbol
var point_symbol = SymbolFactory.Instance.ConstructPointSymbol(
ColorFactory.Instance.GreenRGB);

//create a CIMGraphic
var graphic = new CIMMultipointGraphic
{
Symbol = point_symbol.MakeSymbolReference(),
Multipoint = multiPoints
};
graphicsLayer.AddElement(graphic);

使用 CIMSymbol 的图形元素

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
var graphicsLayer = MapView.Active.Map.GetLayersAsFlattenedList()
.OfType<ArcGIS.Desktop.Mapping.GraphicsLayer>().FirstOrDefault();
if (graphicsLayer == null)
return;
QueuedTask.Run(() =>
{
//Place symbol in the center of the map
var extent = MapView.Active.Extent;
var location = extent.Center;

//specify a symbol
var pt_symbol = SymbolFactory.Instance.ConstructPointSymbol(
ColorFactory.Instance.GreenRGB);
graphicsLayer.AddElement(location, pt_symbol);
});

文本图形元素

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
var graphicsLayer = MapView.Active.Map.GetLayersAsFlattenedList()
.OfType<ArcGIS.Desktop.Mapping.GraphicsLayer>().FirstOrDefault();
if (graphicsLayer == null)
return;
QueuedTask.Run(() =>
{
//Place symbol in the center of the map
var extent = MapView.Active.Extent;
var location = extent.Center;

//specify a text symbol
var text_symbol = SymbolFactory.Instance.ConstructTextSymbol
(ColorFactory.Instance.BlackRGB, 8.5, "Corbel", "Regular");

graphicsLayer.AddElement(location, text_symbol, "Text Example");
});

批量图形创建

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
//Point Feature layer to convert into graphics
var lyr = MapView.Active?.Map?.GetLayersAsFlattenedList().OfType<FeatureLayer>().FirstOrDefault();
//Graphics layer to store the graphics to
var gl = MapView.Active.Map.GetLayersAsFlattenedList().OfType<ArcGIS.Desktop.Mapping.GraphicsLayer>().FirstOrDefault();
if (lyr == null) return;
QueuedTask.Run(() =>
{
//Point symbol for graphics
var pointSymbol = SymbolFactory.Instance.ConstructPointSymbol(CIMColor.CreateRGBColor(100, 255, 40), 10, SimpleMarkerStyle.Circle);
//Collection to hold the point graphics
var listGraphicElements = new List<CIMGraphic>();
//Iterate through each point feature in the feature layer
using (RowCursor rows = lyr.Search()) //execute
{
int i = 0;
while (rows.MoveNext())
{
using (var feature = rows.Current as Feature)
{
//Create a point graphic for the feature
var crimePt = feature.GetShape() as MapPoint;
if (crimePt != null)
{
var cimGraphicElement = new CIMPointGraphic
{
Location = crimePt, //MapPoint
Symbol = pointSymbol.MakeSymbolReference()
};
//Add the point feature to the collection
listGraphicElements.Add(cimGraphicElement);
i++;
}
}
}
}
//Magic happens...Add all the features to the Graphics layer
gl.AddElements(listGraphicElements);
});

图形元素选择

选择图形元素

1
2
3
4
5
6
7
8
9
10
11
12
var graphicsLayer = MapView.Active.Map.GetLayersAsFlattenedList()
.OfType<ArcGIS.Desktop.Mapping.GraphicsLayer>().FirstOrDefault();
if (graphicsLayer == null)
return;
var elements = graphicsLayer.GetElementsAsFlattenedList()
.Where(e => e.Name.StartsWith("Text"));
QueuedTask.Run(() =>
{
graphicsLayer.SelectElements(elements);
//or select one element
graphicsLayer.SelectElement(elements.FirstOrDefault());
});

查找图形元素

1
2
3
4
5
6
7
8
9
10
11
12
13
14
//on the QueuedTask
//Find elements by name
var elems = graphicsLayer.FindElements(new List<string>() { "Point 1", "Line 3", "Text 1" });
//Find elements by type
//Find all point graphics in the Graphics Layer
var pointGraphics = graphicsLayer.GetElementsAsFlattenedList().Where(elem => elem.GetGraphic() is CIMPointGraphic);
//Find all line graphics in the Graphics Layer
var lineGraphics = graphicsLayer.GetElementsAsFlattenedList().Where(elem => elem.GetGraphic() is CIMLineGraphic);
//Find all polygon graphics in the Graphics Layer
var polygonGraphics = graphicsLayer.GetElementsAsFlattenedList().Where(elem => elem.GetGraphic() is CIMPolygonGraphic);
//Find all text graphics in the Graphics Layer
var textGraphics = graphicsLayer.GetElementsAsFlattenedList().Where(elem => elem.GetGraphic() is CIMTextGraphic);
//Find all picture graphics in the Graphics Layer
var pictureGraphic = graphicsLayer.GetElementsAsFlattenedList().Where(elem => elem.GetGraphic() is CIMPictureGraphic);

所有图形图层中元素的空间选择

1
2
3
4
5
6
7
8
9
10
11
12
13
14
//Map Tool is used to perform Spatial selection.
//Graphic selection uses the selection geometry
//to intersect the geometries of those elements (graphic or group)
//that will be selected and then highlights them.
protected override async Task<bool> OnSketchCompleteAsync(Geometry geometry)
{
var selPoly = geometry as Polygon;
return await QueuedTask.Run(() =>
{
//note: the selected elements may belong to more than one layer...
var elems = MapView.Active.SelectElements(selPoly, SelectionCombinationMethod.New);
return true;
});
}

在一个图形图层中对元素进行空间选择

1
2
3
4
5
6
//on the QueuedTask
//Create an extent to use for the spatial selection
var extent = MapView.Active.Extent;
var selectionExtent = extent.Expand(0.5, 0.5, true);
//Select elements in specified graphics layer using the selection extent.
var selectedElements = MapView.Active.SelectElements(graphicsLayer, selectionExtent, SelectionCombinationMethod.Add);

选择文本图形元素

1
2
3
4
5
6
var graphicsLayer = MapView.Active.Map.GetLayersAsFlattenedList()
.OfType<ArcGIS.Desktop.Mapping.GraphicsLayer>().FirstOrDefault();
if (graphicsLayer == null)
return;
var all_text = graphicsLayer.GetElementsAsFlattenedList()
.Where(e => e.GetGraphic() is CIMTextGraphic);

取消选择图形元素

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
var graphicsLayer = MapView.Active.Map.GetLayersAsFlattenedList()
.OfType<ArcGIS.Desktop.Mapping.GraphicsLayer>().FirstOrDefault();
if (graphicsLayer == null)
return;
//unselect the first element in the currently selected elements
var elem = graphicsLayer.GetSelectedElements().FirstOrDefault();
QueuedTask.Run( () => {
if (elem != null)
//Unselect one element
graphicsLayer.UnSelectElement(elem);

//unselect all elements
graphicsLayer.UnSelectElements();
//equivalent to
graphicsLayer.ClearSelection();
});

图形元素事件

订阅元素选择更改事件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
ArcGIS.Desktop.Layouts.Events.ElementEvent.Subscribe((args) => {
//check if the container is a graphics layer - could be a Layout (or even map view)
if (args.Container is ArcGIS.Desktop.Mapping.GraphicsLayer graphicsLayer)
{
//get the total selection count for the container
var count = args.Elements.Count();
//Check count - could have been an unselect or clearselect
if (count > 0)
{
//this is a selection or add to selection
var elems = graphicsLayer.GetSelectedElements();
//TODO process the selection...
}
else
{
//This is an unselect or clear selection
//TODO process the unselect or clear select
}
}
});

对图形元素进行分组和排序

组图形元素

1
2
3
4
5
6
7
8
9
var graphicsLayer = MapView.Active.Map.GetLayersAsFlattenedList()
.OfType<ArcGIS.Desktop.Mapping.GraphicsLayer>().FirstOrDefault();
if (graphicsLayer == null)
return;

var elemsToGroup = graphicsLayer.GetSelectedElements();
//Note: run within the QueuedTask
//group elements
var groupElement = graphicsLayer.GroupElements(elemsToGroup);

取消组合图形元素

1
2
3
4
5
6
7
8
9
10
11
12
13
14
var selectedElements = graphicsLayer.GetSelectedElements().ToList(); ;
if (selectedElements?.Any() == false)//must be at least 1.
return;
var elementsToUnGroup = new List<GroupElement>();
//All selected elements should be grouped.
if (selectedElements.Count() == selectedElements.OfType<GroupElement>().Count())
{
//Convert to a GroupElement list.
elementsToUnGroup = selectedElements.ConvertAll(x => (GroupElement)x);
}
if (elementsToUnGroup.Count() == 0)
return;
//UnGroup
graphicsLayer.UnGroupElements(elementsToUnGroup);

组元素的父级

1
2
3
4
//check the parent
var parent = groupElement.Elements.First().GetParent();//will be the group element
//top-most parent
var top_most = groupElement.Elements.First().GetParent(true);//will be the GraphicsLayer

排序:向后发送和向前发送

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
//On the QueuedTask
//get the current selection set
var sel_elems = graphicsLayer.GetSelectedElements();
//can they be brought forward? This will also check that all elements have the same parent
if (graphicsLayer.CanBringForward(sel_elems))
{
//bring forward
graphicsLayer.BringForward(sel_elems);
//bring to front (of parent)
//graphicsLayer.BringToFront(sel_elems);
}
else if (graphicsLayer.CanSendBackward(sel_elems))
{
//send back
graphicsLayer.SendBackward(sel_elems);
//send to the back (of parent)
//graphicsLayer.SendToBack(sel_elems);
}

获取 Z 顺序

1
2
3
4
var selElementsZOrder = graphicsLayer.GetSelectedElements();
//list out the z order
foreach (var elem in selElementsZOrder)
System.Diagnostics.Debug.WriteLine($"{elem.Name}: z-order {elem.ZOrder}");

修改图形元素

移动图形元素

1
2
3
4
5
6
7
8
9
10
11
12
13
//Each selected element will move to a set distance to the upper right.
var selElements = graphicsLayer.GetSelectedElements();
if (selElements.Count == 0) return;
//Move the element up
foreach (var selElement in selElements)
{
//Get the element's bounds
var elementPoly = PolygonBuilderEx.CreatePolygon(selElement.GetBounds());
//get the coordinates of the element bounding envelope.
var pointsList = elementPoly.Copy2DCoordinatesToList();
//Move the element's Anchor point to the upper right.
selElement.SetAnchorPoint(pointsList[1]);
}

修改图形元素的符号系统

1
2
3
4
5
6
7
8
9
10
11
12
13
14
//within a queued Task
//get the first line element in the layer
var ge = graphicsLayer.FindElement("Line 10") as GraphicElement;
var graphic = ge.GetGraphic();
if (graphic is CIMLineGraphic lineGraphic)
{
//change its symbol
lineGraphic.Symbol =
SymbolFactory.Instance.ConstructLineSymbol(
SymbolFactory.Instance.ConstructStroke(
ColorFactory.Instance.BlueRGB, 2, SimpleLineStyle.DashDot)).MakeSymbolReference();
//apply the change
ge.SetGraphic(lineGraphic);
}

布局

布局项目项

参考布局项目项及其关联布局

1
2
3
4
5
6
7
8
9
10
11
//Reference layout project items and their associated layout.
//A layout project item is an item that appears in the Layouts
//folder in the Catalog pane.

//Reference all the layout project items
IEnumerable<LayoutProjectItem> layouts =
Project.Current.GetItems<LayoutProjectItem>();

//Or reference a specific layout project item by name
LayoutProjectItem layoutItem = Project.Current.GetItems<LayoutProjectItem>()
.FirstOrDefault(item => item.Name.Equals("MyLayout"));

在新视图中打开布局项目项

1
2
3
4
5
6
7
8
9
10
11
12
//Open a layout project item in a new view.
//A layout project item may exist but it may not be open in a view.

//Reference a layout project item by name
LayoutProjectItem someLytItem = Project.Current.GetItems<LayoutProjectItem>()
.FirstOrDefault(item => item.Name.Equals("MyLayout"));

//Get the layout associated with the layout project item
Layout layout = await QueuedTask.Run(() => someLytItem.GetLayout()); //Worker thread

//Create the new pane - call on UI
ILayoutPane iNewLayoutPane = await ProApp.Panes.CreateLayoutPaneAsync(layout); //GUI thread

激活已打开的布局视图

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
//Activate an already open layout view.
//A layout view may be open but it may not be active.

//Find the pane that references the layout and activate it.
//Note - there can be multiple panes referencing the same layout.
foreach (var pane in ProApp.Panes)
{
var layoutPane = pane as ILayoutPane;
if (layoutPane == null) //if not a layout view, continue to the next pane
continue;
if (layoutPane.LayoutView.Layout == layout) //activate the view
{
(layoutPane as Pane).Activate();
return;
}
}

引用活动布局视图

1
2
3
4
5
6
7
8
9
//Reference the active layout view.

//Confirm if the current, active view is a layout view.
//If it is, do something.
LayoutView activeLayoutView = LayoutView.Active;
if (activeLayoutView != null)
{
// do something
}

将 pagx 导入到项目中

1
2
3
4
5
6
7
8
9
//Import a pagx into a project.

//Create a layout project item from importing a pagx file
await QueuedTask.Run(() =>
{
IProjectItem pagx = ItemFactory.Instance.Create(
@"C:\Temp\Layout.pagx") as IProjectItem;
Project.Current.AddItem(pagx);
});

删除布局项目项

1
2
3
4
//Remove a layout project item.

//Remove the layout fro the project
await QueuedTask.Run(() => Project.Current.RemoveItem(layoutItem));

创建新的基本布局并将其打开

1
2
3
4
5
6
7
8
9
10
11
12
//Create a new, basic layout and open it.

//Create layout with minimum set of parameters on the worker thread
Layout lyt = await QueuedTask.Run(() =>
{
var newLayout = LayoutFactory.Instance.CreateLayout(8.5, 11, LinearUnit.Inches);
newLayout.SetName("New 8.5x11 Layout");
return newLayout;
});

//Open new layout on the GUI thread
await ProApp.Panes.CreateLayoutPaneAsync(lyt);

使用修改后的 CIM 创建新布局并将其打开

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
//Create a new layout using a modified CIM and open it.
//The CIM exposes additional members that may not be
//available through the managed API.
//In this example, optional guides are added.

//Create a new CIMLayout on the worker thread
Layout newCIMLayout = await QueuedTask.Run(() =>
{
//Set up a CIM page
CIMPage newPage = new CIMPage
{
//required parameters
Width = 8.5,
Height = 11,
Units = LinearUnit.Inches,

//optional rulers
ShowRulers = true,
SmallestRulerDivision = 0.5,

//optional guides
ShowGuides = true
};
CIMGuide guide1 = new CIMGuide
{
Position = 1,
Orientation = Orientation.Vertical
};
CIMGuide guide2 = new CIMGuide
{
Position = 6.5,
Orientation = Orientation.Vertical
};
CIMGuide guide3 = new CIMGuide
{
Position = 1,
Orientation = Orientation.Horizontal
};
CIMGuide guide4 = new CIMGuide
{
Position = 10,
Orientation = Orientation.Horizontal
};

List<CIMGuide> guideList = new List<CIMGuide>
{
guide1,
guide2,
guide3,
guide4
};
newPage.Guides = guideList.ToArray();

//Construct the new layout using the customized cim definitions
var layout_local = LayoutFactory.Instance.CreateLayout(newPage);
layout_local.SetName("New 8.5x11 Layout");
return layout_local;
});

//Open new layout on the GUI thread
await ProApp.Panes.CreateLayoutPaneAsync(newCIMLayout);

更改布局页面大小

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
//Change the layout page size.

//Reference the layout project item
LayoutProjectItem lytItem = Project.Current.GetItems<LayoutProjectItem>()
.FirstOrDefault(item => item.Name.Equals("MyLayout"));
if (layoutItem != null)
{
await QueuedTask.Run(() =>
{
//Get the layout
Layout lyt = lytItem.GetLayout();
if (lyt != null)
{
//Change properties
CIMPage page = lyt.GetPage();
page.Width = 8.5;
page.Height = 11;

//Apply the changes to the layout
lyt.SetPage(page);
}
});
}

ProSnippet Group CIM Graphics and GraphicFactory

创建圆形图形

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
//Must be on QueuedTask.Run(() => { ...

//Build geometry
Coordinate2D center = new Coordinate2D(2, 4);
EllipticArcSegment circle_seg = EllipticArcBuilderEx.CreateCircle(
new Coordinate2D(2, 4), 0.5, ArcOrientation.ArcClockwise, null);
var circle_poly = PolygonBuilderEx.CreatePolygon(PolylineBuilderEx.CreatePolyline(circle_seg));

//PolylineBuilderEx.CreatePolyline(cir, AttributeFlags.AllAttributes));
//Set symbolology, create and add element to layout
CIMStroke outline = SymbolFactory.Instance.ConstructStroke(
ColorFactory.Instance.BlackRGB, 2.0, SimpleLineStyle.Dash);

CIMPolygonSymbol circleSym = SymbolFactory.Instance.ConstructPolygonSymbol(
ColorFactory.Instance.RedRGB, SimpleFillStyle.Solid, outline);
SymbolFactory.Instance.ConstructPolygonSymbol(null,
SymbolFactory.Instance.ConstructStroke(ColorFactory.Instance.RedRGB, 2));

var circleGraphic = GraphicFactory.Instance.CreateSimpleGraphic(circle_poly, circleSym);

//Make an element to add to GraphicsLayer or Layout
//var elemInfo = new ElementInfo() { Anchor = Anchor.CenterPoint };
//GraphicElement cirElm = ElementFactory.Instance.CreateGraphicElement(
// container, circleGraphic, "New Circle", true, elemInfo);

创建圆形文本图形

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
//Must be on QueuedTask.Run(() => { ...

//Build geometry
Coordinate2D center = new Coordinate2D(4.5, 4);
var eabCir = new EllipticArcBuilderEx(center, 0.5, ArcOrientation.ArcClockwise);
var cir = eabCir.ToSegment();

var poly = PolygonBuilderEx.CreatePolygon(
PolylineBuilderEx.CreatePolyline(cir, AttributeFlags.AllAttributes));

//Set symbolology, create and add element to layout
CIMTextSymbol sym = SymbolFactory.Instance.ConstructTextSymbol(
ColorFactory.Instance.GreenRGB, 10, "Arial", "Regular");
string text = "Circle, circle, circle";

var graphic = GraphicFactory.Instance.CreateSimpleTextGraphic(
TextType.CircleParagraph, poly, sym, text);

//Make an element to add to GraphicsLayer or Layout
//var ge = ElementFactory.Instance.CreateGraphicElement(container, graphic,
// "New Circle Text", true);

创建贝塞尔图形

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
//Must be on QueuedTask.Run(() => { ...

//Build geometry
Coordinate2D pt1 = new Coordinate2D(3.5, 7.5);
Coordinate2D pt2 = new Coordinate2D(4.16, 8);
Coordinate2D pt3 = new Coordinate2D(4.83, 7.1);
Coordinate2D pt4 = new Coordinate2D(5.5, 7.5);
var bez = new CubicBezierBuilderEx(pt1, pt2, pt3, pt4);
var bezSeg = bez.ToSegment();
Polyline bezPl = PolylineBuilderEx.CreatePolyline(bezSeg, AttributeFlags.AllAttributes);

//Set symbolology, create and add element to layout
CIMTextSymbol sym = SymbolFactory.Instance.ConstructTextSymbol(
ColorFactory.Instance.BlackRGB, 24, "Comic Sans MS", "Regular");

var graphic = GraphicFactory.Instance.CreateSimpleTextGraphic(
TextType.SplinedText, bezPl, sym, "Splined text");

//Make an element to add to GraphicsLayer or Layout
//var ge = ElementFactory.Instance.CreateGraphicElement(container, graphic);

创建图例图面图形

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
//Must be on QueuedTask.Run(() => { ...

//Build geometry
List<Coordinate2D> plyCoords = new List<Coordinate2D>();
plyCoords.Add(new Coordinate2D(1, 1));
plyCoords.Add(new Coordinate2D(1.25, 2));
plyCoords.Add(new Coordinate2D(1.5, 1.1));
plyCoords.Add(new Coordinate2D(1.75, 2));
plyCoords.Add(new Coordinate2D(2, 1.1));
plyCoords.Add(new Coordinate2D(2.25, 2));
plyCoords.Add(new Coordinate2D(2.5, 1.1));
plyCoords.Add(new Coordinate2D(2.75, 2));
plyCoords.Add(new Coordinate2D(3, 1));
Polygon poly = PolygonBuilderEx.CreatePolygon(plyCoords);

//Set symbolology, create and add element to layout
CIMStroke outline = SymbolFactory.Instance.ConstructStroke(
ColorFactory.Instance.BlackRGB, 2.0, SimpleLineStyle.Solid);
CIMPolygonSymbol polySym = SymbolFactory.Instance.ConstructPolygonSymbol(
ColorFactory.Instance.RedRGB, SimpleFillStyle.ForwardDiagonal, outline);

var graphic = GraphicFactory.Instance.CreateLegendPatchGraphic(
PatchShape.AreaBoundary, poly.Extent, polySym);

//Make an element to add to GraphicsLayer or Layout
//
//var elemInfo = new ElementInfo()
//{
// CustomProperties = null,
// Anchor = Anchor.LeftMidPoint
//};
//var ge = ElementFactory.Instance.CreateGraphicElement(container, graphic,
// "New Legend Patch", true, elemInfo);

创建箭头图形

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
//Must be on QueuedTask.Run(() => { ...

//Build geometry
List<Coordinate2D> plCoords = new List<Coordinate2D>();
plCoords.Add(new Coordinate2D(1, 8.5));
plCoords.Add(new Coordinate2D(1.66, 9));
plCoords.Add(new Coordinate2D(2.33, 8.1));
plCoords.Add(new Coordinate2D(3, 8.5));
Polyline linePl = PolylineBuilderEx.CreatePolyline(plCoords);

//Set up the arrow info
var arrowInfo = new ArrowInfo()
{
ArrowHeadKey = ArrowInfo.DefaultArrowHeadKeys[1],
ArrowOnBothEnds = true,
ArrowSizePoints = 30,
LineWidthPoints = 15
};

var graphic = GraphicFactory.Instance.CreateArrowGraphic(linePl, arrowInfo);

//Make an element to add to GraphicsLayer or Layout
//var ge = ElementFactory.Instance.CreateGraphicElement(
// container, graphic, "Arrow Line", false);

创建图片图形

1
2
3
4
5
6
7
8
9
10
11
12
13
//Must be on QueuedTask.Run(() => { ...

//Build geometry
Coordinate2D ll = new Coordinate2D(3.5, 1);
Coordinate2D ur = new Coordinate2D(5.5, 2);
Envelope env = EnvelopeBuilderEx.CreateEnvelope(ll, ur);

//Create and add element to layout
//string picPath = ApplicationUtilities.BASEPATH + _settings.baseFolder + "irefusetowatchthismovi�.jpg";
var graphic = GraphicFactory.Instance.CreatePictureGraphic(env.Center, picPath);

//Make an element to add to GraphicsLayer or Layout
//var ge = ElementFactory.Instance.CreateGraphicElement(layout, graphic);

创建布局图形元素

创建椭圆图形元素

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
//Must be on QueuedTask.Run(() => { ...

//Build geometry
Coordinate2D center = new Coordinate2D(2, 2.75);
var eabElp = new EllipticArcBuilderEx(center, 0, 1, 0.45,
ArcOrientation.ArcClockwise);
var ellipse = eabElp.ToSegment();

//Set symbolology, create and add element to layout
CIMStroke outline = SymbolFactory.Instance.ConstructStroke(
ColorFactory.Instance.GreenRGB, 2.0,
SimpleLineStyle.Dot);
CIMPolygonSymbol ellipseSym = SymbolFactory.Instance.ConstructPolygonSymbol(
ColorFactory.Instance.GreyRGB, SimpleFillStyle.Vertical,
outline);

var poly = PolygonBuilderEx.CreatePolygon(
PolylineBuilderEx.CreatePolyline(ellipse, AttributeFlags.AllAttributes));

var elpElm = ElementFactory.Instance.CreateGraphicElement(
container, poly, ellipseSym, "New Ellipse");

创建套索线,手绘图形元素

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
//Must be on QueuedTask.Run(() => { ...

//Build geometry
List<Coordinate2D> plCoords = new List<Coordinate2D>();
plCoords.Add(new Coordinate2D(1.5, 10.5));
plCoords.Add(new Coordinate2D(1.25, 9.5));
plCoords.Add(new Coordinate2D(1, 10.5));
plCoords.Add(new Coordinate2D(0.75, 9.5));
plCoords.Add(new Coordinate2D(0.5, 10.5));
plCoords.Add(new Coordinate2D(0.5, 1));
plCoords.Add(new Coordinate2D(0.75, 2));
plCoords.Add(new Coordinate2D(1, 1));
Polyline linePl = PolylineBuilderEx.CreatePolyline(plCoords);

//Set symbolology, create and add element to layout
CIMLineSymbol lineSym = SymbolFactory.Instance.ConstructLineSymbol(
ColorFactory.Instance.BlackRGB, 2.0, SimpleLineStyle.Solid);
//var graphic = GraphicFactory.Instance.CreateShapeGraphic(linePl, lineSym);

var ge = ElementFactory.Instance.CreateGraphicElement(
container, linePl, lineSym, "New Freehand");

创建套索多边形,手绘元素

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
//Must be on QueuedTask.Run(() => { ...

List<Coordinate2D> plyCoords = new List<Coordinate2D>();
plyCoords.Add(new Coordinate2D(1, 1));
plyCoords.Add(new Coordinate2D(1.25, 2));
plyCoords.Add(new Coordinate2D(1.5, 1.1));
plyCoords.Add(new Coordinate2D(1.75, 2));
plyCoords.Add(new Coordinate2D(2, 1.1));
plyCoords.Add(new Coordinate2D(2.25, 2));
plyCoords.Add(new Coordinate2D(2.5, 1.1));
plyCoords.Add(new Coordinate2D(2.75, 2));
plyCoords.Add(new Coordinate2D(3, 1));
Polygon poly = PolygonBuilderEx.CreatePolygon(plyCoords);

//Set symbolology, create and add element to layout
CIMStroke outline = SymbolFactory.Instance.ConstructStroke(
ColorFactory.Instance.BlackRGB, 2.0, SimpleLineStyle.Solid);
CIMPolygonSymbol polySym = SymbolFactory.Instance.ConstructPolygonSymbol(
ColorFactory.Instance.RedRGB, SimpleFillStyle.ForwardDiagonal, outline);

ElementFactory.Instance.CreateGraphicElement(
container, poly, polySym, "New Lasso");

创建线元素

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
//Must be on QueuedTask.Run(() => { ...

//Build geometry
List<Coordinate2D> plCoords = new List<Coordinate2D>();
plCoords.Add(new Coordinate2D(1, 8.5));
plCoords.Add(new Coordinate2D(1.66, 9));
plCoords.Add(new Coordinate2D(2.33, 8.1));
plCoords.Add(new Coordinate2D(3, 8.5));
Polyline linePl = PolylineBuilderEx.CreatePolyline(plCoords);

//Reference a line symbol in a style
var ProjectStyles = Project.Current.GetItems<StyleProjectItem>();
StyleProjectItem style = ProjectStyles.First(x => x.Name == "ArcGIS 2D");
var symStyle = style.SearchSymbols(StyleItemType.LineSymbol, "Line with 2 Markers")[0];
CIMLineSymbol lineSym = symStyle.Symbol as CIMLineSymbol;
lineSym.SetSize(20);

//Set symbolology, create and add element to layout
//CIMLineSymbol lineSym = SymbolFactory.Instance.ConstructLineSymbol(ColorFactory.Instance.BlueRGB, 4.0, SimpleLineStyle.Solid);
ElementFactory.Instance.CreateGraphicElement(
container, linePl, lineSym, "New Line");

创建点元素

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
//Must be on QueuedTask.Run(() => { ...

//Build geometry
Coordinate2D coord2D = new Coordinate2D(2.0, 10.0);

//Reference a point symbol in a style
StyleProjectItem stylePrjItm = Project.Current.GetItems<StyleProjectItem>()
.FirstOrDefault(item => item.Name == "ArcGIS 2D");
SymbolStyleItem symStyleItm = stylePrjItm.SearchSymbols(
StyleItemType.PointSymbol, "City Hall")[0];
CIMPointSymbol pointSym = symStyleItm.Symbol as CIMPointSymbol;
pointSym.SetSize(50);

var elemInfo = new ElementInfo()
{
CustomProperties = new List<CIMStringMap>() {
new CIMStringMap() { Key = "Key1", Value = "Value1"},
new CIMStringMap() { Key = "Key2", Value = "Value2"}
},
Anchor = Anchor.TopRightCorner,
Rotation = 45.0
};

var graphic = GraphicFactory.Instance.CreateSimpleGraphic(
coord2D.ToMapPoint(), pointSym);

ElementFactory.Instance.CreateGraphicElement(
container, graphic, "New Point", true, elemInfo);

创建多边形元素

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
//Must be on QueuedTask.Run(() => { ...

//Build geometry
List<Coordinate2D> plyCoords = new List<Coordinate2D>();
plyCoords.Add(new Coordinate2D(1, 7));
plyCoords.Add(new Coordinate2D(2, 7));
plyCoords.Add(new Coordinate2D(2, 6.7));
plyCoords.Add(new Coordinate2D(3, 6.7));
plyCoords.Add(new Coordinate2D(3, 6.1));
plyCoords.Add(new Coordinate2D(1, 6.1));
Polygon poly = PolygonBuilderEx.CreatePolygon(plyCoords);

//Set symbolology, create and add element to layout
CIMStroke outline = SymbolFactory.Instance.ConstructStroke(
ColorFactory.Instance.BlueRGB, 2.0, SimpleLineStyle.DashDotDot);
CIMPolygonSymbol polySym = SymbolFactory.Instance.ConstructPolygonSymbol(
ColorFactory.Instance.RedRGB, SimpleFillStyle.ForwardDiagonal, outline);

ElementFactory.Instance.CreateGraphicElement(
container, poly, polySym, "New Polygon", false);

创建矩形元素

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
//Must be on QueuedTask.Run(() => { ...

//Build geometry
Coordinate2D ll = new Coordinate2D(1.0, 4.75);
Coordinate2D ur = new Coordinate2D(3.0, 5.75);
Envelope env = EnvelopeBuilderEx.CreateEnvelope(ll, ur);

//Set symbolology, create and add element to layout
CIMStroke outline = SymbolFactory.Instance.ConstructStroke(
ColorFactory.Instance.BlackRGB, 5.0, SimpleLineStyle.Solid);
CIMPolygonSymbol polySym = SymbolFactory.Instance.ConstructPolygonSymbol(
ColorFactory.Instance.GreenRGB, SimpleFillStyle.DiagonalCross, outline);

var ge = GraphicFactory.Instance.CreateSimpleGraphic(env, polySym);
var elemInfo = new ElementInfo()
{
Anchor = Anchor.CenterPoint,
Rotation = 45.0,
CornerRounding = 5.0
};

ElementFactory.Instance.CreateGraphicElement(
container, env, polySym, "New Rectangle", false, elemInfo);

创建贝塞尔曲线元素

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
//Must be on QueuedTask.Run(() => { ...
//Build geometry
Coordinate2D pt1 = new Coordinate2D(1, 7.5);
Coordinate2D pt2 = new Coordinate2D(1.66, 8);
Coordinate2D pt3 = new Coordinate2D(2.33, 7.1);
Coordinate2D pt4 = new Coordinate2D(3, 7.5);
var bez = new CubicBezierBuilderEx(pt1, pt2, pt3, pt4);
var bezSeg = bez.ToSegment();
Polyline bezPl = PolylineBuilderEx.CreatePolyline(bezSeg, AttributeFlags.AllAttributes);

//Set symbology, create and add element to layout
CIMLineSymbol lineSym = SymbolFactory.Instance.ConstructLineSymbol(
ColorFactory.Instance.RedRGB, 4.0, SimpleLineStyle.DashDot);

ElementFactory.Instance.CreateGraphicElement(container, bezPl, lineSym, "New Bezier");

创建图形元素

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
//Must be on QueuedTask.Run(() => { ...

//Build geometry
List<Coordinate2D> plyCoords = new List<Coordinate2D>();
plyCoords.Add(new Coordinate2D(1, 7));
plyCoords.Add(new Coordinate2D(2, 7));
plyCoords.Add(new Coordinate2D(2, 6.7));
plyCoords.Add(new Coordinate2D(3, 6.7));
plyCoords.Add(new Coordinate2D(3, 6.1));
plyCoords.Add(new Coordinate2D(1, 6.1));
Polygon poly = PolygonBuilderEx.CreatePolygon(plyCoords);

//Build geometry
Coordinate2D ll = new Coordinate2D(1.0, 4.75);
Coordinate2D ur = new Coordinate2D(3.0, 5.75);
Envelope env = EnvelopeBuilderEx.CreateEnvelope(ll, ur);

//Build geometry
Coordinate2D coord2D = new Coordinate2D(2.0, 10.0);

var g1 = GraphicFactory.Instance.CreateSimpleGraphic(poly);
var g2 = GraphicFactory.Instance.CreateSimpleGraphic(env);
var g3 = GraphicFactory.Instance.CreateSimpleGraphic(coord2D.ToMapPoint());

var ge = ElementFactory.Instance.CreateGraphicElements(
container, new List<CIMGraphic>() { g1, g2, g3 },
new List<string>() { "Poly", "Envelope", "MapPoint" },
true);

使用 CIMG 创建图形元素

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
//on the QueuedTask
//Place symbol on the layout
//At 2.x - MapPoint location = MapPointBuilder.CreateMapPoint(
// new Coordinate2D(9, 1));
MapPoint location = MapPointBuilderEx.CreateMapPoint(new Coordinate2D(9, 1));

//specify a symbol
var pt_symbol = SymbolFactory.Instance.ConstructPointSymbol(
ColorFactory.Instance.GreenRGB);

//create a CIMGraphic
var graphic = new CIMPointGraphic()
{
Symbol = pt_symbol.MakeSymbolReference(),
Location = location //center of map
};
//Or use GraphicFactory
var graphic2 = GraphicFactory.Instance.CreateSimpleGraphic(location, pt_symbol);

//At 2.x - LayoutElementFactory.Instance.CreateGraphicElement(layout, graphic);
ElementFactory.Instance.CreateGraphicElement(container, graphic);
ElementFactory.Instance.CreateGraphicElement(container, graphic2);

使用 CIMSymbol 创建图形元素

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
//Must be on QueuedTask.Run(() => { ...

//Place symbol on the layout
//At 2.x - MapPoint location = MapPointBuilder.CreateMapPoint(
// new Coordinate2D(9, 1));
MapPoint location = MapPointBuilderEx.CreateMapPoint(new Coordinate2D(9, 1));

//specify a symbol
var pt_symbol = SymbolFactory.Instance.ConstructPointSymbol(
ColorFactory.Instance.GreenRGB);
//At 2.x -
// LayoutElementFactory.Instance.CreateGraphicElement(
// layout, location, pt_symbol);

ElementFactory.Instance.CreateGraphicElement(container, location, pt_symbol);

批量元素创建

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
//Must be on QueuedTask.Run(() => { ...

//List of Point graphics
var listGraphics = new List<CIMPointGraphic>();
var listGraphics2 = new List<CIMPointGraphic>();
//Symbol
var pointSymbol = SymbolFactory.Instance.ConstructPointSymbol(
ColorFactory.Instance.BlackRGB);
//Define size of the array
int dx = 5;
int dy = 5;
MapPoint point = null;
//Create the List of graphics for the array
for (int row = 0; row <= dx; ++row)
{
for (int col = 0; col <= dy; ++col)
{
//At 2.x - point = MapPointBuilder.CreateMapPoint(col, row);
point = MapPointBuilderEx.CreateMapPoint(col, row);
//create a CIMGraphic
var graphic = new CIMPointGraphic()
{
Symbol = pointSymbol.MakeSymbolReference(),
Location = point
};
listGraphics.Add(graphic);
//Or use GraphicFactory
var graphic2 = GraphicFactory.Instance.CreateSimpleGraphic(
point, pointSymbol) as CIMPointGraphic;
listGraphics2.Add(graphic2);
}
}
//Draw the array of graphics
//At 2.x - var bulkgraphics =
// LayoutElementFactory.Instance.CreateGraphicElements(
// layout, listGraphics, null);

var bulkgraphics = ElementFactory.Instance.CreateGraphicElements(
container, listGraphics);
var bulkgraphics2 = ElementFactory.Instance.CreateGraphicElements(
container, listGraphics2);

使用 CIMG 创建元素

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
//Must be on QueuedTask.Run(() => { ...

//Place symbol on the layout
//At 2.x - MapPoint point = MapPointBuilder.CreateMapPoint(new Coordinate2D(9, 1));
MapPoint point = MapPointBuilderEx.CreateMapPoint(new Coordinate2D(9, 1));

//specify a symbol
var pt_symbol = SymbolFactory.Instance.ConstructPointSymbol(
ColorFactory.Instance.GreenRGB);

//create a CIMGraphic
var graphic = new CIMGraphicElement()
{
Graphic = new CIMPointGraphic()
{
Symbol = pt_symbol.MakeSymbolReference(),
Location = point //A point in the layout
}
};
//At 2.x - LayoutElementFactory.Instance.CreateElement(layout, graphic);
ElementFactory.Instance.CreateElement(container, graphic);

使用符号系统创建点图形

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
//Create a simple 2D point graphic and apply an existing point style item as the symbology.

//Construct on the worker thread
await QueuedTask.Run(() =>
{
//Build 2D point geometry
Coordinate2D coord2D = new Coordinate2D(2.0, 10.0);

//(optionally) Reference a point symbol in a style
StyleProjectItem ptStylePrjItm = Project.Current.GetItems<StyleProjectItem>()
.FirstOrDefault(item => item.Name == "ArcGIS 2D");
SymbolStyleItem ptSymStyleItm = ptStylePrjItm.SearchSymbols(
StyleItemType.PointSymbol, "City Hall")[0];
CIMPointSymbol pointSym = ptSymStyleItm.Symbol as CIMPointSymbol;
pointSym.SetSize(50);

//Set symbolology, create and add element to layout

//An alternative simple symbol is also commented out below.
//This would elminate the four optional lines of code above that
//reference a style.

//CIMPointSymbol pointSym = SymbolFactory.Instance.ConstructPointSymbol(
// ColorFactory.Instance.RedRGB, 25.0, SimpleMarkerStyle.Star);
//At 2.x - GraphicElement ptElm =
// LayoutElementFactory.Instance.CreatePointGraphicElement(
// layout, coord2D, pointSym);

GraphicElement ptElm = ElementFactory.Instance.CreateGraphicElement(
container, coord2D.ToMapPoint(), pointSym);
ptElm.SetName("New Point");
});

使用符号系统创建线图形

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
//Create a simple 2D line graphic and apply an existing line
//style item as the symbology.

//Construct on the worker thread
await QueuedTask.Run(() =>
{
//Build 2d line geometry
List<Coordinate2D> plCoords = new List<Coordinate2D>();
plCoords.Add(new Coordinate2D(1, 8.5));
plCoords.Add(new Coordinate2D(1.66, 9));
plCoords.Add(new Coordinate2D(2.33, 8.1));
plCoords.Add(new Coordinate2D(3, 8.5));
//At 2.x - Polyline linePl = PolylineBuilder.CreatePolyline(plCoords);
Polyline linePl = PolylineBuilderEx.CreatePolyline(plCoords);

//(optionally) Reference a line symbol in a style
StyleProjectItem lnStylePrjItm = Project.Current.GetItems<StyleProjectItem>()
.FirstOrDefault(item => item.Name == "ArcGIS 2D");
SymbolStyleItem lnSymStyleItm = lnStylePrjItm.SearchSymbols(
StyleItemType.LineSymbol, "Line with 2 Markers")[0];
CIMLineSymbol lineSym = lnSymStyleItm.Symbol as CIMLineSymbol;
lineSym.SetSize(20);

//Set symbolology, create and add element to layout

//An alternative simple symbol is also commented out below.
//This would elminate the four optional lines of code above that
//reference a style.
//
//CIMLineSymbol lineSym = SymbolFactory.Instance.ConstructLineSymbol(
// ColorFactory.Instance.BlueRGB, 4.0, SimpleLineStyle.Solid);
//At 2.x - GraphicElement lineElm =
// LayoutElementFactory.Instance.CreateLineGraphicElement(
// layout, linePl, lineSym);

GraphicElement lineElm = ElementFactory.Instance.CreateGraphicElement(
container, linePl, lineSym);
lineElm.SetName("New Line");
});

使用简单符号系统创建矩形图形

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
//Create a simple 2D rectangle graphic and apply simple fill and
//outline symbols.

//Construct on the worker thread
await QueuedTask.Run(() =>
{
//Build 2D envelope geometry
Coordinate2D rec_ll = new Coordinate2D(1.0, 4.75);
Coordinate2D rec_ur = new Coordinate2D(3.0, 5.75);
//At 2.x - Envelope rec_env = EnvelopeBuilder.CreateEnvelope(rec_ll, rec_ur);
Envelope rec_env = EnvelopeBuilderEx.CreateEnvelope(rec_ll, rec_ur);

//Set symbolology, create and add element to layout
CIMStroke outline = SymbolFactory.Instance.ConstructStroke(
ColorFactory.Instance.BlackRGB, 5.0, SimpleLineStyle.Solid);
CIMPolygonSymbol polySym = SymbolFactory.Instance.ConstructPolygonSymbol(
ColorFactory.Instance.GreenRGB, SimpleFillStyle.DiagonalCross, outline);

//At 2.x - GraphicElement recElm =
// LayoutElementFactory.Instance.CreateRectangleGraphicElement(
// layout, rec_env, polySym);
// recElm.SetName("New Rectangle");
//
GraphicElement recElm = ElementFactory.Instance.CreateGraphicElement(
container, rec_env, polySym, "New Rectangle");
//Or use Predefined shape
GraphicElement recElm2 = ElementFactory.Instance.CreatePredefinedShapeGraphicElement(
container, PredefinedShape.Rectangle, rec_env, polySym,
"New Rectangle2");
});

创建文本图形元素

创建点文本元素 1

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
//Create a simple point text element and assign basic symbology and text settings.

//Construct on the worker thread
await QueuedTask.Run(() =>
{
//Build 2D point geometry
Coordinate2D coord2D = new Coordinate2D(3.5, 10);

//Set symbolology, create and add element to layout
CIMTextSymbol sym = SymbolFactory.Instance.ConstructTextSymbol(
ColorFactory.Instance.RedRGB, 32, "Arial", "Regular");
string textString = "Point text";
//At 2.x - GraphicElement ptTxtElm =
// LayoutElementFactory.Instance.CreatePointTextGraphicElement(
// layout, coord2D, textString, sym);
//ptTxtElm.SetName("New Point Text");
//ptTxtElm.SetAnchor(Anchor.CenterPoint);
//ptTxtElm.SetX(4.5);
//ptTxtElm.SetY(9.5);
//ptTxtElm.SetRotation(45);

//use ElementInfo to set placement properties during create
var elemInfo = new ElementInfo()
{
Anchor = Anchor.CenterPoint,
Rotation = 45
};
var ptTxtElm = ElementFactory.Instance.CreateTextGraphicElement(
container, TextType.PointText, coord2D.ToMapPoint(), sym, textString,
"New Point Text", true, elemInfo);

//Change additional text properties
ptTxtElm.SetX(4.5);
ptTxtElm.SetY(9.5);
});

创建矩形段落文本元素 1

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
//Create rectangle text with background and border symbology.  

//Construct on the worker thread
await QueuedTask.Run(() =>
{
//Build 2D polygon geometry
List<Coordinate2D> plyCoords = new List<Coordinate2D>();
plyCoords.Add(new Coordinate2D(3.5, 7));
plyCoords.Add(new Coordinate2D(4.5, 7));
plyCoords.Add(new Coordinate2D(4.5, 6.7));
plyCoords.Add(new Coordinate2D(5.5, 6.7));
plyCoords.Add(new Coordinate2D(5.5, 6.1));
plyCoords.Add(new Coordinate2D(3.5, 6.1));
//At 2.x - Polygon poly = PolygonBuilder.CreatePolygon(plyCoords);
Polygon poly = PolygonBuilderEx.CreatePolygon(plyCoords);

//Set symbolology, create and add element to layout
//Also notice how formatting tags are using within the text string.
CIMTextSymbol sym = SymbolFactory.Instance.ConstructTextSymbol(
ColorFactory.Instance.GreyRGB, 10, "Arial", "Regular");
string text = "Some Text String that is really long and is " +
"<BOL>forced to wrap to other lines</BOL> so that " +
"we can see the effects." as String;
//At 2.x - GraphicElement polyTxtElm =
// LayoutElementFactory.Instance.CreatePolygonParagraphGraphicElement(
// layout, poly, text, sym);
// polyTxtElm.SetName("New Polygon Text");

GraphicElement polyTxtElm = ElementFactory.Instance.CreateTextGraphicElement(
container, TextType.RectangleParagraph, poly, sym, text, "Polygon Paragraph");

//(Optionally) Modify paragraph border
CIMGraphic polyTxtGra = polyTxtElm.GetGraphic();
CIMParagraphTextGraphic cimPolyTxtGra = polyTxtGra as CIMParagraphTextGraphic;
cimPolyTxtGra.Frame.BorderSymbol = new CIMSymbolReference();
cimPolyTxtGra.Frame.BorderSymbol.Symbol =
SymbolFactory.Instance.ConstructLineSymbol(
ColorFactory.Instance.GreyRGB, 1.0, SimpleLineStyle.Solid);
polyTxtElm.SetGraphic(polyTxtGra);
});

创建动态点文本元素

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
//Create a dynamic text element.

//Set the string with tags and the location
String title = @"<dyn type = ""page"" property = ""name"" />";
Coordinate2D llTitle = new Coordinate2D(6, 2.5);

//Construct element on worker thread
await QueuedTask.Run(() =>
{
//Create with default text properties
//At 2.x - TextElement titleGraphics =
// LayoutElementFactory.Instance.CreatePointTextGraphicElement(
// layout, llTitle, null) as TextElement;
TextElement titleGraphics = ElementFactory.Instance.CreateTextGraphicElement(
container, TextType.PointText, llTitle.ToMapPoint()) as TextElement;

//Modify the text properties
titleGraphics.SetTextProperties(new TextProperties(title, "Arial", 24, "Bold"));
});

创建点文本元素 2

1
2
3
4
5
6
7
8
9
10
11
12
13
14
//Must be on QueuedTask.Run(() => { ...

//Build geometry
Coordinate2D coord2D = new Coordinate2D(3.5, 10);

//Set symbolology, create and add element to layout
CIMTextSymbol sym = SymbolFactory.Instance.ConstructTextSymbol(
ColorFactory.Instance.RedRGB, 32, "Arial", "Regular");
string textString = "Point text";

var elemInfo = new ElementInfo() { Anchor = Anchor.BottomLeftCorner };
GraphicElement ptTxtElm = ElementFactory.Instance.CreateTextGraphicElement(
container, TextType.PointText, coord2D.ToMapPoint(), sym, textString,
"New Point Text", true, elemInfo);

创建多边形段落文本元素

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
//Must be on QueuedTask.Run(() => { ...

//Build geometry
List<Coordinate2D> plyCoords = new List<Coordinate2D>();
plyCoords.Add(new Coordinate2D(3.5, 7));
plyCoords.Add(new Coordinate2D(4.5, 7));
plyCoords.Add(new Coordinate2D(4.5, 6.7));
plyCoords.Add(new Coordinate2D(5.5, 6.7));
plyCoords.Add(new Coordinate2D(5.5, 6.1));
plyCoords.Add(new Coordinate2D(3.5, 6.1));
Polygon poly = PolygonBuilderEx.CreatePolygon(plyCoords);

//Set symbolology, create and add element to layout
CIMTextSymbol sym = SymbolFactory.Instance.ConstructTextSymbol(
ColorFactory.Instance.GreyRGB, 10, "Arial", "Regular");
string text = "Some text string that is really long and " +
"<BOL>wraps to other lines</BOL>" +
" so that we can see the effects.";

var ge = ElementFactory.Instance.CreateTextGraphicElement(
container, TextType.PolygonParagraph, poly, sym, text,
"New Polygon Text", true);

创建矩形段落文本元素 2

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
//Must be on QueuedTask.Run(() => { ...

//Build geometry
Coordinate2D ll = new Coordinate2D(3.5, 4.75);
Coordinate2D ur = new Coordinate2D(5.5, 5.75);
Envelope env = EnvelopeBuilderEx.CreateEnvelope(ll, ur);

//Set symbolology, create and add element to layout
CIMTextSymbol sym = SymbolFactory.Instance.ConstructTextSymbol(
ColorFactory.Instance.WhiteRGB, 10, "Arial", "Regular");
string text = "Some text string that is really long and " +
"<BOL>wraps to other lines</BOL>" +
" so that we can see the effects.";

//(Optionally) Modify border and background with 50% transparency
//CIMGraphic recTxtGra = recTxtElm.Graphic;
//CIMParagraphTextGraphic cimRecTxtGra = recTxtGra as CIMParagraphTextGraphic;
//CIMSymbolReference cimRecTxtBorder = cimRecTxtGra.Frame.BorderSymbol;
//
//CIMLineSymbol lineSym = SymbolFactory.Instance.ConstructLineSymbol(
// ColorFactory.Instance.BlackRGB, 1.0, SimpleLineStyle.Solid);
//cimRecTxtBorder.Symbol = lineSym;
//
//CIMSymbolReference cimRecTxtBkgrd = cimRecTxtGra.Frame.BackgroundSymbol;
//CIMPolygonSymbol polySym = SymbolFactory.Instance.ConstructPolygonSymbol(
// ColorFactory.Instance.GreyRGB, SimpleFillStyle.Solid);
//
//CIMColor symCol = polySym.GetColor(IElementContainer container);
//symCol.SetAlphaValue(50);
//cimRecTxtBkgrd.Symbol = polySym;
//recTxtElm.SetGraphic(recTxtGra);

var ge = ElementFactory.Instance.CreateTextGraphicElement(container,
TextType.RectangleParagraph, env, sym, text, "New Rectangle Text");

创建圆形文本元素

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
//Must be on QueuedTask.Run(() => { ...

//Build geometry
Coordinate2D center = new Coordinate2D(4.5, 4);
var eabCir = new EllipticArcBuilderEx(center, 0.5, ArcOrientation.ArcClockwise);
var cir = eabCir.ToSegment();

var poly = PolygonBuilderEx.CreatePolygon(
PolylineBuilderEx.CreatePolyline(cir, AttributeFlags.AllAttributes));

//Set symbolology, create and add element to layout
CIMTextSymbol sym = SymbolFactory.Instance.ConstructTextSymbol(
ColorFactory.Instance.GreenRGB, 10, "Arial", "Regular");
string text = "Circle, circle, circle";

GraphicElement cirTxtElm = ElementFactory.Instance.CreateTextGraphicElement(
container, TextType.CircleParagraph, poly, sym, text, "New Circle Text", false);

创建贝塞尔文本元素

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
//Must be on QueuedTask.Run(() => { ...

//Build geometry
Coordinate2D pt1 = new Coordinate2D(3.5, 7.5);
Coordinate2D pt2 = new Coordinate2D(4.16, 8);
Coordinate2D pt3 = new Coordinate2D(4.83, 7.1);
Coordinate2D pt4 = new Coordinate2D(5.5, 7.5);
var bez = new CubicBezierBuilderEx(pt1, pt2, pt3, pt4);
var bezSeg = bez.ToSegment();
Polyline bezPl = PolylineBuilderEx.CreatePolyline(bezSeg, AttributeFlags.AllAttributes);

//Set symbolology, create and add element to layout
CIMTextSymbol sym = SymbolFactory.Instance.ConstructTextSymbol(
ColorFactory.Instance.BlackRGB, 24, "Comic Sans MS", "Regular");

var ge = ElementFactory.Instance.CreateTextGraphicElement(
container, TextType.SplinedText, bezPl, sym, "this is the bezier text",
"New Bezier Text", true, new ElementInfo() { Anchor = Anchor.CenterPoint });

创建椭圆文本元素

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
//Must be on QueuedTask.Run(() => { ...

//Build geometry
Coordinate2D center = new Coordinate2D(4.5, 2.75);
var eabElp = new EllipticArcBuilderEx(center, 0, 1, 0.45, ArcOrientation.ArcClockwise);
var ellipse = eabElp.ToSegment();

var poly = PolygonBuilderEx.CreatePolygon(
PolylineBuilderEx.CreatePolyline(ellipse, AttributeFlags.AllAttributes));

//Set symbolology, create and add element to layout
CIMTextSymbol sym = SymbolFactory.Instance.ConstructTextSymbol(
ColorFactory.Instance.BlueRGB, 10, "Arial", "Regular");
string text = "Ellipse, ellipse, ellipse";

GraphicElement ge = ElementFactory.Instance.CreateTextGraphicElement(
container, TextType.PolygonParagraph, poly, sym, text, "New Ellipse Text", false);

创建预定义的形状和箭头

创建预定义的形状图形元素

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
//Must be on QueuedTask.Run(() => { ...

//PredefinedShape shapeType =
// PredefinedShape.Circle | Cloud | Cross |Circle | Triangle | ... ;

//Build geometry
Coordinate2D ll = new Coordinate2D(4, 2.5);
Coordinate2D ur = new Coordinate2D(6, 4.5);
Envelope env = EnvelopeBuilderEx.CreateEnvelope(ll, ur);

var outline = SymbolFactory.Instance.ConstructStroke(
ColorFactory.Instance.BlueRGB, 2);
var poly_sym = SymbolFactory.Instance.ConstructPolygonSymbol(
null, outline);

var ge = ElementFactory.Instance.CreatePredefinedShapeGraphicElement(
container, shapeType, env.Center, env.Width, env.Height,
poly_sym, shapeType.ToString(), true);

创建预定义的形状图形元素

1
2
3
4
5
6
7
8
9
10
11
12
13
14
//Must be on QueuedTask.Run(() => { ...

//Build geometry
Coordinate2D ll = new Coordinate2D(6.5, 7);
Coordinate2D ur = new Coordinate2D(9, 9);
Envelope env = EnvelopeBuilderEx.CreateEnvelope(ll, ur);

var outline = SymbolFactory.Instance.ConstructStroke(
ColorFactory.Instance.GreenRGB, 2);
var poly_sym = SymbolFactory.Instance.ConstructPolygonSymbol(
null, outline);

var ge = ElementFactory.Instance.CreatePredefinedShapeGraphicElement(
container, PredefinedShape.RoundedRectangle, env, poly_sym, "Rounded Rect", true);

创建预定义的形状图形元素

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
//Must be on QueuedTask.Run(() => { ...

//Build geometry
Coordinate2D center = new Coordinate2D(2, 2.75);
var eabElp = new EllipticArcBuilderEx(
center, 0, 1, 0.45, ArcOrientation.ArcClockwise);
var ellipse = eabElp.ToSegment();

//Set symbolology, create and add element to layout
CIMStroke outline = SymbolFactory.Instance.ConstructStroke(
ColorFactory.Instance.GreenRGB, 2.0, SimpleLineStyle.Dot);
CIMPolygonSymbol ellipseSym = SymbolFactory.Instance.ConstructPolygonSymbol(
ColorFactory.Instance.GreyRGB, SimpleFillStyle.Vertical, outline);

var poly = PolygonBuilderEx.CreatePolygon(
PolylineBuilderEx.CreatePolyline(ellipse, AttributeFlags.AllAttributes));

var ge = ElementFactory.Instance.CreatePredefinedShapeGraphicElement(
container, PredefinedShape.Ellipse, poly.Extent.Center, 0, 0, ellipseSym,
"New Ellipse2", false, new ElementInfo() { Anchor = Anchor.TopRightCorner });

创建线箭头元素

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
//Must be on QueuedTask.Run(() => { ...

//Build geometry
List<Coordinate2D> plCoords = new List<Coordinate2D>();
plCoords.Add(new Coordinate2D(1, 8.5));
plCoords.Add(new Coordinate2D(1.66, 9));
plCoords.Add(new Coordinate2D(2.33, 8.1));
plCoords.Add(new Coordinate2D(3, 8.5));
Polyline linePl = PolylineBuilderEx.CreatePolyline(plCoords);

var arrowInfo = new ArrowInfo()
{
ArrowHeadKey = ArrowInfo.DefaultArrowHeadKeys[8],
ArrowOnBothEnds = true,
ArrowSizePoints = 24,
LineWidthPoints = 12
};

//Create and add element to layout
GraphicElement lineElm = ElementFactory.Instance.CreateArrowGraphicElement(
container, linePl, arrowInfo, "Arrow Line", true,
new ElementInfo() { Rotation = 15.0 });
//lineElm.SetName("New Line");

图片元素

使用 CIMSymbol 创建图片图形元素

1
2
3
4
5
6
7
8
9
10
11
//Must be on QueuedTask.Run(() => { ...

//Build geometry
Coordinate2D ll = new Coordinate2D(0.5, 1);
Coordinate2D ur = new Coordinate2D(2.5, 2);
Envelope env = EnvelopeBuilderEx.CreateEnvelope(ll, ur);

//Create and add element to layout
//string picPath = ApplicationUtilities.BASEPATH + _settings.baseFolder + "irefusetowatchthismovi�.jpg";
var pic_gr = ElementFactory.Instance.CreatePictureGraphicElement(
layout, env.Center, picPath, "New Picture", true, new ElementInfo() { Anchor = Anchor.CenterPoint });

使用高级符号设置创建新的图片元素

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
//Create a picture element and also set background and border symbology.

//Construct on the worker thread
await QueuedTask.Run(() =>
{
//Build 2D envelope geometry
Coordinate2D pic_ll = new Coordinate2D(6, 1);
Coordinate2D pic_ur = new Coordinate2D(8, 2);
//At 2.x - Envelope env = EnvelopeBuilder.CreateEnvelope(pic_ll, pic_ur);
Envelope env = EnvelopeBuilderEx.CreateEnvelope(pic_ll, pic_ur);

//Create and add element to layout
string picPath = @"C:\Temp\WhitePass.jpg";
//At 2.x - GraphicElement picElm =
// LayoutElementFactory.Instance.CreatePictureGraphicElement(
// layout, env, picPath);
// picElm.SetName("New Picture");
//
GraphicElement picElm = ElementFactory.Instance.CreatePictureGraphicElement(
layout, env, picPath, "New Picture");

//(Optionally) Modify the border and shadow
CIMGraphic picGra = picElm.GetGraphic();
CIMPictureGraphic cimPicGra = picGra as CIMPictureGraphic;
cimPicGra.Frame.BorderSymbol = new CIMSymbolReference();
cimPicGra.Frame.BorderSymbol.Symbol =
SymbolFactory.Instance.ConstructLineSymbol(
ColorFactory.Instance.BlueRGB, 2.0, SimpleLineStyle.Solid);

cimPicGra.Frame.ShadowSymbol = new CIMSymbolReference();
cimPicGra.Frame.ShadowSymbol.Symbol =
SymbolFactory.Instance.ConstructPolygonSymbol(
ColorFactory.Instance.BlackRGB, SimpleFillStyle.Solid);

//Update the element
picElm.SetGraphic(picGra);
});

创建地图框和环绕要素

创建地图框并设置照相机

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
//Create a map frame and set its camera by zooming to the extent of an existing bookmark.

//Construct on the worker thread
await QueuedTask.Run(() =>
{
//Build 2D envelope geometry
Coordinate2D mf_ll = new Coordinate2D(6.0, 8.5);
Coordinate2D mf_ur = new Coordinate2D(8.0, 10.5);
//At 2.x - Envelope mf_env = EnvelopeBuilder.CreateEnvelope(mf_ll, mf_ur);
Envelope mf_env = EnvelopeBuilderEx.CreateEnvelope(mf_ll, mf_ur);

//Reference map, create MF and add to layout
MapProjectItem mapPrjItem = Project.Current.GetItems<MapProjectItem>()
.FirstOrDefault(item => item.Name.Equals("Map"));
Map mfMap = mapPrjItem.GetMap();
Bookmark bookmark = mfMap.GetBookmarks().FirstOrDefault(
b => b.Name == "Great Lakes");

//At 2.x - MapFrame mfElm =
// LayoutElementFactory.Instance.CreateMapFrame(
// layout, mf_env, mfMap);
// mfElm.SetName("New Map Frame");
//
MapFrame mfElm = ElementFactory.Instance.CreateMapFrameElement(
layout, mf_env, mfMap, "New Map Frame");

//Zoom to bookmark
mfElm.SetCamera(bookmark);
});

创建图例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
//Create a legend for an associated map frame.

//Construct on the worker thread
await QueuedTask.Run(() =>
{
//Build 2D envelope geometry
Coordinate2D leg_ll = new Coordinate2D(6, 2.5);
Coordinate2D leg_ur = new Coordinate2D(8, 4.5);
//At 2.x - Envelope leg_env = EnvelopeBuilder.CreateEnvelope(leg_ll, leg_ur);
Envelope leg_env = EnvelopeBuilderEx.CreateEnvelope(leg_ll, leg_ur);

//Reference MF, create legend and add to layout
MapFrame mapFrame = layout.FindElement("New Map Frame") as MapFrame;
if (mapFrame == null)
{
//TODO handle null map frame
return;
}
//At 2.x - Legend legendElm = LayoutElementFactory.Instance.CreateLegend(
// layout, leg_env, mapFrame);
// legendElm.SetName("New Legend");
var legendInfo = new LegendInfo()
{
MapFrameName = mapFrame.Name
};
Legend legendElm = ElementFactory.Instance.CreateMapSurroundElement(
layout, leg_env, legendInfo, "New Legend") as Legend;
});

从样式项创建比例尺

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
//Create a scale bar using a style.

//Search for a style project item by name
StyleProjectItem arcgis_2dStyle = Project.Current.GetItems<StyleProjectItem>()
.First(si => si.Name == "ArcGIS 2D");

//Construct on the worker thread
await QueuedTask.Run(() =>
{
//Reference the specific scale bar by name
ScaleBarStyleItem scaleBarItem = arcgis_2dStyle.SearchScaleBars(
"Double Alternating Scale Bar").FirstOrDefault();

//Reference the map frame and define the location
MapFrame myMapFrame = layout.FindElement("Map Frame") as MapFrame;
Coordinate2D coord2D = new Coordinate2D(10.0, 7.0);

//Construct the scale bar
//At 2.x - LayoutElementFactory.Instance.CreateScaleBar(
// layout, coord2D, myMapFrame, scaleBarItem);
var sbarInfo = new ScaleBarInfo()
{
MapFrameName = myMapFrame.Name,
ScaleBarStyleItem = scaleBarItem
};
ElementFactory.Instance.CreateMapSurroundElement(
layout, coord2D.ToMapPoint(), sbarInfo);
});

从样式项 1 创建指北针

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
//Create a north arrow using a style.

//Search for a style project item by name
StyleProjectItem arcgis2dStyles = Project.Current.GetItems<StyleProjectItem>()
.First(si => si.Name == "ArcGIS 2D");

//Construct on the worker thread
await QueuedTask.Run(() =>
{
NorthArrowStyleItem naStyleItem = arcgis2dStyles.SearchNorthArrows(
"ArcGIS North 13").FirstOrDefault();

//Reference the map frame and define the location
MapFrame newFrame = layout.FindElement("New Map Frame") as MapFrame;
Coordinate2D nArrow = new Coordinate2D(6, 2.5);

//Construct the north arrow
//At 2.x - var newNorthArrow = LayoutElementFactory.Instance.CreateNorthArrow(
// layout, nArrow, newFrame, naStyleItem);

var naInfo = new NorthArrowInfo()
{
MapFrameName = newFrame.Name,
NorthArrowStyleItem = naStyleItem
};
var newNorthArrow = ElementFactory.Instance.CreateMapSurroundElement(
layout, nArrow.ToMapPoint(), naInfo);
});

创建表格框

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
//Create a table frame.

//Construct on the worker thread
await QueuedTask.Run(() =>
{
//Build 2D envelope geometry
Coordinate2D rec_ll = new Coordinate2D(1.0, 3.5);
Coordinate2D rec_ur = new Coordinate2D(7.5, 4.5);
//At 2.x - Envelope rec_env = EnvelopeBuilder.CreateEnvelope(rec_ll, rec_ur);
Envelope rec_env = EnvelopeBuilderEx.CreateEnvelope(rec_ll, rec_ur);

//Reference map frame and layer
MapFrame mf = layout.FindElement("Map Frame") as MapFrame;
FeatureLayer lyr = mf.Map.FindLayers("GreatLakes").First() as FeatureLayer;

//Build fields list
var fields = new[] { "NAME", "Shape_Area", "Shape_Length" };

//Construct the table frame
//At 2.x - TableFrame tabFrame = LayoutElementFactory.Instance.CreateTableFrame(
// layout, rec_env, mf, lyr, fields);

var tableFrameInfo = new TableFrameInfo()
{
FieldNames = fields,
MapFrameName = mf.Name,
MapMemberUri = lyr.URI
};
var tabFrame = ElementFactory.Instance.CreateMapSurroundElement(
layout, rec_env, tableFrameInfo) as TableFrame;
});

创建地图框 1

1
2
3
4
5
6
7
8
9
10
11
12
13
14
//Must be on QueuedTask.Run(() => { ...

//Build geometry
Coordinate2D ll = new Coordinate2D(2.0, 4.5);
Coordinate2D ur = new Coordinate2D(4.0, 6.5);
Envelope env = EnvelopeBuilderEx.CreateEnvelope(ll, ur);

//Reference map, create MF and add to layout
//var map = MapView.Active.Map;
//var map = mapProjectItem.GetMap();
//...

MapFrame mfElm = ElementFactory.Instance.CreateMapFrameElement(
layout, env, map);

创建地图框 2

1
2
3
4
5
6
7
8
9
10
11
12
13
//Must be on QueuedTask.Run(() => { ...

//Build geometry
Coordinate2D ll = new Coordinate2D(4.0, 2.5);
Coordinate2D ur = new Coordinate2D(7.0, 5.5);
Envelope env = EnvelopeBuilderEx.CreateEnvelope(ll, ur);

//Reference map, create MF and add to layout
//var map = MapView.Active.Map;
//var map = mapProjectItem.GetMap();
//...
MapFrame mfElm = ElementFactory.Instance.CreateMapFrameElement(
layout, env.Center, map);

创建图例 2

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
//Must be on QueuedTask.Run(() => { ...

//Build geometry
Coordinate2D ll = new Coordinate2D(6, 2.5);
Coordinate2D ur = new Coordinate2D(8, 4.5);
Envelope env = EnvelopeBuilderEx.CreateEnvelope(ll, ur);

//Reference MF, create legend and add to layout
MapFrame mf = layout.FindElement(mapFrameName) as MapFrame;
var surroundInfo = new LegendInfo()
{
MapFrameName = mf.Name
};

var legendElm = ElementFactory.Instance.CreateMapSurroundElement(
layout, env.Center, surroundInfo) as Legend;
legendElm.SetName("New Legend");

从样式项 2 创建指北针

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
//Must be on QueuedTask.Run(() => { ...

//Build geometry
Coordinate2D center = new Coordinate2D(7, 5.5);

//Reference a North Arrow in a style
StyleProjectItem stylePrjItm = Project.Current.GetItems<StyleProjectItem>()
.FirstOrDefault(item => item.Name == "ArcGIS 2D");
NorthArrowStyleItem naStyleItm = stylePrjItm.SearchNorthArrows(
"ArcGIS North 10")[0];

//Reference MF, create north arrow and add to layout
//var mf = container.FindElement("New Map Frame") as MapFrame;
var mf = layout.FindElement(MapFrameName) as MapFrame;
var narrow_info = new NorthArrowInfo()
{
MapFrameName = mf.Name,
NorthArrowStyleItem = naStyleItm
};
var arrowElm = (NorthArrow)ElementFactory.Instance.CreateMapSurroundElement(
layout, center.ToMapPoint(), narrow_info) as NorthArrow;
arrowElm.SetName("New North Arrow");
arrowElm.SetHeight(1.75);
arrowElm.SetX(7);
arrowElm.SetY(6);

创建表格框

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
//Must be on QueuedTask.Run(() => { ...

//Build geometry
Coordinate2D ll = new Coordinate2D(1, 1);
Coordinate2D ur = new Coordinate2D(4, 4);
Envelope env = EnvelopeBuilderEx.CreateEnvelope(ll, ur);

var tableFrameInfo = new TableFrameInfo()
{
MapFrameName = mapFrameName,
MapMemberUri = uri
};
var attribs = new List<CIMStringMap>();
for (int i = 1; i < 6; i++)
{
attribs.Add(new CIMStringMap
{
Key = $"Key {i}",
Value = $"Value {i}"
});
}
var elemInfo = new ElementInfo()
{
CustomProperties = attribs
};
var tableFrameElem = ElementFactory.Instance.CreateMapSurroundElement(
layout, env.Center, tableFrameInfo,
"New Table Frame", false, elemInfo) as TableFrame;

创建比例尺

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
//Must be on QueuedTask.Run(() => { ...

//Build geometry
Coordinate2D ll = new Coordinate2D(5.0, 6);
Coordinate2D ur = new Coordinate2D(6.0, 7);
Envelope sbEnv = EnvelopeBuilderEx.CreateEnvelope(ll, ur);

//Reference a Scale Bar in a style
StyleProjectItem stylePrjItm = Project.Current.GetItems<StyleProjectItem>()
.FirstOrDefault(item => item.Name == "ArcGIS 2D");
ScaleBarStyleItem sbStyleItm = stylePrjItm.SearchScaleBars(
"Alternating Scale Bar 1")[0];
//ScaleBarStyleItem sbStyleItm = stylePrjItm.SearchScaleBars(
// "Double Alternating Scale Bar 1")[0];
//ScaleBarStyleItem sbStyleItm = stylePrjItm.SearchScaleBars(
// "Hollow Scale Bar 1")[0];

//Create Scale Bar
ScaleBarInfo sbInfo = new ScaleBarInfo()
{
MapFrameName = mapFrame.Name
};

var sbElm = ElementFactory.Instance.CreateMapSurroundElement(
layout, sbEnv, sbInfo) as ScaleBar;

创建比例线

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
//Must be on QueuedTask.Run(() => { ...

//Build geometry
Coordinate2D ll = new Coordinate2D(5.0, 8);
Coordinate2D ur = new Coordinate2D(6.0, 9);
Envelope sbEnv = EnvelopeBuilderEx.CreateEnvelope(ll, ur);

//Reference a Scale Bar in a style
StyleProjectItem stylePrjItm = Project.Current.GetItems<StyleProjectItem>()
.FirstOrDefault(item => item.Name == "ArcGIS 2D");
ScaleBarStyleItem sbStyleItm = stylePrjItm.SearchScaleBars(
"Scale Line 1")[0];
//ScaleBarStyleItem sbStyleItm = stylePrjItm.SearchScaleBars(
// "Stepped Scale Line")[0];
//ScaleBarStyleItem sbStyleItm = stylePrjItm.SearchScaleBars(
// "Scale Line 2")[0];

//Create Scale Bar
ScaleBarInfo sbInfo = new ScaleBarInfo()
{
MapFrameName = mapFrame.Name,
ScaleBarStyleItem = sbStyleItm
};

var sbElm = ElementFactory.Instance.CreateMapSurroundElement(
layout, sbEnv, sbInfo, "ScaleBar Line") as ScaleBar;

组元素

创建空组元素

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
//Create an empty group element at the root level of the contents pane

//Create on worker thread
await QueuedTask.Run(() =>
{
//At 2.x - GroupElement grp1 =
// LayoutElementFactory.Instance.CreateGroupElement(layout);
// grp1.SetName("Group");

//container is IElementContainer - GroupLayer or Layout
GroupElement grp1 = ElementFactory.Instance.CreateGroupElement(
container, null, "Group");
});

// *** or ***

//Create a group element inside another group element

//Find an existing group element
//container is IElementContainer - GroupLayer or Layout
GroupElement existingGroup = container.FindElement("Group") as GroupElement;

//Create on worker thread
await QueuedTask.Run(() =>
{
//At 2.x - GroupElement grp2 =
// LayoutElementFactory.Instance.CreateGroupElement(existingGroup);
// grp2.SetName("Group in Group");
GroupElement grp2 = ElementFactory.Instance.CreateGroupElement(
existingGroup, null, "Group in Group");
});

创建包含元素的组元素

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
//Create a group with a list of elements at the root level of the contents pane.

//Find an existing elements
//container is IElementContainer - GroupLayer or Layout
var elem1 = container.FindElement("Polygon 1");
var elem2 = container.FindElement("Bezier Text");
var elem3 = container.FindElement("Cloud Shape 2");

//Construct a list and add the elements
var elmList = new List<Element>
{
elem1,
elem2,
elem3
};

//Perform on the worker thread
await QueuedTask.Run(() =>
{
//At 2.x - GroupElement groupWithListOfElementsAtRoot =
// LayoutElementFactory.Instance.CreateGroupElement(layout, elmList);
//groupWithListOfElementsAtRoot.SetName("Group with list of elements at root");
//
GroupElement groupWithListOfElementsAtRoot =
ElementFactory.Instance.CreateGroupElement(
container, elmList, "Group with list of elements at root");
});

// *** or ***

//Create a group using a list of element names at the root level of the contents pane.

//List of element names
var elmNameList = new[] { "Para Text1", "Line 3" };

//Perform on the worker thread
await QueuedTask.Run(() =>
{
//At 2.x - GroupElement groupWithListOfElementNamesAtRoot =
// LayoutElementFactory.Instance.CreateGroupElement(layout, elmNameList);
// groupWithListOfElementNamesAtRoot.SetName(
// "Group with list of element names at root");

//At 3.x, use the names to find the relevant elements first
//container is IElementContainer - GroupLayer or Layout
var elems = container.FindElements(elmNameList);
GroupElement groupWithListOfElementNamesAtRoot =
ElementFactory.Instance.CreateGroupElement(
container, elems, "Group with list of element names at root");
});

布局元素和选择

在布局上查找元素

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
//Find an element on a layout.

// Reference a layout project item by name
LayoutProjectItem layoutItem = Project.Current.GetItems<LayoutProjectItem>().FirstOrDefault(item => item.Name.Equals("MyLayout"));
if (layoutItem != null)
{
QueuedTask.Run(() =>
{
// Reference and load the layout associated with the layout item
Layout mylayout = layoutItem.GetLayout();
if (mylayout != null)
{
//Find a single specific element
Element rect = mylayout.FindElement("Rectangle") as Element;

//Or use the Elements collection
Element rect2 = mylayout.Elements.FirstOrDefault(item => item.Name.Equals("Rectangle"));
}
});
}

查找布局元素

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
//on the QueuedTask
//Find elements by name
var layoutElementsToFind = layout.FindElements(new List<string>() { "Point 1", "Line 3", "Text 1" });
//Get the collection of elements from the page layout. Nesting within GroupElement is preserved.
var elementCollection = layout.GetElements();
//Get the collection of Element from the page layout as a flattened list. Nested groups within GroupElement are not preserved.
var elements = layout.GetElementsAsFlattenedList();
//Convert collection of the elements to a collection of GraphicElements.
var graphicElements = elements.ToList().ConvertAll(x => (GraphicElement)x);
//Find elements by type
//Find all point graphics in the Layout
var pointGraphics = graphicElements.Where(elem => elem.GetGraphic() is CIMPointGraphic);
//Find all line graphics in the Graphics Layer
var lineGraphics = graphicElements.Where(elem => elem.GetGraphic() is CIMLineGraphic);
////Find all polygon graphics in the Graphics Layer
var polyGraphics = graphicElements.Where(elem => elem.GetGraphic() is CIMPolygonGraphic);
////Find all text graphics in the Graphics Layer
var textGraphics = graphicElements.Where(elem => elem.GetGraphic() is CIMTextGraphic);
////Find all picture graphics in the Graphics Layer
var pictureGraphic = graphicElements.Where(elem => elem.GetGraphic() is CIMPictureGraphic);

更新元素属性

1
2
3
4
5
6
7
8
9
10
11
//Update an element's properties.

//Performed on worker thread
QueuedTask.Run(() =>
{
// update an element's name
element.SetName("New Name");

// update and element's visibility
element.SetVisible(true);
});

获取元素选择计数

1
2
3
4
5
6
7
8
9
//Get element's selection count.

//Count the number of selected elements on the active layout view
LayoutView activeLayoutView = LayoutView.Active;
if (activeLayoutView != null)
{
var selectedElements = activeLayoutView.GetSelectedElements();
ArcGIS.Desktop.Framework.Dialogs.MessageBox.Show($@"Selected elements: {selectedElements.Count}");
}

设置元素选择

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
//Set the active layout view's selection to include 2 rectangle elements.

//Reference the active view
LayoutView activeLayoutView = LayoutView.Active;
if (activeLayoutView != null)
{

//Perform on the worker thread
QueuedTask.Run(() =>
{

//Reference the layout
Layout lyt = activeLayoutView.Layout;

//Reference the two rectangle elements
Element rec = lyt.FindElement("Rectangle");
Element rec2 = lyt.FindElement("Rectangle 2");

//Construct a list and add the elements
List<Element> elmList = new List<Element>
{
rec,
rec2
};

//Set the selection
activeLayoutView.SelectElements(elmList);
});
}

取消选择布局上的元素

1
2
3
4
5
6
//Unselect one element.
var elementToUnSelect = layout.FindElements(new List<string>() { "MyPoint" }).FirstOrDefault();
layout.UnSelectElement(elementToUnSelect);
//Unselect multiple elements.
var elementsToUnSelect = layout.FindElements(new List<string>() { "Point 1", "Line 3", "Text 1" });
layout.UnSelectElements(elementsToUnSelect);

在布局视图中取消选择元素

1
2
3
4
5
6
7
LayoutView layoutView = LayoutView.Active;
//Unselect one element.
var elementToUnSelectInView = layout.FindElements(new List<string>() { "MyPoint" }).FirstOrDefault();
layoutView.UnSelectElement(elementToUnSelect);
//Unselect multiple elements.
var elementsToUnSelectInView = layout.FindElements(new List<string>() { "Point 1", "Line 3", "Text 1" });
layoutView.UnSelectElements(elementsToUnSelect);

清除布局视图中的选择

1
2
3
4
5
6
//If the a layout view is active, clear its selection
LayoutView activeLayoutView = LayoutView.Active;
if (activeLayoutView != null)
{
activeLayoutView.ClearElementSelection();
}

清除布局中的所选内容

1
2
//Clear the layout selection.
layout.ClearElementSelection();

复制布局元素

1
2
3
//on the QueuedTask
var elems = layout.FindElements(new List<string>() { "Point 1", "Line 3", "Text 1" });
var copiedElements = layout.CopyElements(elems);

删除布局元素

1
2
3
//on the QueuedTask  
var elementsToRemove = layout.GetSelectedElements();
layout.DeleteElements(elementsToRemove);

删除布局上的一个或多个元素

1
2
3
4
5
6
7
8
9
10
11
12
13
14
//Delete an element or elements on a layout.

//Perform on the worker thread
QueuedTask.Run(() =>
{
//Delete a specific element on a layout
aLayout.DeleteElement(elm);

//Or delete a group of elements using a filter
aLayout.DeleteElements(item => item.Name.Contains("Clone"));

//Or delete all elements on a layout
aLayout.DeleteElements(item => true);
});

缩放到元素

1
2
3
4
5
6
7
LayoutView lytView = LayoutView.Active;
//Zoom to an element
var elementToZoomTo = layout.FindElements(new List<string>() { "MyPoint" }).FirstOrDefault();
lytView.ZoomToElement(elementToZoomTo);
//Zoom to multiple elements.
var elementsToZoomTo = layout.FindElements(new List<string>() { "Point 1", "Line 3", "Text 1" });
lytView.ZoomToElements(elementsToZoomTo);

设置指北针的晕圈属性

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
//Set the CIM halo properties of a north arrow.

//Reference the first selected element (assumption is it is a north arrow)
Element northArrow = LayoutView.Active.GetSelectedElements().First();

//Perform on the worker thread
QueuedTask.Run(() =>
{
//Get definition of north arrow...
var cim = northArrow.GetDefinition() as CIMMarkerNorthArrow;

//this halo symbol is 50% transparent, no outline (i.e. 0 width)
//First construct a polygon symbol to use in the Halo
//Polygon symbol will need a fill and a stroke
var polyFill = SymbolFactory.Instance.ConstructSolidFill(ColorFactory.Instance.CreateRGBColor(0, 0, 0, 50));
var polyStroke = SymbolFactory.Instance.ConstructStroke(ColorFactory.Instance.BlackRGB, 0);
var haloPoly = SymbolFactory.Instance.ConstructPolygonSymbol(polyFill, polyStroke);

//Set the north arrow defintion of HaloSymbol and HaloSize
((CIMPointSymbol)cim.PointSymbol.Symbol).HaloSymbol = haloPoly;
((CIMPointSymbol)cim.PointSymbol.Symbol).HaloSize = 3;//size of the halo

//Apply the CIM changes back to the element
northArrow.SetDefinition(cim);
});

对图形元素进行分组和排序

组图形元素

1
2
3
4
5
//on the QueuedTask
var elemsToGroup = layout.GetSelectedElements();
//Note: run within the QueuedTask
//group elements
var groupElement = layout.GroupElements(elemsToGroup);

取消组合图形元素

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
var selectedElements = layout.GetSelectedElements().ToList(); 
if (selectedElements?.Any() == false)//must be at least 1.
return;
var elementsToUnGroup = new List<GroupElement>();
//All selected elements should be grouped elements.
if (selectedElements.Count() == selectedElements.OfType<GroupElement>().Count())
{
//Convert to a GroupElement list.
elementsToUnGroup = selectedElements.ConvertAll(x => (GroupElement)x);
}
if (elementsToUnGroup.Count() == 0)
return;
//UnGroup many grouped elements
layout.UnGroupElements(elementsToUnGroup);
//Ungroup one grouped element
layout.UnGroupElement(elementsToUnGroup.FirstOrDefault());

组元素的父级

1
2
3
4
5
//check the parent
var parent = groupElement.Elements.First().GetParent();//will be the group element
//top-most parent
//will be a GraphicsLayer or Layout
var top_most = groupElement.Elements.First().GetParent(true);

组元素中的子元素

1
2
// Nested groups within ArcGIS.Desktop.Layouts.GroupElement are not preserved.
var children = groupElement.GetElementsAsFlattenedList();

排序:向后发送和向前发送

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
//On the QueuedTask
//get the current selection set
var sel_elems = layout.GetSelectedElements();
//can they be brought forward? This will also check that all elements have the same parent
if (layout.CanBringForward(sel_elems))
{
//bring forward
layout.BringForward(sel_elems);
//bring to front (of parent)
//graphicsLayer.BringToFront(sel_elems);
}
else if (layout.CanSendBackward(sel_elems))
{
//send back
layout.SendBackward(sel_elems);
//send to the back (of parent)
//graphicsLayer.SendToBack(sel_elems);
}

获取 Z 顺序

1
2
3
4
5
var selElementsZOrder = layout.GetSelectedElements();
//list out the z order
foreach (var elem in selElementsZOrder)
//At 2.x - System.Diagnostics.Debug.WriteLine($"{elem.Name}: z-order {elem.GetZOrder()}");
System.Diagnostics.Debug.WriteLine($"{elem.Name}: z-order {elem.ZOrder}");

更新布局元素

更新文本元素属性

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
//Update text element properties for an existing text element.

// Reference a layoutitem in a project by name
LayoutProjectItem layoutItem = Project.Current.GetItems<LayoutProjectItem>()
.FirstOrDefault(item => item.Name.Equals("MyLayout"));
if (layoutItem != null)
{

//Perform on the worker thread
QueuedTask.Run(() =>
{
// Reference and load the layout associated with the layout item
Layout layout = layoutItem.GetLayout();
if (layout != null)
{
// Reference a text element by name
TextElement txtElm = layout.FindElement("MyTextElement") as TextElement;
if (txtElm != null)
{
// Change placement properties
txtElm.SetAnchor(Anchor.CenterPoint);
txtElm.SetX(x);
txtElm.SetY(y);

// Change TextProperties
TextProperties txtProperties = new TextProperties(
"Hello world", "Times New Roman", 48, "Regular");
txtElm.SetTextProperties(txtProperties);
}
}
});
}

更新图片元素

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
//Update a picture element.

//Perform on the worker thread
QueuedTask.Run(() =>
{
// Reference and load the layout associated with the layout item
Layout layout = layoutItem.GetLayout();
if (layout != null)
{
// Reference a picture element by name
PictureElement picElm = layout.FindElement("MyPicture") as PictureElement;
// Change the path to a new source
if (picElm != null)
picElm.SetSourcePath(@"D:\MyData\Pics\somePic.jpg");
}
});

将背景颜色应用于地图框

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
//Apply a background color to the map frame element using the CIM.

//Perform on the worker thread
QueuedTask.Run(() =>
{
//Get the layout
var myLayout = Project.Current.GetItems<LayoutProjectItem>()?.First().GetLayout();
if (myLayout == null) return;

//Get the map frame in the layout
MapFrame mapFrame = myLayout.FindElement("New Map Frame") as MapFrame;
if (mapFrame == null)
{
//TODO Handle null mapframe
return;
}

//Get the map frame's definition in order to modify the background.
var mapFrameDefn = mapFrame.GetDefinition() as CIMMapFrame;

//Construct the polygon symbol to use to create a background
var polySymbol = SymbolFactory.Instance.ConstructPolygonSymbol(
ColorFactory.Instance.BlueRGB, SimpleFillStyle.Solid);

//Set the background
mapFrameDefn.GraphicFrame.BackgroundSymbol =
polySymbol.MakeSymbolReference();

//Set the map frame definition
mapFrame.SetDefinition(mapFrameDefn);
});

更新地图整饰

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
//Update a map surround.

//Perform on the worker thread
QueuedTask.Run(() =>
{
// Reference and load the layout associated with the layout item
Layout layout = layoutItem.GetLayout();
if (layout != null)
{
// Reference a scale bar element by name
MapSurround scaleBar = layout.FindElement("MyScaleBar") as MapSurround;

// Reference a map frame element by name
MapFrame mf = layout.FindElement("MyMapFrame") as MapFrame;

if ((scaleBar != null) && (mf != null))
//Set the scale bar to the newly referenced map frame
scaleBar.SetMapFrame(mf);
}
});

锁定元素

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
// The Locked property is displayed in the TOC as a lock symbol next
// to each element. If locked the element can't be selected in the layout
// using the graphic selection tools.

//Perform on the worker thread
QueuedTask.Run(() =>
{
// Reference and load the layout associated with the layout item
Layout layout = layoutItem.GetLayout();
if (layout != null)
{
//Reference an element by name
Element element = layout.FindElement("MyElement");
if (element != null)
{
// Modify the Locked property via the CIM
CIMElement CIMElement = element.GetDefinition() as CIMElement;
CIMElement.Locked = true;
element.SetDefinition(CIMElement);
}
}
});

更新元素透明度

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
//Update an element's transparency using the CIM.

//Perform on the worker thread
QueuedTask.Run(() =>
{
// Reference and load the layout associated with the layout item
Layout layout = layoutItem.GetLayout();
if (layout != null)
{
// Reference a element by name
GraphicElement graphicElement = layout.FindElement("MyElement") as GraphicElement;
if (graphicElement != null)
{
// Modify the Transparency property that exists only in the CIMGraphic class.
CIMGraphic CIMGraphic = graphicElement.GetGraphic() as CIMGraphic;
CIMGraphic.Transparency = 50; // mark it 50% transparent
graphicElement.SetGraphic(CIMGraphic);
}
}
});

克隆元素

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
//Clone a layout graphic element and apply an offset.

//Perform on the worker thread
QueuedTask.Run(() =>
{
// Reference and load the layout associated with the layout item
Layout layout = layoutItem.GetLayout();
if (layout != null)
{
// Reference a graphic element by name
GraphicElement graphicElement =
layout.FindElement("MyElement") as GraphicElement;
if (graphicElement != null)
{

//Clone and set the new x,y
GraphicElement cloneElement = graphicElement.Clone("Clone");
cloneElement.SetX(cloneElement.GetX() + xOffset);
cloneElement.SetY(cloneElement.GetY() + yOffset);
}
}
});

布局元数据

布局元数据

1
2
3
4
5
6
7
8
9
//var layout = ...;
//Must be on the QueuedTask.Run()

//Gets the Layout metadata.
var layout_xml = layout.GetMetadata();
//Can metadata be edited?
if (layout.GetCanEditMetadata())
//Set the metadata back
layout.SetMetadata(layout_xml);

布局地图框

更改与地图框关联的地图

1
2
3
4
5
6
7
8
9
10
11
12
13
14
//Change the map associated with a map frame

//Reference a map frame on a layout
MapFrame mfrm = layout.FindElement("Map Frame") as MapFrame;

//Peform on worker thread
await QueuedTask.Run(() =>
{
//Reference map from the project item
Map map = Project.Current.GetItems<MapProjectItem>().FirstOrDefault(m => m.Name.Equals("Map1")).GetMap();

//Set the map to the map frame
mfrm.SetMap(map);
});

更改地图框照相机设置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
//Change a map frame's camera settings.

//Perform on the worker thread
await QueuedTask.Run(() =>
{
//Reference MapFrame
MapFrame mf = layout.FindElement("Map Frame") as MapFrame;

//Reference the camera associated with the map frame and change the scale
Camera cam = mf.Camera;
cam.Scale = 100000;

//Set the map frame extent based on the new camera info
mf.SetCamera(cam);
});

将地图框缩放到单个图层的范围

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
//Zoom map frame to the extent of a single layer.

//Perform on the worker thread
await QueuedTask.Run(() =>
{
//Reference MapFrame
MapFrame mf = layout.FindElement("Map Frame") as MapFrame;

//Reference map and layer
Map m = mf.Map;
FeatureLayer lyr = m.FindLayers("GreatLakes").First() as FeatureLayer;

//Set the map frame extent to all features in the layer
mf.SetCamera(lyr, false);
});

将地图框范围更改为多个图层中的所选要素

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
//Change the extent of a map frame to the selected features multiple layers.

//Perform on the worker thread
await QueuedTask.Run(() =>
{
//Reference MapFrame
MapFrame mf = layout.FindElement("Map Frame") as MapFrame;

//Reference map, layers and create layer list
Map m = mf.Map;
FeatureLayer fl_1 = m.FindLayers("GreatLakes").First() as FeatureLayer;
FeatureLayer fl_2 = m.FindLayers("States_WithRegions").First() as FeatureLayer;
var layers = new[] { fl_1, fl_2 };
//IEnumerable<Layer> layers = m.Layers; //This creates a list of ALL layers in map.

//Set the map frame extent to the selected features in the list of layers
mf.SetCamera(layers, true);
});

将地图框范围更改为具有 15% 缓冲区的单个要素

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
//Change map frame extent to single feature with 10 percent buffer

//Process on the worker thread
await QueuedTask.Run(() =>
{
//Reference the mapframe and its associated map
MapFrame mf = layout.FindElement("Map Frame") as MapFrame;
Map m = mf.Map;

//Reference a feature layer and build a query (to return a single feature)
FeatureLayer fl = m.FindLayers("GreatLakes").First() as FeatureLayer;
QueryFilter qf = new QueryFilter();
string whereClause = "NAME = 'Lake Erie'";
qf.WhereClause = whereClause;

//Zoom to the feature
using (ArcGIS.Core.Data.RowCursor rowCursor = fl.Search(qf))
{
while (rowCursor.MoveNext())
{
//Get the shape from the row and set extent
using (var feature = rowCursor.Current as ArcGIS.Core.Data.Feature)
{
Polygon polygon = feature.GetShape() as Polygon;
Envelope env = polygon.Extent as Envelope;
mf.SetCamera(env);

//Zoom out 15 percent
Camera cam = mf.Camera;
cam.Scale = cam.Scale * 1.15;
mf.SetCamera(cam);
}
}
}
});

将页面坐标中的点转换为地图坐标中的点。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
//On the QueuedTask
var layout = Project.Current.GetItems<LayoutProjectItem>().FirstOrDefault().GetLayout();
var mapFrame = layout.FindElement("New Map Frame") as MapFrame;

//Get a point in the center of the Map frame
var mapFrameCenterPoint = mapFrame.GetBounds().CenterCoordinate;
//Convert to MapPoint
//At 2.x - var pointInMapFrame = MapPointBuilder.CreateMapPoint(mapFrameCenterPoint);
var pointInMapFrame = MapPointBuilderEx.CreateMapPoint(mapFrameCenterPoint);

//Find the corresponding point in the MapView
var pointOnMap = mapFrame.PageToMap(pointInMapFrame);

//Create a point graphic on the MapView.
var cimGraphicElement = new CIMPointGraphic
{
Location = pointOnMap,
Symbol = pointSymbol.MakeSymbolReference()
};
graphicsLayer.AddElement(cimGraphicElement);

将地图坐标中的点转换为页面坐标中的点

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
internal class GetMapCoordinates : MapTool
{
protected override void OnToolMouseDown(MapViewMouseButtonEventArgs e)
{
if (e.ChangedButton == System.Windows.Input.MouseButton.Left)
e.Handled = true; //Handle the event args to get the call to the corresponding async method
}

protected override Task HandleMouseDownAsync(MapViewMouseButtonEventArgs e)
{
return QueuedTask.Run(() =>
{
var pointSymbol = SymbolFactory.Instance.ConstructPointSymbol(ColorFactory.Instance.BlackRGB, 8);
var layout = Project.Current.GetItems<LayoutProjectItem>().FirstOrDefault().GetLayout();

//Convert the clicked point in client coordinates to the corresponding map coordinates.
var mapPoint = MapView.Active.ClientToMap(e.ClientPoint);
ArcGIS.Desktop.Framework.Dialogs.MessageBox.Show(string.Format("X: {0} Y: {1} Z: {2}",
mapPoint.X, mapPoint.Y, mapPoint.Z), "Map Coordinates");
//Get the corresponding layout point
var mapFrame = layout.FindElement("New Map Frame") as MapFrame;
var pointOnLayoutFrame = mapFrame.MapToPage(mapPoint);

//Create a point graphic on the Layout.
var cimGraphicElement = new CIMPointGraphic
{
Location = pointOnLayoutFrame,
Symbol = pointSymbol.MakeSymbolReference()
};
//Or use GraphicFactory
var cimGraphicElement2 = GraphicFactory.Instance.CreateSimpleGraphic(
pointOnLayoutFrame, pointSymbol);

//At 2.x - LayoutElementFactory.Instance.CreateGraphicElement(layout, cimGraphicElement);

ElementFactory.Instance.CreateGraphicElement(layout, cimGraphicElement);
ElementFactory.Instance.CreateGraphicElement(layout, cimGraphicElement2);

});

}
}

布局图系列

修改现有地图系列

1
2
3
4
5
6
7
8
9
10
11
12
13
//Modify the currently active map series and changes its sort field and page number field.

//Perform on the worker thread
await QueuedTask.Run(() =>
{
SpatialMapSeries SMS = layout.MapSeries as SpatialMapSeries; //cast as spatial map seris for additional members
SMS.SortField = "State_Name";
SMS.SortAscending = true;
SMS.PageNumberField = "PageNum";

//Overwrite the current map series with these new settings
layout.SetMapSeries(SMS);
});

创建新的空间地图系列

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
// This example create a new spatial map series and then applies it to the active layout. This will automatically 
// overwrite an existing map series if one is already present.

//Reference map frame and index layer
MapFrame mf = layout.FindElement("Map Frame") as MapFrame;
Map m = mf.Map;
BasicFeatureLayer indexLyr = m.FindLayers("Countries").FirstOrDefault() as BasicFeatureLayer;

//Construct map series on worker thread
await QueuedTask.Run(() =>
{
//SpatialMapSeries constructor - required parameters
SpatialMapSeries SMS = MapSeries.CreateSpatialMapSeries(layout, mf, indexLyr, "Name");

//Set optional, non-default values
SMS.CategoryField = "Continent";
SMS.SortField = "Population";
SMS.ExtentOptions = ExtentFitType.BestFit;
SMS.MarginType = ArcGIS.Core.CIM.UnitType.PageUnits;
SMS.MarginUnits = ArcGIS.Core.Geometry.LinearUnit.Centimeters;
SMS.Margin = 1;
SMS.ScaleRounding = 1000;
layout.SetMapSeries(SMS); //Overwrite existing map series.
});

布局导出

将布局导出为 PDF

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
//Export a single page layout to PDF.

//Create a PDF format with appropriate settings
//BMP, EMF, EPS, GIF, JPEG, PNG, SVG, TGA, and TFF formats are also available for export
PDFFormat PDF = new PDFFormat()
{
OutputFileName = filePath,
Resolution = 300,
DoCompressVectorGraphics = true,
DoEmbedFonts = true,
HasGeoRefInfo = true,
ImageCompression = ImageCompression.Adaptive,
ImageQuality = ImageQuality.Best,
LayersAndAttributes = LayersAndAttributes.LayersAndAttributes
};

//Check to see if the path is valid and export
if (PDF.ValidateOutputFilePath())
{
await QueuedTask.Run(() => layout.Export(PDF)); //Export the layout to PDF on the worker thread
}

将地图框导出为 JPG

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
//Export a map frame to JPG.

//Create JPEG format with appropriate settings
//BMP, EMF, EPS, GIF, PDF, PNG, SVG, TGA, and TFF formats are also available for export
//at 2.x - JPEGFormat JPG = new JPEGFormat()
//{
// HasWorldFile = true,
// Resolution = 300,
// OutputFileName = filePath,
// JPEGColorMode = JPEGColorMode.TwentyFourBitTrueColor,
// Height = 800,
// Width = 1200
//};
JPEGFormat JPG = new JPEGFormat()
{
HasWorldFile = true,
Resolution = 300,
OutputFileName = filePath,
ColorMode = JPEGColorMode.TwentyFourBitTrueColor,
Height = 800,
Width = 1200
};

//Reference the map frame
MapFrame mf = layout.FindElement("MyMapFrame") as MapFrame;

//Export on the worker thread
await QueuedTask.Run(() =>
{
//Check to see if the path is valid and export
if (JPG.ValidateOutputFilePath())
{
mf.Export(JPG); //Export the map frame to JPG
}
});

将与地图框关联的地图视图导出到 BMP

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
//Export the map view associated with a map frame to BMP.

//Create BMP format with appropriate settings
//EMF, EPS, GIF, JPEG, PDF, PNG, SVG, TGA, and TFF formats are also available for export
BMPFormat BMP = new BMPFormat()
{
Resolution = 300,
Height = 500,
Width = 800,
HasWorldFile = true,
OutputFileName = filePath
};

//Reference the active layout view
LayoutView lytView = LayoutView.Active;

//Reference the map frame and its map view
MapFrame mf_bmp = layout.FindElement("Map Frame") as MapFrame;
MapView mv_bmp = mf_bmp.GetMapView(lytView);

if (mv_bmp != null)
{
//Export on the worker thread
await QueuedTask.Run(() =>
{

//Check to see if the path is valid and export
if (BMP.ValidateOutputFilePath())
{
mv_bmp.Export(BMP); //Export to BMP
}
});
}

将地图系列导出为单个 PDF

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
//Export a map series with multiple pages to a single PDF.

//Create PDF format with appropriate settings
PDFFormat MS_PDF = new PDFFormat()
{
OutputFileName = filePath,
Resolution = 300,
DoCompressVectorGraphics = true,
DoEmbedFonts = true,
HasGeoRefInfo = true,
ImageCompression = ImageCompression.Adaptive,
ImageQuality = ImageQuality.Best,
LayersAndAttributes = LayersAndAttributes.LayersAndAttributes
};

//Set up map series export options
MapSeriesExportOptions MS_ExportOptions = new MapSeriesExportOptions()
{
ExportPages = ExportPages.Custom, //Provide a specific list of pages
CustomPages = "1-3, 5", //Only used if ExportPages.Custom is set
ExportFileOptions = ExportFileOptions.ExportAsSinglePDF, //Export all pages to a single, multi-page PDF
ShowSelectedSymbology = false //Do no show selection symbology in the output
};

//Export on the worker thread
await QueuedTask.Run(() =>
{
//Check to see if the path is valid and export
if (MS_PDF.ValidateOutputFilePath())
{
layout.Export(MS_PDF, MS_ExportOptions); //Export to PDF
}
});

将地图系列导出到单个 TIFF 文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
//Export each page of a map series to an individual TIFF file.

//Create TIFF format with appropriate settings
TIFFFormat TIFF = new TIFFFormat()
{
OutputFileName = filePath,
Resolution = 300,
ColorMode = TIFFColorMode.TwentyFourBitTrueColor,
HasGeoTiffTags = true,
HasWorldFile = true,
ImageCompression = TIFFImageCompression.LZW
};

//Set up map series export options
MapSeriesExportOptions MSExportOptions_TIFF = new MapSeriesExportOptions()
{
ExportPages = ExportPages.All, //All pages
ExportFileOptions = ExportFileOptions.ExportMultipleNames, //Export each page to an individual file using page name as a suffix.
ShowSelectedSymbology = true //Include selection symbology in the output
};

//Export on the worker thread
await QueuedTask.Run(() =>
{
//Check to see if the path is valid and export
if (TIFF.ValidateOutputFilePath())
{
layout.Export(TIFF, MSExportOptions_TIFF); //Export to TIFF
}
});

布局选项

获取布局选项

1
2
3
4
var lastToolActive = ApplicationOptions.LayoutOptions.KeepLastToolActive;
var warnOnSurrounds = ApplicationOptions.LayoutOptions.WarnAboutAssociatedSurrounds;
//eg <Install_Path>\Resources\LayoutTemplates\en-US
var gallery_path = ApplicationOptions.LayoutOptions.LayoutTemplatePath;

设置布局选项

1
2
3
4
5
6
//keep graphic element insert tool active
ApplicationOptions.LayoutOptions.KeepLastToolActive = true;
//no warning when deleting a map frame results in other elements being deleted
ApplicationOptions.LayoutOptions.WarnAboutAssociatedSurrounds = false;
//path to .pagx files used as templates
ApplicationOptions.LayoutOptions.LayoutTemplatePath = @"D:\data\layout_templates";

文本和图形元素选项

获取所有可用字体

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
//Note: see also SymbolFactory.Instance.GetAvailableFonts() which returns the
//same list. Use for TextAndGraphicsElementsOptions.GetAvailableFonts() convenience

QueuedTask.Run(() =>
{
//A list of tuples of Font name + associated Font Styles, one tuple per
//font, is returned
var fonts = ApplicationOptions.TextAndGraphicsElementsOptions.GetAvailableFonts();
StringBuilder sb = new StringBuilder();
sb.AppendLine("Pro Fonts\r\n============================");
foreach (var font in fonts)
{
var styles = string.Join(",", font.fontStyles);
sb.AppendLine($"{font.fontName}, [{styles}]");
}
System.Diagnostics.Debug.WriteLine(sb.ToString());
});

获取文本和图形元素选项

1
2
3
4
5
6
7
8
9
10
11
12
13
QueuedTask.Run(() =>
{
//Get the default font (see also 'SymbolFactory.Instance.DefaultFont')
var def_font = ApplicationOptions.TextAndGraphicsElementsOptions.GetDefaultFont();
System.Diagnostics.Debug.WriteLine(
$"\r\ndefault font: {def_font.fontName}, {def_font.styleName}");

//Get the default graphics element symbols - point, line, poly, text
var ptSymbol = ApplicationOptions.TextAndGraphicsElementsOptions.GetDefaultPointSymbol();
var lineSymbol = ApplicationOptions.TextAndGraphicsElementsOptions.GetDefaultLineSymbol();
var polySymbol = ApplicationOptions.TextAndGraphicsElementsOptions.GetDefaultPolygonSymbol();
var textSymbol = ApplicationOptions.TextAndGraphicsElementsOptions.GetDefaultTextSymbol();
});

设置文本和图形元素选项

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
QueuedTask.Run(() =>
{
//Set a default font. Use its default style
ApplicationOptions.TextAndGraphicsElementsOptions.SetDefaultFont("tahoma");
//or specify an explicit style
ApplicationOptions.TextAndGraphicsElementsOptions.SetDefaultFont("tahoma", "bold");

//Create symbols
var ptSymbol2 = SymbolFactory.Instance.ConstructPointSymbol(
ColorFactory.Instance.RedRGB, 14, SimpleMarkerStyle.Diamond);
var lineSymbol2 = SymbolFactory.Instance.ConstructLineSymbol(
ColorFactory.Instance.RedRGB, 2, SimpleLineStyle.Dash);
var polySymbol2 = SymbolFactory.Instance.ConstructPolygonSymbol(
ColorFactory.Instance.RedRGB, SimpleFillStyle.DiagonalCross);
var textSymbol2 = SymbolFactory.Instance.ConstructTextSymbol(
ColorFactory.Instance.RedRGB, 12);

//Set default point, line, poly, text graphics element symbols
ApplicationOptions.TextAndGraphicsElementsOptions.SetDefaultPointSymbol(ptSymbol2);
ApplicationOptions.TextAndGraphicsElementsOptions.SetDefaultLineSymbol(lineSymbol2);
ApplicationOptions.TextAndGraphicsElementsOptions.SetDefaultPolygonSymbol(polySymbol2);
ApplicationOptions.TextAndGraphicsElementsOptions.SetDefaultTextSymbol(textSymbol2);
});

MapFrame_Display_Constraints

设置自动相机无

1
2
3
4
5
6
7
8
var layout = LayoutView.Active.Layout;
var mf = layout.GetElementsAsFlattenedList().OfType<MapFrame>()
.First(mf => mf.Name == mapFrame);
var autoCamera = mf.GetAutoCamera();
autoCamera.Source = AutoCameraSource.None;
if (mf.ValidateAutoCamera(autoCamera) &&
!mf.IsMapSeriesMapFrame())
mf.SetAutoCamera(autoCamera);

设置自动相机固定范围

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
var layout = LayoutView.Active.Layout;
var mf = layout.GetElementsAsFlattenedList().OfType<MapFrame>()
.First(mf => mf.Name == mapFrame);
var autoCamera = mf.GetAutoCamera();
autoCamera.Source = AutoCameraSource.Fixed;
autoCamera.AutoCameraType = AutoCameraType.Extent;

var mf_extent = mf.GetViewExtent();

var extent = EnvelopeBuilderEx.CreateEnvelope(
400748.62, 800296.4, 1310669.05, 1424520.74, mf.Map.SpatialReference);
autoCamera.Extent = extent;

if (mf.ValidateAutoCamera(autoCamera) &&
!mf.IsMapSeriesMapFrame())
mf.SetAutoCamera(autoCamera);

设置自动相机固定中心

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
var layout = LayoutView.Active.Layout;
var mf = layout.GetElementsAsFlattenedList().OfType<MapFrame>()
.First(mf => mf.Name == mapFrame);
var autoCamera = mf.GetAutoCamera();
autoCamera.Source = AutoCameraSource.Fixed;
autoCamera.AutoCameraType = AutoCameraType.Center;

var camera = mf.GetMapView(LayoutView.Active).Camera;
var center = mf.GetViewCenter();

//var extent = EnvelopeBuilderEx.CreateEnvelope(
// 400748.62, 800296.4, 1310669.05, 1424520.74, mf.Map.SpatialReference);
//autoCamera.Extent = extent;

var camera2 = new CIMViewCamera()
{
Heading = 0,
Pitch = -90,
Roll = 0,
Scale = 21169571,
X = 855708,
Y = 1112409,
Z = double.NaN
};
autoCamera.Camera = camera2;
var states = mf.Map.GetLayersAsFlattenedList().First(l => l.Name == "State_Polygons");
autoCamera.IntersectLayerPath = states.URI;

if (mf.ValidateAutoCamera(autoCamera) &&
!mf.IsMapSeriesMapFrame())
mf.SetAutoCamera(autoCamera);

设置自动相机固定居中和缩放

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
var layout = LayoutView.Active.Layout;
var mf = layout.GetElementsAsFlattenedList().OfType<MapFrame>()
.First(mf => mf.Name == mapFrame);
var autoCamera = mf.GetAutoCamera();
autoCamera.Source = AutoCameraSource.Fixed;
autoCamera.AutoCameraType = AutoCameraType.CenterAndScale;

var camera = mf.GetMapView(LayoutView.Active).Camera;
var center = mf.GetViewCenter();

//var extent = EnvelopeBuilderEx.CreateEnvelope(
// 400748.62, 800296.4, 1310669.05, 1424520.74, mf.Map.SpatialReference);
//autoCamera.Extent = extent;

var camera2 = new CIMViewCamera()
{
Heading = 0,
Pitch = -90,
Roll = 0,
Scale = 21169571,
X = 1310669.0 + ((400748.5 - 1310669.0) / 2.0),
Y = 800296.4 + ((1424520.74 - 800296.4) / 2.0),
Z = double.NaN
};
autoCamera.Camera = camera2;
var states = mf.Map.GetLayersAsFlattenedList().First(l => l.Name == "State_Polygons");
//autoCamera.IntersectLayerPath = states.URI;


if (mf.ValidateAutoCamera(autoCamera) &&
!mf.IsMapSeriesMapFrame())
mf.SetAutoCamera(autoCamera);

设置自动相机固定比例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
var layout = LayoutView.Active.Layout;
var mf = layout.GetElementsAsFlattenedList().OfType<MapFrame>()
.First(mf => mf.Name == mapFrame);
var autoCamera = mf.GetAutoCamera();
autoCamera.Source = AutoCameraSource.Fixed;
autoCamera.AutoCameraType = AutoCameraType.Scale;

var camera = mf.GetMapView(LayoutView.Active).Camera;
var center = mf.GetViewCenter();

//var extent = EnvelopeBuilderEx.CreateEnvelope(
// 400748.62, 800296.4, 1310669.05, 1424520.74, mf.Map.SpatialReference);
//autoCamera.Extent = extent;

var camera2 = new CIMViewCamera()
{
Heading = 0,
Pitch = -90,
Roll = 0,
Scale = 20000571,
X = 1310669.0 + ((400748.5 - 1310669.0) / 2.0),
Y = 800296.4 + ((1424520.74 - 800296.4) / 2.0),
Z = double.NaN
};
autoCamera.Camera = camera2;
var states = mf.Map.GetLayersAsFlattenedList().First(l => l.Name == "State_Polygons");
//autoCamera.IntersectLayerPath = states.URI;

if (mf.ValidateAutoCamera(autoCamera) &&
!mf.IsMapSeriesMapFrame())
mf.SetAutoCamera(autoCamera);

设置自动照相机链接范围

1
2
3
4
5
6
7
8
9
10
11
var layout = LayoutView.Active.Layout;
var mf = layout.GetElementsAsFlattenedList().OfType<MapFrame>()
.First(mf => mf.Name == mapFrame);
var autoCamera = mf.GetAutoCamera();
autoCamera.Source = AutoCameraSource.MapFrameLink;
autoCamera.AutoCameraType = AutoCameraType.Extent;
autoCamera.MapFrameLinkName = mapFrameLink;

if (mf.ValidateAutoCamera(autoCamera) &&
!mf.IsMapSeriesMapFrame())
mf.SetAutoCamera(autoCamera);

设置自动相机链接中心

1
2
3
4
5
6
7
8
9
10
11
12
13
var layout = LayoutView.Active.Layout;
var mf = layout.GetElementsAsFlattenedList().OfType<MapFrame>()
.First(mf => mf.Name == mapFrame);
var autoCamera = mf.GetAutoCamera();
autoCamera.Source = AutoCameraSource.MapFrameLink;
autoCamera.AutoCameraType = AutoCameraType.Center;
autoCamera.MapFrameLinkName = mapFrameLink;
var states = mf.Map.GetLayersAsFlattenedList().First(l => l.Name == "State_Polygons");
autoCamera.IntersectLayerPath = states.URI;

if (mf.ValidateAutoCamera(autoCamera) &&
!mf.IsMapSeriesMapFrame())
mf.SetAutoCamera(autoCamera);

设置自动相机链接中心和缩放

1
2
3
4
5
6
7
8
9
10
11
12
13
var layout = LayoutView.Active.Layout;
var mf = layout.GetElementsAsFlattenedList().OfType<MapFrame>()
.First(mf => mf.Name == mapFrame);
var autoCamera = mf.GetAutoCamera();
autoCamera.Source = AutoCameraSource.MapFrameLink;
autoCamera.AutoCameraType = AutoCameraType.CenterAndScale;
autoCamera.MapFrameLinkName = mapFrameLink;
var states = mf.Map.GetLayersAsFlattenedList().First(l => l.Name == "State_Polygons");
autoCamera.IntersectLayerPath = states.URI;

if (mf.ValidateAutoCamera(autoCamera) &&
!mf.IsMapSeriesMapFrame())
mf.SetAutoCamera(autoCamera);

设置自动相机链接缩放

1
2
3
4
5
6
7
8
9
10
11
12
13
var layout = LayoutView.Active.Layout;
var mf = layout.GetElementsAsFlattenedList().OfType<MapFrame>()
.First(mf => mf.Name == mapFrame);
var autoCamera = mf.GetAutoCamera();
autoCamera.Source = AutoCameraSource.MapFrameLink;
autoCamera.AutoCameraType = AutoCameraType.Scale;
autoCamera.MapFrameLinkName = mapFrameLink;
var states = mf.Map.GetLayersAsFlattenedList().First(l => l.Name == "State_Polygons");
autoCamera.IntersectLayerPath = states.URI;

if (mf.ValidateAutoCamera(autoCamera) &&
!mf.IsMapSeriesMapFrame())
mf.SetAutoCamera(autoCamera);

设置自动相机链接地图系列形状

1
2
3
4
5
6
7
8
9
10
11
12
13
var layout = LayoutView.Active.Layout;
var mf = layout.GetElementsAsFlattenedList().OfType<MapFrame>()
.First(mf => mf.Name == mapFrame);
var autoCamera = mf.GetAutoCamera();
autoCamera.Source = AutoCameraSource.MapSeriesLink;
autoCamera.AutoCameraType = AutoCameraType.Extent;
//autoCamera.MapFrameLinkName = mapFrameLink;
var states = mf.Map.GetLayersAsFlattenedList().First(l => l.Name == "State_Polygons");
autoCamera.IntersectLayerPath = states.URI;

if (mf.ValidateAutoCamera(autoCamera) &&
!mf.IsMapSeriesMapFrame())
mf.SetAutoCamera(autoCamera);

设置自动相机链接地图系列中心

1
2
3
4
5
6
7
8
9
10
11
12
13
var layout = LayoutView.Active.Layout;
var mf = layout.GetElementsAsFlattenedList().OfType<MapFrame>()
.First(mf => mf.Name == mapFrame);
var autoCamera = mf.GetAutoCamera();
autoCamera.Source = AutoCameraSource.MapSeriesLink;
autoCamera.AutoCameraType = AutoCameraType.Center;

var states = mf.Map.GetLayersAsFlattenedList().First(l => l.Name == "State_Polygons");
autoCamera.IntersectLayerPath = states.URI;

if (mf.ValidateAutoCamera(autoCamera) &&
!mf.IsMapSeriesMapFrame())
mf.SetAutoCamera(autoCamera);

布局-报告

报告项目项

获取当前项目中的所有报表

1
2
3
4
5
var projectReports = Project.Current.GetItems<ReportProjectItem>();
foreach (var reportItem in projectReports)
{
//Do Something with the report
}

获取特定报告

1
2
ReportProjectItem reportProjItem = Project.Current.GetItems<ReportProjectItem>().FirstOrDefault(item => item.Name.Equals(reportName));
Report report = reportProjItem?.GetReport();

在新视图中打开报表项目项

1
2
3
4
5
6
7
8
9
10
11
//Open a report project item in a new view.
//A report project item may exist but it may not be open in a view.

//Reference a report project item by name
ReportProjectItem reportPrjItem = Project.Current.GetItems<ReportProjectItem>().FirstOrDefault(item => item.Name.Equals("MyReport"));

//Get the report associated with the report project item
Report reportToOpen = await QueuedTask.Run(() => reportPrjItem.GetReport());

//Create the new pane
IReportPane iNewReporttPane = await ProApp.Panes.CreateReportPaneAsync(reportToOpen); //GUI thread

激活已打开的报告视图

1
2
3
4
5
6
7
8
Report report = Project.Current.GetItems<ReportProjectItem>().FirstOrDefault().GetReport();
var reportPane = FrameworkApplication.Panes.FindReportPanes(report).Last();
if (reportPane == null)
return;
//Activate the pane
(reportPane as ArcGIS.Desktop.Framework.Contracts.Pane).Activate();
//Get the "ReportView" associated with the Report Pane.
ReportView reportView = reportPane.ReportView;

引用活动报表视图

1
2
3
4
5
6
//Confirm if the current, active view is a report view.  If it is, do something.
ReportView activeReportView = ReportView.Active;
if (activeReportView != null)
{
// do something
}

刷新报表视图

1
2
3
if (reportView == null)
return;
QueuedTask.Run(() => reportView.Refresh());

缩放到整个页面

1
QueuedTask.Run(() => reportView.ZoomToWholePage());

缩放到报表视图上的特定位置

1
2
3
4
//On the QueuedTask
var detailsSection = report.Elements.OfType<ReportSection>().FirstOrDefault().Elements.OfType<ReportDetails>().FirstOrDefault();
var bounds = detailsSection.GetBounds();
ReportView.Active.ZoomTo(bounds);

缩放到页面宽度

1
2
//Process on worker thread
QueuedTask.Run(() => reportView.ZoomToPageWidth());

创建报告

创建报告

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
//Note: Call within QueuedTask.Run()
//The fields in the datasource used for the report
//This uses a US Cities dataset
var listFields = new List<CIMReportField> {
//Grouping should be the first field
new CIMReportField{Name = "STATE_NAME", FieldOrder = 0, Group = true, SortInfo = FieldSortInfo.Desc}, //Group cities using STATES
new CIMReportField{Name = "CITY_NAME", FieldOrder = 1},
new CIMReportField{Name = "POP1990", FieldOrder = 2, },
};
//Definition query to use for the data source
var defQuery = "STATE_NAME LIKE 'C%'";
//Define the Datasource
//pass true to use the selection set
var reportDataSource = new ReportDataSource(featureLayer, defQuery, false, listFields);
//The CIMPage defintion - page size, units, etc
var cimReportPage = new CIMPage
{
Height = 11,
StretchElements = false,
Width = 6.5,
ShowRulers = true,
ShowGuides = true,
Margin = new CIMMargin { Bottom = 1, Left = 1, Right = 1, Top = 1 },
Units = LinearUnit.Inches
};

//Report template
var reportTemplates = await ReportTemplateManager.GetTemplatesAsync();
var reportTemplate = reportTemplates.Where(r => r.Name == "Attribute List with Grouping").First();

//Report Styling
var reportStyles = await ReportStylingManager.GetStylingsAsync();
var reportStyle = reportStyles.Where(s => s == "Cool Tones").First();

//Field Statistics
var fieldStatisticsList = new List<ReportFieldStatistic> {
new ReportFieldStatistic{ Field = "POP1990", Statistic = FieldStatisticsFlag.Sum}
//Note: NoStatistics option for FieldStatisticsFlag is not supported.
};
var report = ReportFactory.Instance.CreateReport("USAReport", reportDataSource, cimReportPage, fieldStatisticsList, reportTemplate, reportStyle);

将报告导出为 pdf

1
2
3
4
5
6
7
8
9
10
11
12
13
//Note: Call within QueuedTask.Run()
//Define Export Options
var exportOptions = new ReportExportOptions
{
ExportPageOption = ExportPageOptions.ExportAllPages,
TotalPageNumberOverride = 0

};
//Create PDF format with appropriate settings
PDFFormat pdfFormat = new PDFFormat();
pdfFormat.Resolution = 300;
pdfFormat.OutputFileName = path;
report.ExportToPDF($"{report.Name}", pdfFormat, exportOptions, useSelection);

导入报告文件

1
2
3
//Note: Call within QueuedTask.Run()
Item reportToImport = ItemFactory.Instance.Create(reportFile);
Project.Current.AddItem(reportToImport as IProjectItem);

删除报表

1
2
3
4
5
6
7
8
9
10
//Note: Call within QueuedTask.Run()
//Reference a reportitem in a project by name
ReportProjectItem reportItem = Project.Current.GetItems<ReportProjectItem>().FirstOrDefault(item => item.Name.Equals(reportName));

//Check for report item
if (reportItem == null)
return Task.FromResult<bool>(false);

//Delete the report from the project
return Task.FromResult<bool>(Project.Current.RemoveItem(reportItem));

修改报表

重命名报表

1
2
3
//Note: Call within QueuedTask.Run()
ReportProjectItem reportProjItem = Project.Current.GetItems<ReportProjectItem>().FirstOrDefault(item => item.Name.Equals(reportName));
reportProjItem.GetReport().SetName("RenamedReport");

修改报表定义查询

1
2
3
4
5
6
7
8
9
10
11
12
13
14
//Note: Call within QueuedTask.Run()
//Remove Groups
// The fields in the datasource used for the report
var listFields = new List<string> {
"STATE_NAME"
};
report.RemoveGroups(listFields);

//Add Group
report.AddGroup("STATE_NAME", true, true, "");

//Modify the Definition Query
var defQuery = "STATE_NAME LIKE 'C%'";
report.SetDefinitionQuery(defQuery);

修改报表页

1
2
3
4
5
6
7
8
9
10
11
12
13
14
//Note: Call within QueuedTask.Run()
var cimReportPage = new CIMPage
{
Height = 12,
StretchElements = false,
Width = 6.5,
ShowRulers = true,
ShowGuides = true,
Margin = new CIMMargin { Bottom = 1, Left = 1, Right = 1, Top = 1 },
Units = LinearUnit.Inches
};
report.SetPage(cimReportPage);
//Change only the report's page height
report.SetPageHeight(12);

添加子报表

1
2
3
4
5
6
7
8
9
//Note: Call within QueuedTask.Run()
var mainReport = Project.Current.GetItems<ReportProjectItem>().FirstOrDefault(r => r.Name == "USAReports")?.GetReport();

if (mainReport == null) return;
//Add sub report
var vermontReportItem = Project.Current.GetItems<ReportProjectItem>().FirstOrDefault(r => r.Name == "Vermont");
if (vermontReportItem == null) return;
Report vermontReport = vermontReportItem.GetReport();
mainReport.AddSubReport(vermontReportItem, -1, true); // If -1, the subreport is added to the end of the report.

报表设计

获取报告模板

1
2
3
4
5
6
7
8
//Report Template Styles:
//Attribute List
//Attribute List with Grouping
//Basic Summary
//Basic Summary with Grouping
//Page Per Feature
var reportTemplates = await ReportTemplateManager.GetTemplatesAsync();
var reportTemplate = reportTemplates.Where(r => r.Name == reportTemplateName).First();

获取报表样式

1
2
3
4
5
6
//Report Styling:
//Black and White
//Cool Tones
//Warm Tones
var reportStyles = await ReportStylingManager.GetStylingsAsync();
var reportStyle = reportStyles.Where(s => s == reportStyleName).First();

报表元素

获取各种报告部分

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
//Get the "ReportSection element"
//ReportSectionElement contains the ReportHeader, ReportPageHeader, ReportDetails. ReportPageFooter, ReportFooter sections.
var mainReportSection = report.Elements.OfType<ReportSection>().FirstOrDefault();

//Get the ReportHeader
var reportHeader = mainReportSection?.Elements.OfType<ReportHeader>().FirstOrDefault();

//Get the ReportHeader
var reportPageHeader = mainReportSection?.Elements.OfType<ReportPageHeader>().FirstOrDefault();

//Get the "ReportDetails" within the ReportSectionElement. ReportDetails is where "fields" are.
var reportDetailsSection = mainReportSection?.Elements.OfType<ReportDetails>().FirstOrDefault();

//Get the ReportPageFooter
var reportPageFooter = mainReportSection?.Elements.OfType<ReportPageFooter>().FirstOrDefault();

//Get the ReportFooter
var reportFooter = mainReportSection?.Elements.OfType<ReportFooter>().FirstOrDefault();

选择元素

1
2
3
4
//ReportDetailsSection contains the "Fields"

var elements = reportDetailsSection.Elements;
reportDetailsSection.SelectElements(elements);

选择所有元素

1
2
3
//Select all elements in the Report Footer.
ReportPageFooter pageFooterSection = report.Elements.OfType<ReportSection>().FirstOrDefault().Elements.OfType<ReportPageFooter>().FirstOrDefault();
pageFooterSection.SelectAllElements();

获取所选元素

1
2
3
IReadOnlyList<Element> selectedElements = report.GetSelectedElements();
//Can also use the active ReportView
IReadOnlyList<Element> selectedElementsFromView = ReportView.Active.GetSelectedElements();

缩放至所选元素

1
QueuedTask.Run(() => reportView.ZoomToSelectedElements());

清晰的元素选择

1
reportView.ClearElementSelection();

根据名称查找报表中的特定元素。

1
2
var reportElementsToFind = new List<string> { "ReportText1", "ReportText2" };
var textReportElements = report.FindElements(reportElementsToFind);

删除元素

1
QueuedTask.Run(() => report.DeleteElements(textReportElements));

在报表中创建新字段

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
//This is the gap between two fields
double fieldIncrement = 0.9388875113593206276389;
//On the QueuedTask
//New field to add.
var newReportField = new CIMReportField
{
Name = "POP1990",
FieldOrder = 2,
};
//Get the "ReportSection element"
var mainReportSection = report.Elements.OfType<ReportSection>().FirstOrDefault();
if (mainReportSection == null) return;

//Get the "ReportDetails" within the ReportSectionElement. ReportDetails is where "fields" are.
var reportDetailsSection = mainReportSection?.Elements.OfType<ReportDetails>().FirstOrDefault();
if (reportDetailsSection == null) return;

//Within ReportDetails find the envelope that encloses a field.
//We get the first CIMParagraphTextGraphic in the collection so that we can add the new field next to it.
var lastFieldGraphic = reportDetailsSection.Elements.FirstOrDefault((r) =>
{
var gr = r as GraphicElement;
if (gr == null) return false;
return (gr.GetGraphic() is CIMParagraphTextGraphic ? true : false);
});
//Get the Envelope of the last field
var graphicBounds = lastFieldGraphic.GetBounds();

//Min and Max values of the envelope
var xMinOfFieldEnvelope = graphicBounds.XMin;
var yMinOfFieldEnvelope = graphicBounds.YMin;

var xMaxOfFieldEnvelope = graphicBounds.XMax;
var YMaxOfFieldEnvelope = graphicBounds.YMax;
//create the new Envelope to be offset from the existing field
//At 2.x
//MapPoint newMinPoint = MapPointBuilder.CreateMapPoint(xMinOfFieldEnvelope + fieldIncrement, yMinOfFieldEnvelope);
//MapPoint newMaxPoint = MapPointBuilder.CreateMapPoint(xMaxOfFieldEnvelope + fieldIncrement, YMaxOfFieldEnvelope);
//Envelope newFieldEnvelope = EnvelopeBuilder.CreateEnvelope(newMinPoint, newMaxPoint);

MapPoint newMinPoint = MapPointBuilderEx.CreateMapPoint(xMinOfFieldEnvelope + fieldIncrement, yMinOfFieldEnvelope);
MapPoint newMaxPoint = MapPointBuilderEx.CreateMapPoint(xMaxOfFieldEnvelope + fieldIncrement, YMaxOfFieldEnvelope);
Envelope newFieldEnvelope = EnvelopeBuilderEx.CreateEnvelope(newMinPoint, newMaxPoint);

//Create field
GraphicElement fieldGraphic = ReportElementFactory.Instance.CreateFieldValueTextElement(reportDetailsSection, newFieldEnvelope, newReportField);

地图创作

地图

获取活动地图

1
Map map = MapView.Active.Map;

使用默认底图图层创建新地图

1
2
3
4
5
await QueuedTask.Run(() =>
{
var map = MapFactory.Instance.CreateMap(mapName, basemap: Basemap.ProjectDefault);
//TODO: use the map...
});

在工程中查找地图并将其打开

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
public static async Task<Map> FindOpenExistingMapAsync(string mapName)
{
return await QueuedTask.Run(async () =>
{
Map map = null;
Project proj = Project.Current;

//Finding the first project item with name matches with mapName
MapProjectItem mpi =
proj.GetItems<MapProjectItem>()
.FirstOrDefault(m => m.Name.Equals(mapName, StringComparison.CurrentCultureIgnoreCase));
if (mpi != null)
{
map = mpi.GetMap();
//Opening the map in a mapview
await ProApp.Panes.CreateMapPaneAsync(map);
}
return map;
});

}

打开 web 地图

1
2
3
4
5
6
7
8
9
10
11
Map map = null;

//Assume we get the selected webmap from the Project pane's Portal tab
if (Project.Current.SelectedItems.Count > 0)
{
if (MapFactory.Instance.CanCreateMapFrom(Project.Current.SelectedItems[0]))
{
map = MapFactory.Instance.CreateMapFromItem(Project.Current.SelectedItems[0]);
await ProApp.Panes.CreateMapPaneAsync(map);
}
}

获取地图窗格

1
2
3
4
5
public static IEnumerable<IMapPane> GetMapPanes()
{
//Sorted by Map Uri
return ProApp.Panes.OfType<IMapPane>().OrderBy((mp) => mp.MapView.Map.URI ?? mp.MapView.Map.Name);
}

从地图窗格中获取唯一的地图列表

1
2
3
4
5
6
7
8
9
10
11
12
13
public static IReadOnlyList<Map> GetMapsFromMapPanes()
{
//Gets the unique list of Maps from all the MapPanes.
//Note: The list of maps retrieved from the MapPanes
//maybe less than the total number of Maps in the project.
//It depends on what maps the user has actually opened.
var mapPanes = ProApp.Panes.OfType<IMapPane>()
.GroupBy((mp) => mp.MapView.Map.URI).Select(grp => grp.FirstOrDefault());
List<Map> uniqueMaps = new List<Map>();
foreach (var pane in mapPanes)
uniqueMaps.Add(pane.MapView.Map);
return uniqueMaps;
}

更改地图名称

1
MapView.Active.Map.SetName("Test");

重命名窗格的标题

1
ProApp.Panes.ActivePane.Caption = "Caption";

将地图转换为局部场景

1
2
3
4
//Note: Run within the context of QueuedTask.Run
bool canConvertMap = MapFactory.Instance.CanConvertMap(map, MapConversionType.SceneLocal);
if (canConvertMap)
MapFactory.Instance.ConvertMap(map, MapConversionType.SceneLocal, true);

获取底图

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
//Basemaps stored locally in the project. This is usually an empty collection
string localBasemapTypeID = "cim_map_basemap";
var localBasemaps = await QueuedTask.Run(() =>
{
var mapContainer = Project.Current.GetProjectItemContainer("Map");
return mapContainer.GetItems().Where(i => i.TypeID == localBasemapTypeID).ToList();
});

//portal basemaps. If there is no current active portal, the usual default
//is arcgis online
var portal = ArcGISPortalManager.Current.GetActivePortal();
var portalBaseMaps = await portal.GetBasemapsAsync();

//use one of them...local or portal...
//var map = MapView.Active.Map;
//QueuedTask.Run(() => map?.SetBasemapLayers(portalBaseMaps[0]));

将地图另存为 MapX

1
map.SaveAsFile(@"C:\Data\MyMap.mapx", true);

将 2D 地图另存为 Web 地图 在磁盘上

1
2
3
4
5
//2D maps only
//Must be on the QueuedTask.Run(...)
if (map.DefaultViewingMode == MapViewingMode.Map)
//Only webmap compatible layers will be saved out to the file
map.SaveAsWebMapFile(@"C:\Data\MyMap.json");

裁剪映射到提供的裁剪多边形

1
2
3
4
5
6
7
8
9
10
11
12
//Run within QueuedTask
var map = MapView.Active.Map;
//A layer to use for the clip extent
var lyrOfInterest = MapView.Active.Map.GetLayersAsFlattenedList().OfType<FeatureLayer>().Where(l => l.Name == "TestPoly").FirstOrDefault();
//Get the polygon to use to clip the map
var extent = lyrOfInterest.QueryExtent();
var polygonForClipping = PolygonBuilderEx.CreatePolygon(extent);
//Clip the map using the layer's extent
map.SetClipGeometry(polygonForClipping,
SymbolFactory.Instance.ConstructLineSymbol(
SymbolFactory.Instance.ConstructStroke(
ColorFactory.Instance.BlueRGB, 2.0, SimpleLineStyle.Dash)));

清除当前地图剪辑几何

1
2
3
4
5
//Run within QueuedTask
var map = MapView.Active.Map;
//Clear the Map clip.
//If no clipping is set then this is a no-op.
map.ClearClipGeometry();

获取地图裁剪几何

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
var map = MapView.Active.Map;
//If clipping is set to ArcGIS.Core.CIM.ClippingMode.None or ArcGIS.Core.CIM.ClippingMode.MapSeries null is returned
//If clipping is set to ArcGIS.Core.CIM.ClippingMode.MapExtent the ArcGIS.Core.CIM.CIMMap.CustomFullExtent is returned.
//Otherwise, if clipping is set to ArcGIS.Core.CIM.ClippingMode.CustomShape the custom clip polygon is returned.
var poly = map.GetClipGeometry();
//You can use the polygon returned
//For example: We make a polygon graphic element and add it to a Graphics Layer.
var gl = map.GetLayersAsFlattenedList().OfType<GraphicsLayer>().FirstOrDefault();
if (gl == null) return;
var polygonSymbol = SymbolFactory.Instance.ConstructPolygonSymbol(CIMColor.CreateRGBColor(255, 255, 0));
var cimGraphicElement = new CIMPolygonGraphic
{
Polygon = poly,
Symbol = polygonSymbol.MakeSymbolReference()
};
gl.AddElement(cimGraphicElement);

获取当前地图位置单元

1
2
3
4
5
6
7
//var map = MapView.Active.Map;
//Must be on the QueuedTask.Run()

//Get the current location unit
var loc_unit = map.GetLocationUnitFormat();
var line = $"{loc_unit.DisplayName}, {loc_unit.UnitCode}";
System.Diagnostics.Debug.WriteLine(line);

获取可用的地图位置单位列表

1
2
3
4
5
6
//var map = MapView.Active.Map;
//Must be on the QueuedTask.Run()

//Linear location unit formats are not included if the map sr
//is geographic.
var loc_units = map.GetAvailableLocationUnitFormats();

使用当前地图位置单元设置位置格式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
var mv = MapView.Active;
var map = mv.Map;

QueuedTask.Run(() =>
{
//Get the current view camera location
var center_pt = new Coordinate2D(mv.Camera.X, mv.Camera.Y);
//Get the current location unit
var loc_unit = map.GetLocationUnitFormat();

//Format the camera location
var str = loc_unit.FormatLocation(center_pt, map.SpatialReference);
System.Diagnostics.Debug.WriteLine($"Formatted location: {str}");
});

设置当前地图的位置单位

1
2
3
4
5
6
7
8
9
10
11
12
var mv = MapView.Active;
var map = mv.Map;

QueuedTask.Run(() =>
{
//Get the list of available location unit formats
//for the current map
var loc_units = map.GetAvailableLocationUnitFormats();

//arbitrarily use the last unit in the list
map.SetLocationUnitFormat(loc_units.Last());
});

获取当前地图高程单位

1
2
3
4
5
6
7
8
//var map = MapView.Active.Map;
//Must be on the QueuedTask.Run()

//If the map is not a scene, the default Project distance
//unit will be returned
var elev_unit = map.GetElevationUnitFormat();
var line = $"{elev_unit.DisplayName}, {elev_unit.UnitCode}";
System.Diagnostics.Debug.WriteLine(line);

获取可用的地图高程单位列表

1
2
3
4
5
6
//var map = MapView.Active.Map;
//Must be on the QueuedTask.Run()

//If the map is not a scene, the list of current
//Project distance units will be returned
var elev_units = map.GetAvailableElevationUnitFormats();

使用当前地图高程单位设置高程格式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
var mv = MapView.Active;
var map = mv.Map;

QueuedTask.Run(() =>
{
//Get the current elevation unit. If the map is not
//a scene the default Project distance unit is returned
var elev_unit = map.GetElevationUnitFormat();

//Format the view camera elevation
var str = elev_unit.FormatValue(mv.Camera.Z);

System.Diagnostics.Debug.WriteLine($"Formatted elevation: {str}");
});

设置当前地图的高程单位

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
var map = MapView.Active.Map;

QueuedTask.Run(() =>
{
//Trying to set the elevation unit on a map other than
//a scene will throw an InvalidOperationException
if (map.IsScene)
{
//Get the list of available elevation unit formats
//for the current map
var loc_units = map.GetAvailableElevationUnitFormats();
//arbitrarily use the last unit in the list
map.SetElevationUnitFormat(loc_units.Last());
}

});

离线地图

检查地图是否具有启用同步的内容

1
2
3
4
5
6
7
8
9
10
11
12
//namespace ArcGIS.Desktop.Mapping.Offline
var map = MapView.Active.Map;

//await if needed...
QueuedTask.Run(() =>
{
var hasSyncEnabledContent = GenerateOfflineMap.Instance.GetCanGenerateReplicas(map);
if (hasSyncEnabledContent)
{
//TODO - use status...
}
});

为启用同步的内容生成副本

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
//namespace ArcGIS.Desktop.Mapping.Offline
var extent = MapView.Active.Extent;
var map = MapView.Active.Map;

//await if needed...
QueuedTask.Run(() =>
{
//Check map has sync-enabled content that can be taken offline
var hasSyncEnabledContent = GenerateOfflineMap.Instance.GetCanGenerateReplicas(map);
if (hasSyncEnabledContent)
{
//Generate Replicas and take the content offline
//sync-enabled content gets copied local into a SQLite DB
var gen_params = new GenerateReplicaParams()
{
Extent = extent, //SR of extent must match map SR

//DestinationFolder can be left blank, if specified,
//it must exist. Defaults to project offline maps location
DestinationFolder = @"C:\Data\Offline"
};
//Sync-enabled layer content will be resourced to point to the
//local replica content.
GenerateOfflineMap.Instance.GenerateReplicas(map, gen_params);

}
});

检查地图是否具有本地可同步内容

1
2
3
4
5
6
7
8
9
10
11
12
13
//namespace ArcGIS.Desktop.Mapping.Offline
var map = MapView.Active.Map;

//await if needed...
QueuedTask.Run(() =>
{
//Check map has local syncable content
var canSyncContent = GenerateOfflineMap.Instance.GetCanSynchronizeReplicas(map);
if (canSyncContent)
{
//TODO - use status
}
});

同步可同步内容的副本

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
//namespace ArcGIS.Desktop.Mapping.Offline
var map = MapView.Active.Map;

//await if needed...
QueuedTask.Run(() =>
{
//Check map has local syncable content
var canSyncContent = GenerateOfflineMap.Instance.GetCanSynchronizeReplicas(map);
if (canSyncContent)
{
//Sync Replicas - changes since last sync are pushed to the
//parent replica. Parent changes are pulled to the client.
//Unsaved edits are _not_ sync'd.
GenerateOfflineMap.Instance.SynchronizeReplicas(map);
}
});

删除可同步内容的副本

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
//namespace ArcGIS.Desktop.Mapping.Offline
var extent = MapView.Active.Extent;
var map = MapView.Active.Map;

//await if needed...
QueuedTask.Run(() =>
{
//Check map has local syncable content
//Either..
//var canSyncContent = GenerateOfflineMap.Instance.GetCanSynchronizeReplicas(map);
//Or...both accomplish the same thing...
var canRemove = GenerateOfflineMap.Instance.GetCanRemoveReplicas(map);
if (canRemove)
{
//Remove Replicas - any unsync'd changes are lost
//Call sync _first_ to push any outstanding changes if
//needed. Local syncable content is re-sourced
//to point to the service
GenerateOfflineMap.Instance.RemoveReplicas(map);
}
});

导出地图栅格切片缓存内容

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
//namespace ArcGIS.Desktop.Mapping.Offline
var extent = MapView.Active.Extent;
var map = MapView.Active.Map;

//await if needed...
QueuedTask.Run(() =>
{
//Does the map have any exportable raster content?
var canExport = GenerateOfflineMap.Instance.GetCanExportRasterTileCache(map);
if (canExport)
{
//Check the available LOD scale ranges
var scales = GenerateOfflineMap.Instance.GetExportRasterTileCacheScales(map, extent);
//Pick the desired LOD scale
var max_scale = scales[scales.Count() / 2];

//Configure the export parameters
var export_params = new ExportTileCacheParams()
{
Extent = extent,//Use same extent as was used to retrieve scales
MaximumUserDefinedScale = max_scale
//DestinationFolder = .... (optional)
};
//If DestinationFolder is not set, output defaults to project
//offline maps location set in the project properties. If that is
//not set, output defaults to the current project folder location.

//Do the export. Depending on the MaximumUserDefinedScale and the
//area of the extent requested, this can take minutes for tile packages
//over 1 GB or less if your network speed is slow...
GenerateOfflineMap.Instance.ExportRasterTileCache(map, export_params);
}
});

导出地图矢量切片缓存内容

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
//namespace ArcGIS.Desktop.Mapping.Offline
var extent = MapView.Active.Extent;
var map = MapView.Active.Map;

//await if needed...
QueuedTask.Run(() =>
{
//Does the map have any exportable vector tile content?
var canExport = GenerateOfflineMap.Instance.GetCanExportVectorTileCache(map);
if (canExport)
{
//Check the available LOD scale ranges
var scales = GenerateOfflineMap.Instance.GetExportVectorTileCacheScales(map, extent);
//Pick the desired LOD scale
var max_scale = scales[scales.Count() / 2];

//Configure the export parameters
var export_params = new ExportTileCacheParams()
{
Extent = extent,//Use same extent as was used to retrieve scales
MaximumUserDefinedScale = max_scale,
DestinationFolder = @"C:\Data\Offline"
};
//If DestinationFolder is not set, output defaults to project
//offline maps location set in the project properties. If that is
//not set, output defaults to the current project folder location.

//Do the export. Depending on the MaximumUserDefinedScale and the
//area of the extent requested, this can take minutes for tile packages
//over 1 GB or less if your network speed is slow...
GenerateOfflineMap.Instance.ExportVectorTileCache(map, export_params);
}
});

创建图层

创建图层并将其添加到活动地图

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
/*
* string url = @"c:\data\project.gdb\DEM"; //Raster dataset from a FileGeodatabase
* string url = @"c:\connections\mySDEConnection.sde\roads"; //FeatureClass of a SDE
* string url = @"c:\connections\mySDEConnection.sde\States\roads"; //FeatureClass within a FeatureDataset from a SDE
* string url = @"c:\data\roads.shp"; //Shapefile
* string url = @"c:\data\imagery.tif"; //Image from a folder
* string url = @"c:\data\mySDEConnection.sde\roads"; //.lyrx or .lpkx file
* string url = @"c:\data\CAD\Charlottesville\N1W1.dwg\Polyline"; //FeatureClass in a CAD dwg file
* string url = @"C:\data\CAD\UrbanHouse.rvt\Architectural\Windows"; //Features in a Revit file
* string url = @"http://sampleserver1.arcgisonline.com/ArcGIS/rest/services/Demographics/ESRI_Census_USA/MapServer"; //map service
* string url = @"http://sampleserver6.arcgisonline.com/arcgis/rest/services/NapervilleShelters/FeatureServer/0"; //FeatureLayer off a map service or feature service
*/
string url = @"c:\data\project.gdb\roads"; //FeatureClass of a FileGeodatabase

Uri uri = new Uri(url);
await QueuedTask.Run(() => LayerFactory.Instance.CreateLayer(uri, MapView.Active.Map));

使用创建参数创建图层

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
var flyrCreatnParam = new FeatureLayerCreationParams(new Uri(@"c:\data\world.gdb\cities"))
{
Name = "World Cities",
IsVisible = false,
MinimumScale = 1000000,
MaximumScale = 5000,
// At 2.x - DefinitionFilter = new CIMDefinitionFilter()
//{
// DefinitionExpression = "Population > 100000",
// Name = "More than 100k"
//},
DefinitionQuery = new DefinitionQuery(whereClause: "Population > 100000", name: "More than 100k"),
RendererDefinition = new SimpleRendererDefinition()
{
SymbolTemplate = SymbolFactory.Instance.ConstructPointSymbol(
CIMColor.CreateRGBColor(255, 0, 0), 8, SimpleMarkerStyle.Hexagon).MakeSymbolReference()
}
};

var featureLayer = LayerFactory.Instance.CreateLayer<FeatureLayer>(
flyrCreatnParam, map);

创建要素图层并使用图层创建参数添加到地图

1
2
3
4
//Note: Call within QueuedTask.Run()
var layerDoc = new LayerDocument(@"E:\Data\SDK\Default2DPointSymbols.lyrx");
var createParams = new LayerCreationParams(layerDoc.GetCIMLayerDocument());
LayerFactory.Instance.CreateLayer<FeatureLayer>(createParams, MapView.Active.Map);

创建要素图层并设置为不显示在地图中。

1
2
3
4
5
6
7
8
9
10
//The catalog path of the feature layer to add to the map
var featureClassUriVisibility = new Uri(@"C:\Data\Admin\AdminData.gdb\USA\cities");
//Define the Feature Layer's parameters.
var layerParamsVisibility = new FeatureLayerCreationParams(featureClassUriVisibility)
{
//Set visibility
IsVisible = false,
};
//Create the layer with the feature layer parameters and add it to the active map
var createdFC = LayerFactory.Instance.CreateLayer<FeatureLayer>(layerParamsVisibility, MapView.Active.Map);

使用渲染器创建要素图层

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
//Note: Call within QueuedTask.Run()
//Define a simple renderer to draw the Point US Cities feature class.
var simpleRender = new SimpleRendererDefinition
{
SymbolTemplate = SymbolFactory.Instance.ConstructPointSymbol(ColorFactory.Instance.RedRGB, 4.0, SimpleMarkerStyle.Circle).MakeSymbolReference()

};
//The catalog path of the feature layer to add to the map
var featureClassUri = new Uri(@"C:\Data\Admin\AdminData.gdb\USA\cities");
//Define the Feature Layer's parameters.
var layerParams = new FeatureLayerCreationParams(featureClassUri)
{
//Set visibility
IsVisible = true,
//Set Renderer
RendererDefinition = simpleRender,
};
//Create the layer with the feature layer parameters and add it to the active map
var createdFCWithRenderer = LayerFactory.Instance.CreateLayer<FeatureLayer>(layerParams, MapView.Active.Map);

使用查询定义创建要素图层

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
//The catalog path of the feature layer to add to the map
var featureClassUriDefinition = new Uri(@"C:\Data\Admin\AdminData.gdb\USA\cities");
//Define the Feature Layer's parameters.
//At 2.x - var layerParamsQueryDefn = new FeatureLayerCreationParams(featureClassUriDefinition)
//{
// IsVisible = true,
// DefinitionFilter = new CIMDefinitionFilter()
// {
// Name = "CACities",
// DefinitionExpression = "STATE_NAME = 'California'"
// }
//};
var layerParamsQueryDefn = new FeatureLayerCreationParams(featureClassUriDefinition)
{
IsVisible = true,
DefinitionQuery = new DefinitionQuery(whereClause: "STATE_NAME = 'California'", name: "CACities")
};

//Create the layer with the feature layer parameters and add it to the active map
var createdFCWithQueryDefn = LayerFactory.Instance.CreateLayer<FeatureLayer>(layerParamsQueryDefn, MapView.Active.Map);

将地图注释添加到活动地图

1
2
3
4
5
6
7
8
9
10
11
12
13
14
//Gets the collection of layer template packages installed with Pro for use with maps
var items = MapView.Active.Map.LayerTemplatePackages;
//Iterate through the collection of items to add each Map Note to the active map
foreach (var item in items)
{
//Create a parameter item for the map note
var layer_params = new LayerCreationParams(item);
layer_params.IsVisible = false;
await QueuedTask.Run(() =>
{
//Create a feature layer for the map note
var layer = LayerFactory.Instance.CreateLayer<Layer>(layer_params, MapView.Active.Map);
});
}

应用目录中图层的符号系统

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
//Note: Call within QueuedTask.Run()
if (MapView.Active.Map == null) return;

//Get an existing Layer. This layer has a symbol you want to use in a new layer.
var lyr = MapView.Active.Map.GetLayersAsFlattenedList().OfType<FeatureLayer>()
.Where(l => l.ShapeType == esriGeometryType.esriGeometryPoint).FirstOrDefault();
//This is the renderer to use in the new Layer
var renderer = lyr.GetRenderer() as CIMSimpleRenderer;
//Set the Dataconnection for the new layer
Geodatabase geodatabase = new Geodatabase(
new FileGeodatabaseConnectionPath(new Uri(@"E:\Data\Admin\AdminData.gdb")));
FeatureClass featureClass = geodatabase.OpenDataset<FeatureClass>("Cities");
var dataConnection = featureClass.GetDataConnection();
//Create the definition for the new feature layer
var featureLayerParams = new FeatureLayerCreationParams(dataConnection)
{
RendererDefinition = new SimpleRendererDefinition(renderer.Symbol),
IsVisible = true,
};
//create the new layer
LayerFactory.Instance.CreateLayer<FeatureLayer>(
featureLayerParams, MapView.Active.Map);

创建新的子类型图层组

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
var subtypeGroupLayerCreateParam = new SubtypeGroupLayerCreationParams
(
new Uri(@"c:\data\SubtypeAndDomain.gdb\Fittings")
);

// Define Subtype layers
//At 2.x - var rendererDefn1 = new UniqueValueRendererDefinition(new string[] { "type" });
var rendererDefn1 = new UniqueValueRendererDefinition(new List<string> { "type" });
var renderDefn2 = new SimpleRendererDefinition()
{
SymbolTemplate = SymbolFactory.Instance.ConstructPointSymbol(
CIMColor.CreateRGBColor(255, 0, 0), 8, SimpleMarkerStyle.Hexagon).MakeSymbolReference()
};
subtypeGroupLayerCreateParam.SubtypeLayers = new List<SubtypeFeatureLayerCreationParams>()
{
//define first subtype layer with unique value renderer
//At 2.x - new SubtypeFeatureLayerCreationParams(new UniqueValueRendererDefinition(new string[] { "type" }), 1),
new SubtypeFeatureLayerCreationParams(new UniqueValueRendererDefinition(new List<string> { "type" }), 1),

//define second subtype layer with simple symbol renderer
new SubtypeFeatureLayerCreationParams(renderDefn2, 2)
};

// Define additional parameters
//At - 2.x subtypeGroupLayerCreateParam.DefinitionFilter = new CIMDefinitionFilter()
//{
// Name = "IsActive",
// DefinitionExpression = "Enabled = 1"
//};
subtypeGroupLayerCreateParam.DefinitionQuery = new DefinitionQuery(whereClause: "Enabled = 1", name: "IsActive");
subtypeGroupLayerCreateParam.IsVisible = true;
subtypeGroupLayerCreateParam.MinimumScale = 50000;

SubtypeGroupLayer subtypeGroupLayer2 = LayerFactory.Instance.CreateLayer<SubtypeGroupLayer>(
subtypeGroupLayerCreateParam, MapView.Active.Map);

从 lyrx 文件创建图层

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
var lyrDocFromLyrxFile = new LayerDocument(@"d:\data\cities.lyrx");
var cimLyrDoc = lyrDocFromLyrxFile.GetCIMLayerDocument();

//modifying its renderer symbol to red
var r = ((CIMFeatureLayer)cimLyrDoc.LayerDefinitions[0]).Renderer as CIMSimpleRenderer;
r.Symbol.Symbol.SetColor(new CIMRGBColor() { R = 255 });

//optionally save the updates out as a file
lyrDocFromLyrxFile.Save(@"c:\data\cities_red.lyrx");

//get a json representation of the layer document and you want store away...
var aJSONString = lyrDocFromLyrxFile.AsJson();

//... and load it back when needed
lyrDocFromLyrxFile.Load(aJSONString);
cimLyrDoc = lyrDocFromLyrxFile.GetCIMLayerDocument();

//create a layer and add it to a map
var lcp = new LayerCreationParams(cimLyrDoc);
var lyr = LayerFactory.Instance.CreateLayer<FeatureLayer>(lcp, map);

将符号系统应用于图层文件中的图层

1
2
3
4
5
6
7
8
9
10
11
//Note: Run within QueuedTask.Run
//Get the Layer Document from the lyrx file
var lyrDocFromLyrxFile = new LayerDocument(layerFile);
var cimLyrDoc = lyrDocFromLyrxFile.GetCIMLayerDocument();

//Get the renderer from the layer file
var rendererFromLayerFile = ((CIMFeatureLayer)cimLyrDoc.LayerDefinitions[0]).Renderer as CIMUniqueValueRenderer;

//Apply the renderer to the feature layer
//Note: If working with a raster layer, use the SetColorizer method.
featureLayer?.SetRenderer(rendererFromLayerFile);

添加 WMS 服务

1
2
3
4
5
6
7
8
9
10
// Create a connection to the WMS server
var serverConnection = new CIMInternetServerConnection { URL = "URL of the WMS service" };
var connection = new CIMWMSServiceConnection { ServerConnection = serverConnection };

// Add a new layer to the map
var layerParams = new LayerCreationParams(connection);
await QueuedTask.Run(() =>
{
var layer = LayerFactory.Instance.CreateLayer<FeatureLayer>(layerParams, MapView.Active.Map);
});

添加 WFS 服务

1
2
3
4
5
6
7
8
9
10
11
12
13
14
CIMStandardDataConnection cIMStandardDataConnection = new CIMStandardDataConnection()
{
WorkspaceConnectionString = @"SWAPXY=TRUE;SWAPXYFILTER=FALSE;URL=http://sampleserver6.arcgisonline.com/arcgis/services/SampleWorldCities/MapServer/WFSServer;VERSION=2.0.0",
WorkspaceFactory = WorkspaceFactory.WFS,
Dataset = "Continent",
DatasetType = esriDatasetType.esriDTFeatureClass
};

// Add a new layer to the map
var layerPamsDC = new LayerCreationParams(cIMStandardDataConnection);
await QueuedTask.Run(() =>
{
Layer layer = LayerFactory.Instance.CreateLayer<FeatureLayer>(layerPamsDC, MapView.Active.Map);
});

添加和更改 WMS 服务图层的样式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
var serverConnection = new CIMInternetServerConnection { URL = "https://spritle.esri.com/arcgis/services/sanfrancisco_sld/MapServer/WMSServer" };
var connection = new CIMWMSServiceConnection { ServerConnection = serverConnection };
LayerCreationParams parameters = new LayerCreationParams(connection);
parameters.MapMemberPosition = MapMemberPosition.AddToBottom;
await QueuedTask.Run(() =>
{
var compositeLyr = LayerFactory.Instance.CreateLayer<WMSLayer>(parameters, MapView.Active.Map);
//wms layer in ArcGIS Pro always has a composite layer inside it
var wmsLayers = compositeLyr.Layers[0] as ServiceCompositeSubLayer;
//each wms sublayer belongs in that composite layer
var highwayLayerWMSSub = wmsLayers.Layers[1] as WMSSubLayer;
//toggling a sublayer's visibility
if ((highwayLayerWMSSub != null))
{
bool visibility = highwayLayerWMSSub.IsVisible;
highwayLayerWMSSub.SetVisibility(!visibility);
}
//applying an existing style to a wms sub layer
var pizzaLayerWMSSub = wmsLayers.Layers[0] as WMSSubLayer;
var currentStyles = pizzaLayerWMSSub.GetStyleNames();
pizzaLayerWMSSub.SetStyleName(currentStyles[1]);
});

创建查询图层

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
await QueuedTask.Run(() =>
{
Map map = MapView.Active.Map;
Geodatabase geodatabase = new Geodatabase(new DatabaseConnectionFile(new Uri(@"C:\Connections\mySDE.sde")));
CIMSqlQueryDataConnection sqldc = new CIMSqlQueryDataConnection()
{
WorkspaceConnectionString = geodatabase.GetConnectionString(),
GeometryType = esriGeometryType.esriGeometryPolygon,
OIDFields = "OBJECTID",
Srid = "102008",
SqlQuery = "select * from MySDE.dbo.STATES",
Dataset = "States"
};
var lcp = new LayerCreationParams(sqldc)
{
Name = "States"
};
FeatureLayer flyr = LayerFactory.Instance.CreateLayer<FeatureLayer>(lcp, map);
});

使用默认值分类间隔渲染器创建要素图层

1
2
3
4
5
6
7
8
9
10
11
12
await QueuedTask.Run(() =>
{
var featureLayerCreationParams = new FeatureLayerCreationParams(new Uri(@"c:\data\countydata.gdb\counties"))
{
Name = "Population Density (sq mi) Year 2010",
RendererDefinition = new GraduatedColorsRendererDefinition("POP10_SQMI")
};
LayerFactory.Instance.CreateLayer<FeatureLayer>(
featureLayerCreationParams,
MapView.Active.Map
);
});

使用分类间隔渲染器创建要素图层

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
string colorBrewerSchemesName = "ColorBrewer Schemes (RGB)";
StyleProjectItem style = Project.Current.GetItems<StyleProjectItem>().First(s => s.Name == colorBrewerSchemesName);
string colorRampName = "Greens (Continuous)";
IList<ColorRampStyleItem> colorRampList = await QueuedTask.Run(() =>
{
return style.SearchColorRamps(colorRampName);
});
ColorRampStyleItem colorRamp = colorRampList[0];

await QueuedTask.Run(() =>
{
GraduatedColorsRendererDefinition gcDef = new GraduatedColorsRendererDefinition()
{
ClassificationField = "CROP_ACR07",
ClassificationMethod = ArcGIS.Core.CIM.ClassificationMethod.NaturalBreaks,
BreakCount = 6,
ColorRamp = colorRamp.ColorRamp,
SymbolTemplate = SymbolFactory.Instance.ConstructPolygonSymbol(
ColorFactory.Instance.GreenRGB, SimpleFillStyle.Solid, null).MakeSymbolReference(),
ExclusionClause = "CROP_ACR07 = -99",
ExclusionSymbol = SymbolFactory.Instance.ConstructPolygonSymbol(
ColorFactory.Instance.RedRGB, SimpleFillStyle.Solid, null).MakeSymbolReference(),
ExclusionLabel = "No yield",
};
var featureLayerCreationParams = new FeatureLayerCreationParams((new Uri(@"c:\Data\CountyData.gdb\Counties")))
{
Name = "Crop",
RendererDefinition = gcDef
};
LayerFactory.Instance.CreateLayer<FeatureLayer>(featureLayerCreationParams, MapView.Active.Map);
});

底图图层

更新地图的底图图层

1
aMap.SetBasemapLayers(Basemap.Gray);

从地图中移除底图图层

1
aMap.SetBasemapLayers(Basemap.None);

使用图层

从地图中获取按图层类型过滤的图层列表

1
List<FeatureLayer> featureLayerList = aMap.GetLayersAsFlattenedList().OfType<FeatureLayer>().ToList();

获取特定几何类型的图层

1
2
3
//Get an existing Layer. This layer has a symbol you want to use in a new layer.
var lyr = MapView.Active.Map.GetLayersAsFlattenedList().OfType<FeatureLayer>()
.Where(l => l.ShapeType == esriGeometryType.esriGeometryPoint).FirstOrDefault();

查找图层

1
2
3
4
5
6
7
8
9
10
//Finds layers by name and returns a read only list of Layers
IReadOnlyList<Layer> layers = aMap.FindLayers("cities", true);

//Finds a layer using a URI.
//The Layer URI you pass in helps you search for a specific layer in a map
var lyrFindLayer = MapView.Active.Map.FindLayer("CIMPATH=map/u_s__states__generalized_.xml");

//This returns a collection of layers of the "name" specified. You can use any Linq expression to query the collection.
var lyrExists = MapView.Active.Map.GetLayersAsFlattenedList()
.OfType<FeatureLayer>().Any(f => f.Name == "U.S. States (Generalized)");

查找独立表

1
2
3
4
5
6
7
// these routines find a standalone table whether it is a child of the Map or a GroupLayer
var tblFind = aMap.FindStandaloneTable("CIMPATH=map/address_audit.xml");

IReadOnlyList<StandaloneTable> tables = aMap.FindStandaloneTables("addresses");

// this method finds a standalone table as a child of the map only
var table = aMap.StandaloneTables.FirstOrDefault(t => t.Name == "Addresses");

使用部分名称搜索查找图层

1
2
Map map = MapView.Active.Map;
IEnumerable<Layer> matches = map.GetLayersAsFlattenedList().Where(l => l.Name.IndexOf(partialName, StringComparison.CurrentCultureIgnoreCase) >= 0);

更改图层可见性、可编辑性、捕捉性

1
2
3
4
5
6
7
8
9
10
11
if (!layer.IsVisible)
layer.SetVisibility(true);

if (layer is FeatureLayer featureLayer)
{
if (!featureLayer.IsEditable)
featureLayer.SetEditable(true);

if (!featureLayer.IsSnappable)
featureLayer.SetSnappable(true);
}

创建 Lyrx 文件

1
2
LayerDocument layerDocument = new LayerDocument(layer);
layerDocument.Save(@"c:\Data\MyLayerDocument.lyrx");

计算图层上所选要素的数量

1
2
var lyr = MapView.Active.Map.GetLayersAsFlattenedList().OfType<FeatureLayer>().FirstOrDefault();
var noFeaturesSelected = lyr.SelectionCount;

访问图层的显示字段

1
2
3
4
5
6
7
8
9
10
var featureLayer = MapView.Active.Map.GetLayersAsFlattenedList().OfType<FeatureLayer>().FirstOrDefault();
ArcGIS.Desktop.Framework.Threading.Tasks.QueuedTask.Run(() =>
{
// get the CIM definition from the layer
var cimFeatureDefinition = featureLayer.GetDefinition() as ArcGIS.Core.CIM.CIMBasicFeatureLayer;
// get the view of the source table underlying the layer
var cimDisplayTable = cimFeatureDefinition.FeatureTable;
// this field is used as the 'label' to represent the row
var displayField = cimDisplayTable.DisplayField;
});

在图层上启用标注

1
2
3
4
5
6
var featureLayer = MapView.Active.Map.GetLayersAsFlattenedList().OfType<FeatureLayer>().FirstOrDefault();
ArcGIS.Desktop.Framework.Threading.Tasks.QueuedTask.Run(() =>
{
// toggle the label visibility
featureLayer.SetLabelVisibility(!featureLayer.IsLabelVisible);
});

将 2D 组中的图层移动到局部场景中的 3D 组

1
2
3
4
5
6
7
8
9
10
11
//The layer in the 2D group to move to the 3D Group in a Local Scene
var layer = MapView.Active.Map.GetLayersAsFlattenedList().OfType<FeatureLayer>().FirstOrDefault();
QueuedTask.Run(() =>
{
//Get the layer's definition
var lyrDefn = layer.GetDefinition() as CIMBasicFeatureLayer;
//setting this property moves the layer to 3D group in a scene
lyrDefn.IsFlattened = false;
//Set the definition back to the layer
layer.SetDefinition(lyrDefn);
});

重置要素服务图层的 URL

1
2
3
CIMStandardDataConnection dataConnection = dataConnectionLayer.GetDataConnection() as CIMStandardDataConnection;
dataConnection.WorkspaceConnectionString = newConnectionString;
dataConnectionLayer.SetDataConnection(dataConnection);

更改要素图层的基础数据源 - 相同的工作空间类型

1
2
3
4
5
6
7
8
9
10
11
12
//This is the existing layer for which we want to switch the underlying datasource
var lyr = MapView.Active.Map.GetLayersAsFlattenedList().OfType<FeatureLayer>().FirstOrDefault();
QueuedTask.Run(() =>
{
var connectionStringToReplace = lyr.GetFeatureClass().GetDatastore().GetConnectionString();
string databaseConnectionPath = @"Path to the .sde connection file to replace with";
//If the new SDE connection did not have a dataset with the same name as in the feature layer,
//pass false for the validate parameter of the FindAndReplaceWorkspacePath method to achieve this.
//If validate is true and the SDE did not have a dataset with the same name,
//FindAndReplaceWorkspacePath will return failure
lyr.FindAndReplaceWorkspacePath(connectionStringToReplace, databaseConnectionPath, true);
});

将图层的地理数据库版本更改为地图中的指定版本

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
await QueuedTask.Run(() =>
{
//Getting the current version name from the first feature layer of the map
FeatureLayer flyr = MapView.Active.Map.GetLayersAsFlattenedList()
.OfType<FeatureLayer>().FirstOrDefault(); //first feature layer
Datastore dataStore = flyr.GetFeatureClass().GetDatastore(); //getting datasource
Geodatabase geodatabase = dataStore as Geodatabase; //casting to Geodatabase
if (geodatabase == null)
return;

VersionManager versionManager = geodatabase.GetVersionManager();
ArcGIS.Core.Data.Version currentVersion = versionManager.GetCurrentVersion();

//Getting all available versions except the current one
IEnumerable<ArcGIS.Core.Data.Version> versions = versionManager.GetVersions()
.Where(v => !v.GetName().Equals(currentVersion.GetName(), StringComparison.CurrentCultureIgnoreCase));

//Assuming there is at least one other version we pick the first one from the list
ArcGIS.Core.Data.Version toVersion = versions.FirstOrDefault();
if (toVersion != null)
{
//Changing version
MapView.Active.Map.ChangeVersion(currentVersion, toVersion);
}
});

查询要素图层

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
var count = await QueuedTask.Run(() =>
{
QueryFilter qf = new QueryFilter()
{
WhereClause = "Class = 'city'"
};

//Getting the first selected feature layer of the map view
var flyr = (FeatureLayer)MapView.Active.GetSelectedLayers()
.OfType<FeatureLayer>().FirstOrDefault();
using (RowCursor rows = flyr.Search(qf)) //execute
{
//Looping through to count
int i = 0;
while (rows.MoveNext()) i++;

return i;
}
});
MessageBox.Show(String.Format(
"Total features that matched the search criteria: {0}", count));

获取图层的属性旋转字段

1
2
3
4
5
6
7
8
var featureLayer = MapView.Active.Map.GetLayersAsFlattenedList().OfType<FeatureLayer>().FirstOrDefault();
QueuedTask.Run(() =>
{
var cimRenderer = featureLayer.GetRenderer() as CIMUniqueValueRenderer;
var cimRotationVariable = cimRenderer.VisualVariables.OfType<CIMRotationVisualVariable>().FirstOrDefault();
var rotationInfoZ = cimRotationVariable.VisualVariableInfoZ;
var rotationExpression = rotationInfoZ.ValueExpressionInfo.Expression; // this expression stores the field name
});

查找要旋转的连接属性字段

1
2
3
4
5
6
7
8
9
10
11
var featureLayer = MapView.Active.Map.GetLayersAsFlattenedList().OfType<FeatureLayer>().FirstOrDefault();
ArcGIS.Desktop.Framework.Threading.Tasks.QueuedTask.Run(() =>
{
// get the CIM renderer from the layer
var cimRenderer = featureLayer.GetRenderer() as ArcGIS.Core.CIM.CIMSimpleRenderer;
// get the collection of connected attributes for rotation
var cimRotationVariable = cimRenderer.VisualVariables.OfType<ArcGIS.Core.CIM.CIMRotationVisualVariable>().FirstOrDefault();
// the z direction is describing the heading rotation
var rotationInfoZ = cimRotationVariable.VisualVariableInfoZ;
var rotationExpression = rotationInfoZ.Expression; // this expression stores the field name
});

切换“设置参考比例时缩放图层符号”

1
2
3
4
5
6
7
8
var featureLayer = MapView.Active.Map.GetLayersAsFlattenedList().OfType<FeatureLayer>().FirstOrDefault();
ArcGIS.Desktop.Framework.Threading.Tasks.QueuedTask.Run(() =>
{
// get the CIM layer definition
var cimFeatureLayer = featureLayer.GetDefinition() as ArcGIS.Core.CIM.CIMFeatureLayer;
// turn on the option to scale the symbols in this layer based in the map's reference scale
cimFeatureLayer.ScaleSymbols = true;
});

设置图层缓存

1
2
3
4
5
6
7
8
9
var featureLayer = MapView.Active.Map.GetLayersAsFlattenedList().OfType<FeatureLayer>().FirstOrDefault();
ArcGIS.Desktop.Framework.Threading.Tasks.QueuedTask.Run(() =>
{
// change the layer cache type to maximum age
//At 2.x - featureLayer.SetDisplayCacheType(ArcGIS.Core.CIM.DisplayCacheType.MaxAge);
featureLayer.SetCacheOptions(LayerCacheType.MaxAge);
// change from the default 5 min to 2 min
featureLayer.SetDisplayCacheMaxAge(TimeSpan.FromMinutes(2));
});

更改图层选择颜色

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
var featureLayer = MapView.Active.Map.GetLayersAsFlattenedList().OfType<FeatureLayer>().FirstOrDefault();
ArcGIS.Desktop.Framework.Threading.Tasks.QueuedTask.Run(() =>
{
// get the CIM definition of the layer
var layerDef = featureLayer.GetDefinition() as ArcGIS.Core.CIM.CIMBasicFeatureLayer;
// disable the default symbol
layerDef.UseSelectionSymbol = false;
// assign a new color
layerDef.SelectionColor = ColorFactory.Instance.RedRGB;
// apply the definition to the layer
featureLayer.SetDefinition(layerDef);

if (!featureLayer.IsVisible)
featureLayer.SetVisibility(true);
//Do a selection

MapView.Active.SelectFeatures(MapView.Active.Extent);
});

删除所有未选中的图层

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
var map = MapView.Active.Map;
if (map == null)
return;
//Get the group layers first
IReadOnlyList<GroupLayer> groupLayers = map.Layers.OfType<GroupLayer>().ToList();
//Iterate and remove the layers within the group layers that are unchecked.
foreach (var groupLayer in groupLayers)
{
//Get layers that not visible within the group
var layers = groupLayer.Layers.Where(l => l.IsVisible == false).ToList();
//Remove all the layers that are not visible within the group
await QueuedTask.Run(() => map.RemoveLayers(layers));
}

//Group Layers that are empty and are unchecked
foreach (var group in groupLayers)
{
if (group.Layers.Count == 0 && group.IsVisible == false) //No layers in the group
{
//remove the group
await QueuedTask.Run(() => map.RemoveLayer(group));
}
}

//Get Layers that are NOT Group layers and are unchecked
var notAGroupAndUnCheckedLayers = map.Layers.Where(l => !(l is GroupLayer) && l.IsVisible == false).ToList();
//Remove all the non group layers that are not visible
await QueuedTask.Run(() => map.RemoveLayers(notAGroupAndUnCheckedLayers));

删除空组

1
2
3
4
5
6
7
8
9
10
11
12
13
var map = MapView.Active.Map;
if (map == null)
return;
//Get the group layers
IReadOnlyList<GroupLayer> groupLayers = map.Layers.OfType<GroupLayer>().ToList();
foreach (var group in groupLayers)
{
if (group.Layers.Count == 0) //No layers in the group
{
//remove the group
await QueuedTask.Run(() => map.RemoveLayer(group));
}
}

在地图定义中创建缩写字典并将其应用于图层

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
public static void CreateDictionary()
{
//Get the map's defintion
var mapDefn = MapView.Active.Map.GetDefinition();
//Get the Map's Maplex labelling engine properties
var mapDefnPlacementProps = mapDefn.GeneralPlacementProperties as CIMMaplexGeneralPlacementProperties;

//Define the abbreaviations we need in an array
List<CIMMaplexDictionaryEntry> abbreviationDictionary = new List<CIMMaplexDictionaryEntry>
{
new CIMMaplexDictionaryEntry {
Abbreviation = "Hts",
Text = "Heights",
MaplexAbbreviationType = MaplexAbbreviationType.Ending

},
new CIMMaplexDictionaryEntry
{
Abbreviation = "Ct",
Text = "Text",
MaplexAbbreviationType = MaplexAbbreviationType.Ending

}
//etc
};
//The Maplex Dictionary - can hold multiple Abbreviation collections
var maplexDictionary = new List<CIMMaplexDictionary>
{
new CIMMaplexDictionary {
Name = "NameEndingsAbbreviations",
MaplexDictionary = abbreviationDictionary.ToArray()
}

};
//Set the Maplex Label Engine Dictionary property to the Maplex Dictionary collection created above.
mapDefnPlacementProps.Dictionaries = maplexDictionary.ToArray();
//Set the Map defintion
MapView.Active.Map.SetDefinition(mapDefn);
}

private static void ApplyDictionary()
{
var featureLayer = MapView.Active.Map.GetLayersAsFlattenedList().OfType<FeatureLayer>().First();

QueuedTask.Run(() =>
{
//Creates Abbreviation dictionary and adds to Map Defintion
CreateDictionary();
//Get the layer's definition
var lyrDefn = featureLayer.GetDefinition() as CIMFeatureLayer;
//Get the label classes - we need the first one
var listLabelClasses = lyrDefn.LabelClasses.ToList();
var theLabelClass = listLabelClasses.FirstOrDefault();
//Modify label Placement props to use abbreviation dictionary
CIMGeneralPlacementProperties labelEngine = MapView.Active.Map.GetDefinition().GeneralPlacementProperties;
theLabelClass.MaplexLabelPlacementProperties.DictionaryName = "NameEndingsAbbreviations";
theLabelClass.MaplexLabelPlacementProperties.CanAbbreviateLabel = true;
theLabelClass.MaplexLabelPlacementProperties.CanStackLabel = false;
//Set the labelClasses back
lyrDefn.LabelClasses = listLabelClasses.ToArray();
//set the layer's definition
featureLayer.SetDefinition(lyrDefn);
});
}

属性表 - ITablePane

设置属性表的缩放级别

1
2
3
4
5
6
7
if (FrameworkApplication.Panes.ActivePane is ITablePane tablePane)
{
var currentZoomLevel = tablePane.ZoomLevel;

var newZoomLevel = currentZoomLevel + 50;
tablePane.SetZoomLevel(newZoomLevel);
}

检索属性表中所选像元的值

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
if (FrameworkApplication.Panes.ActivePane is ITablePane tablePane)
{
var mapMember = tablePane.MapMember;
var oid = tablePane.ActiveObjectID;
if (oid.HasValue && oid.Value != -1 && mapMember != null)
{
var activeField = tablePane.ActiveColumn;
return QueuedTask.Run<object>(() =>
{
// TODO: Use core objects to retrieve record and get value

return null;
});
}
}

移动到特定行

1
2
3
4
5
6
7
8
9
if (FrameworkApplication.Panes.ActivePane is ITablePane tablePane)
{
// move to first row
tablePane.BringIntoView(0);

// move to sixth row
tablePane.BringIntoView(5);
}
}

元数据

获取和设置地图元数据

1
2
3
4
5
6
7
8
9
var map = MapView.Active.Map;
if (map == null) return;
//Get map's metadata
var mapMetadata = map.GetMetadata();
//TODO:Make edits to metadata using the retrieved mapMetadata string.

//Set the modified metadata back to the map.
if (map.GetCanEditMetadata())
map.SetMetadata(mapMetadata);

图层元数据

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
MapMember mapMember = map.GetLayersAsFlattenedList().FirstOrDefault(); //Search for only layers/tables here if needed.
if (mapMember == null) return;

//Gets whether or not the MapMember stores its own metadata or uses metadata retrieved
//from its source. This method must be called on the MCT. Use QueuedTask.Run
bool doesUseSourceMetadata = mapMember.GetUseSourceMetadata();

//Sets whether or not the MapMember will use its own metadata or the metadata from
//its underyling source (if it has one). This method must be called on the MCT.
//Use QueuedTask.Run
mapMember.SetUseSourceMetadata(true);

//Does the MapMember supports metadata
var supportsMetadata = mapMember.SupportsMetadata;

//Get MapMember metadata
var metadatstring = mapMember.GetMetadata();
//TODO:Make edits to metadata using the retrieved mapMetadata string.

//Set the modified metadata back to the mapmember (layer, table..)
if (mapMember.GetCanEditMetadata())
mapMember.SetMetadata(metadatstring);

渲染器

将唯一值渲染器设置为活动地图的所选要素图层

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
await QueuedTask.Run(() =>
{
var fields = new List<string> { "Type" }; //field to be used to retrieve unique values
CIMPointSymbol pointSym = SymbolFactory.Instance.ConstructPointSymbol(
ColorFactory.Instance.GreenRGB, 16.0, SimpleMarkerStyle.Pushpin); //constructing a point symbol as a template symbol
CIMSymbolReference symbolPointTemplate = pointSym.MakeSymbolReference();

//constructing renderer definition for unique value renderer
UniqueValueRendererDefinition uniqueValueRendererDef =
new UniqueValueRendererDefinition(fields, symbolPointTemplate);

//creating a unique value renderer
var flyr = MapView.Active.GetSelectedLayers()[0] as FeatureLayer;
CIMUniqueValueRenderer uniqueValueRenderer = flyr.CreateRenderer(uniqueValueRendererDef) as CIMUniqueValueRenderer;

//setting the renderer to the feature layer
flyr.SetRenderer(uniqueValueRenderer);
});

创建一个唯一值呈现器以指定值的符号

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
return QueuedTask.Run(() =>
{
//The goal is to construct the CIMUniqueValueRenderer which will be applied to the feature layer.
// To do this, the following are the objects we need to set the renderer up with the fields and symbols.
// As a reference, this is the USCities dataset. Snippet will create a unique value renderer that applies
// specific symbols to all the cities in California and Alabama. The rest of the cities will use a default symbol.

// First create a "CIMUniqueValueClass" for the cities in Alabama.
List<CIMUniqueValue> listUniqueValuesAlabama = new List<CIMUniqueValue> { new CIMUniqueValue { FieldValues = new string[] { "Alabama" } } };
CIMUniqueValueClass alabamaUniqueValueClass = new CIMUniqueValueClass
{
Editable = true,
Label = "Alabama",
Patch = PatchShape.Default,
Symbol = SymbolFactory.Instance.ConstructPointSymbol(ColorFactory.Instance.RedRGB).MakeSymbolReference(),
Visible = true,
Values = listUniqueValuesAlabama.ToArray()

};
// Create a "CIMUniqueValueClass" for the cities in California.
List<CIMUniqueValue> listUniqueValuescalifornia = new List<CIMUniqueValue> { new CIMUniqueValue { FieldValues = new string[] { "California" } } };
CIMUniqueValueClass californiaUniqueValueClass = new CIMUniqueValueClass
{
Editable = true,
Label = "California",
Patch = PatchShape.Default,
Symbol = SymbolFactory.Instance.ConstructPointSymbol(ColorFactory.Instance.BlueRGB).MakeSymbolReference(),
Visible = true,
Values = listUniqueValuescalifornia.ToArray()
};
//Create a list of the above two CIMUniqueValueClasses
List<CIMUniqueValueClass> listUniqueValueClasses = new List<CIMUniqueValueClass>
{
alabamaUniqueValueClass, californiaUniqueValueClass
};
//Create a list of CIMUniqueValueGroup
CIMUniqueValueGroup uvg = new CIMUniqueValueGroup
{
Classes = listUniqueValueClasses.ToArray(),
};
List<CIMUniqueValueGroup> listUniqueValueGroups = new List<CIMUniqueValueGroup> { uvg };
//Create the CIMUniqueValueRenderer
CIMUniqueValueRenderer uvr = new CIMUniqueValueRenderer
{
UseDefaultSymbol = true,
DefaultLabel = "all other values",
DefaultSymbol = SymbolFactory.Instance.ConstructPointSymbol(ColorFactory.Instance.GreyRGB).MakeSymbolReference(),
Groups = listUniqueValueGroups.ToArray(),
Fields = new string[] { "STATE_NAME" }
};
//Set the feature layer's renderer.
featureLayer.SetRenderer(uvr);
});

创建热图渲染器

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
string colorBrewerSchemesName = "ArcGIS Colors";
StyleProjectItem style = Project.Current.GetItems<StyleProjectItem>().First(s => s.Name == colorBrewerSchemesName);
string colorRampName = "Heat Map 4 - Semitransparent";
IList<ColorRampStyleItem> colorRampList = await QueuedTask.Run(() =>
{
return style.SearchColorRamps(colorRampName);
});
ColorRampStyleItem colorRamp = colorRampList[0];

await QueuedTask.Run(() =>
{
//defining a heatmap renderer that uses values from Population field as the weights
HeatMapRendererDefinition heatMapDef = new HeatMapRendererDefinition()
{
Radius = 20,
WeightField = "Population",
ColorRamp = colorRamp.ColorRamp,
RendereringQuality = 8,
UpperLabel = "High Density",
LowerLabel = "Low Density"
};

FeatureLayer flyr = MapView.Active.Map.Layers[0] as FeatureLayer;
CIMHeatMapRenderer heatMapRndr = flyr.CreateRenderer(heatMapDef) as CIMHeatMapRenderer;
flyr.SetRenderer(heatMapRndr);
});

创建未分类渲染器

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
string colorBrewerSchemesName = "ArcGIS Colors";
StyleProjectItem style = Project.Current.GetItems<StyleProjectItem>().First(s => s.Name == colorBrewerSchemesName);
string colorRampName = "Heat Map 4 - Semitransparent";
IList<ColorRampStyleItem> colorRampList = await QueuedTask.Run(() =>
{
return style.SearchColorRamps(colorRampName);
});
ColorRampStyleItem colorRamp = colorRampList[0];

await QueuedTask.Run(() =>
{
CIMPointSymbol pointSym = SymbolFactory.Instance.ConstructPointSymbol(ColorFactory.Instance.GreenRGB, 16.0, SimpleMarkerStyle.Diamond);
CIMSymbolReference symbolPointTemplate = pointSym.MakeSymbolReference();

//defining an unclassed renderer with custom upper and lower stops
//all features with value >= 5,000,000 will be drawn with the upper color from the color ramp
//all features with value <= 50,000 will be drawn with the lower color from the color ramp
UnclassedColorsRendererDefinition unclassRndrDef = new UnclassedColorsRendererDefinition
("Population", symbolPointTemplate, colorRamp.ColorRamp, "Highest", "Lowest", 5000000, 50000)
{

//drawing features with null values with a different symbol
ShowNullValues = true,
NullValueLabel = "Unknown"
};
CIMPointSymbol nullSym = SymbolFactory.Instance.ConstructPointSymbol(ColorFactory.Instance.RedRGB, 16.0, SimpleMarkerStyle.Circle);
unclassRndrDef.NullValueSymbol = nullSym.MakeSymbolReference();
FeatureLayer flyr = MapView.Active.Map.Layers[0] as FeatureLayer;
CIMClassBreaksRenderer cbRndr = flyr.CreateRenderer(unclassRndrDef) as CIMClassBreaksRenderer;
flyr.SetRenderer(cbRndr);
});

创建最大和最小符号大小上限的比例渲染器

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
string colorBrewerSchemesName = "ArcGIS Colors";
StyleProjectItem style = Project.Current.GetItems<StyleProjectItem>().First(s => s.Name == colorBrewerSchemesName);
string colorRampName = "Heat Map 4 - Semitransparent";
IList<ColorRampStyleItem> colorRampList = await QueuedTask.Run(() =>
{
return style.SearchColorRamps(colorRampName);
});
ColorRampStyleItem colorRamp = colorRampList[0];

await QueuedTask.Run(() =>
{
CIMPointSymbol pointSym = SymbolFactory.Instance.ConstructPointSymbol(ColorFactory.Instance.GreenRGB, 1.0, SimpleMarkerStyle.Circle);
CIMSymbolReference symbolPointTemplate = pointSym.MakeSymbolReference();

//minimum symbol size is capped to 4 point while the maximum symbol size is set to 50 point
ProportionalRendererDefinition prDef = new ProportionalRendererDefinition("POPULATION", symbolPointTemplate, 4, 50, true)
{

//setting upper and lower size stops to stop symbols growing or shrinking beyond those thresholds
UpperSizeStop = 5000000, //features with values >= 5,000,000 will be drawn with maximum symbol size
LowerSizeStop = 50000 //features with values <= 50,000 will be drawn with minimum symbol size
};
FeatureLayer flyr = MapView.Active.Map.Layers[0] as FeatureLayer;
CIMProportionalRenderer propRndr = flyr.CreateRenderer(prDef) as CIMProportionalRenderer;
flyr.SetRenderer(propRndr);

});

创建真实比例渲染器

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
string colorBrewerSchemesName = "ArcGIS Colors";
StyleProjectItem style = Project.Current.GetItems<StyleProjectItem>().First(s => s.Name == colorBrewerSchemesName);
string colorRampName = "Heat Map 4 - Semitransparent";
IList<ColorRampStyleItem> colorRampList = await QueuedTask.Run(() =>
{
return style.SearchColorRamps(colorRampName);
});
ColorRampStyleItem colorRamp = colorRampList[0];

await QueuedTask.Run(() =>
{
CIMPointSymbol pointSym = SymbolFactory.Instance.ConstructPointSymbol(ColorFactory.Instance.GreenRGB, 1.0, SimpleMarkerStyle.Circle);
CIMSymbolReference symbolPointTemplate = pointSym.MakeSymbolReference();

//Defining proportional renderer where size of symbol will be same as its value in field used in the renderer.
ProportionalRendererDefinition prDef = new ProportionalRendererDefinition("POPULATION", esriUnits.esriMeters, symbolPointTemplate, SymbolShapes.Square, ValueRepresentations.Radius);

FeatureLayer flyr = MapView.Active.Map.Layers[0] as FeatureLayer;
CIMProportionalRenderer propRndr = flyr.CreateRenderer(prDef) as CIMProportionalRenderer;
flyr.SetRenderer(propRndr);

});

拱廊

使用 Arcade 修改渲染器

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
var lyr = MapView.Active.Map.GetLayersAsFlattenedList().OfType<FeatureLayer>().FirstOrDefault(f => f.ShapeType == esriGeometryType.esriGeometryPolygon);
if (lyr == null) return;
QueuedTask.Run(() =>
{
// GetRenderer from Layer (assumes it is a unique value renderer)
var uvRenderer = lyr.GetRenderer() as CIMUniqueValueRenderer;
if (uvRenderer == null) return;
//layer has STATE_NAME field
//community sample Data\Admin\AdminSample.aprx
string expression = "if ($view.scale > 21000000) { return $feature.STATE_NAME } else { return 'All' }";
CIMExpressionInfo updatedExpressionInfo = new CIMExpressionInfo
{
Expression = expression,
Title = "Custom" // can be any string used for UI purpose.
};
//set the renderer's expression
uvRenderer.ValueExpressionInfo = updatedExpressionInfo;

//SetRenderer on Layer
lyr.SetRenderer(uvRenderer);
});

使用 Arcade 修改标注表达式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
var lyr = MapView.Active.Map.GetLayersAsFlattenedList().OfType<FeatureLayer>().FirstOrDefault(f => f.ShapeType == esriGeometryType.esriGeometryPolygon);
if (lyr == null) return;
QueuedTask.Run(() =>
{
//Get the layer's definition
//community sample Data\Admin\AdminSample.aprx
var lyrDefn = lyr.GetDefinition() as CIMFeatureLayer;
if (lyrDefn == null) return;
//Get the label classes - we need the first one
var listLabelClasses = lyrDefn.LabelClasses.ToList();
var theLabelClass = listLabelClasses.FirstOrDefault();
//set the label class Expression to use the Arcade expression
theLabelClass.Expression = "return $feature.STATE_NAME + TextFormatting.NewLine + $feature.POP2000;";
//Set the label definition back to the layer.
lyr.SetDefinition(lyrDefn);
});

高程表面图层

创建具有地表图层的场景

1
2
// wrap in QueuedTask.Run
var scene = MapFactory.Instance.CreateScene("My scene", groundSourceUri, MapViewingMode.SceneGlobal);

创建新的高程表面

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
//Note: call within QueuedTask.Run()
//Define a ServiceConnection to use for the new Elevation surface
var serverConnection = new CIMInternetServerConnection
{
Anonymous = true,
HideUserProperty = true,
URL = "https://elevation.arcgis.com/arcgis/services"
};
CIMAGSServiceConnection serviceConnection = new CIMAGSServiceConnection
{
ObjectName = "WorldElevation/Terrain",
ObjectType = "ImageServer",
URL = "https://elevation.arcgis.com/arcgis/services/WorldElevation/Terrain/ImageServer",
ServerConnection = serverConnection
};
//Defines a new elevation source set to the CIMAGSServiceConnection defined above
//At 2.x - var newElevationSource = new ArcGIS.Core.CIM.CIMElevationSource
//{
// VerticalUnit = ArcGIS.Core.Geometry.LinearUnit.Meters,
// DataConnection = serviceConnection,
// Name = "WorldElevation/Terrain",
// Visibility = true
//};
//The elevation surface
//At 2.x - var newElevationSurface = new ArcGIS.Core.CIM.CIMMapElevationSurface
//{
// Name = "New Elevation Surface",
// BaseSources = new ArcGIS.Core.CIM.CIMElevationSource[1] { newElevationSource },
// Visibility = true,
// ElevationMode = ElevationMode.CustomSurface,
// VerticalExaggeration = 1,
// EnableSurfaceShading = false,
// SurfaceTINShadingMode = SurfaceTINShadingMode.Smooth,
// Expanded = false,
// MapElevationID = "{3DEC3CC5-7C69-4132-A700-DCD5BDED14D6}"
//};
//Get the active map
var map = MapView.Active.Map;
//Get the elevation surfaces defined in the map
//At 2.x - var listOfElevationSurfaces = definition.ElevationSurfaces.ToList();
var listOfElevationSurfaces = map.GetElevationSurfaceLayers();
//Add the new elevation surface
//At 2.x - listOfElevationSurfaces.Add(newElevationSurface);
var elevationLyrCreationParams = new ElevationLayerCreationParams(serviceConnection);
var elevationSurface = LayerFactory.Instance.CreateLayer<ElevationSurfaceLayer>(
elevationLyrCreationParams, map);

将自定义高程表面设置为 Z 感知图层

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
//Define the custom elevation surface to use
//At 2.x - var layerElevationSurface = new CIMLayerElevationSurface
//{
// MapElevationID = "{3DEC3CC5-7C69-4132-A700-DCD5BDED14D6}"
//};
var layerElevationSurface = new CIMLayerElevationSurface
{
ElevationSurfaceLayerURI = "https://elevation3d.arcgis.com/arcgis/services/WorldElevation3D/Terrain3D/ImageServer"
};
//Get the layer's definition
var lyrDefn = featureLayer.GetDefinition() as CIMBasicFeatureLayer;
//Set the layer's elevation surface
lyrDefn.LayerElevation = layerElevationSurface;
//Set the layer's definition
featureLayer.SetDefinition(lyrDefn);

将高程源添加到现有高程表面图层

1
2
3
4
5
6
7
8
// wrap in QueuendTask.Run

// surfaceLayer could also be the ground layer

string uri = "https://elevation3d.arcgis.com/arcgis/rest/services/WorldElevation3D/Terrain3D/ImageServer";
var createParams = new ElevationLayerCreationParams(new Uri(uri));
createParams.Name = "Terrain 3D";
var eleSourceLayer = LayerFactory.Instance.CreateLayer<Layer>(createParams, surfaceLayer);

从地图中获取高程表面图层和高程源图层

1
2
3
4
5
6
7
8
9
10
// retrieve the elevation surface layers in the map including the Ground
var surfaceLayers = map.GetElevationSurfaceLayers();

// retrieve the single ground elevation surface layer in the map
var groundSurfaceLayer = map.GetGroundElevationSurfaceLayer();

// determine the number of elevation sources in the ground elevation surface layer
int numberGroundSources = groundSurfaceLayer.Layers.Count;
// get the first elevation source layer from the ground elevation surface layer
var groundSourceLayer = groundSurfaceLayer.Layers.FirstOrDefault();

查找高程表面图层

1
2
3
4
var surfaceLayers = map.GetElevationSurfaceLayers();
var surfaceLayer = surfaceLayers.FirstOrDefault(l => l.Name == "Surface2");

surfaceLayer = map.FindElevationSurfaceLayer(layerUri);

移除高程表面图层

1
2
3
4
5
6
// wrap in a QueuedTask.Run

map.ClearElevationSurfaceLayers(); //Ground will not be removed

map.RemoveLayer(surfaceLayer);//Cannot remove ground
map.RemoveLayers(map.GetElevationSurfaceLayers()); //Ground will not be removed

从曲面获取 Z 值

1
2
3
4
5
6
7
8
var geometry = await QueuedTask.Run<Geometry>(() =>
{
Geometry mapCentergeometry = MapView.Active.Map.CalculateFullExtent().Center;
return mapCentergeometry;
});
//Pass any Geometry type to GetZsFromSurfaceAsync
var surfaceZResult = await MapView.Active.Map.GetZsFromSurfaceAsync(geometry);
return surfaceZResult;

栅格图层

创建栅格图层

1
2
3
4
5
6
7
string url = @"C:\Images\Italy.tif";
await QueuedTask.Run(() =>
{
// Create a raster layer using a path to an image.
// Note: You can create a raster layer from a url, project item, or data connection.
rasterLayer = LayerFactory.Instance.CreateLayer(new Uri(url), aMap) as RasterLayer;
});

更新栅格图层上的栅格着色器

1
2
3
4
5
6
7
8
9
10
11
await QueuedTask.Run(() =>
{
// Get the colorizer from the raster layer.
CIMRasterColorizer rasterColorizer = rasterLayer.GetColorizer();
// Update raster colorizer properties.
rasterColorizer.Brightness = 10;
rasterColorizer.Contrast = -5;
rasterColorizer.ResamplingType = RasterResamplingType.NearestNeighbor;
// Update the raster layer with the changed colorizer.
rasterLayer.SetColorizer(rasterColorizer);
});

更新栅格图层上的 RGB 着色器

1
2
3
4
5
6
7
8
9
10
11
12
13
await QueuedTask.Run(() =>
{
// Get the colorizer from the raster layer.
CIMRasterColorizer rColorizer = rasterLayer.GetColorizer();
// Check if the colorizer is an RGB colorizer.
if (rColorizer is CIMRasterRGBColorizer rasterRGBColorizer)
{
// Update RGB colorizer properties.
rasterRGBColorizer.StretchType = RasterStretchType.ESRI;
// Update the raster layer with the changed colorizer.
rasterLayer.SetColorizer(rasterRGBColorizer);
}
});

检查是否可以将某个着色器应用于栅格图层

1
2
3
4
5
6
7
8
await QueuedTask.Run(() =>
{
// Get the list of colorizers that can be applied to the raster layer.
IEnumerable<RasterColorizerType> applicableColorizerList = rasterLayer.GetApplicableColorizers();
// Check if the RGB colorizer is part of the list.
bool isTrue_ContainTheColorizerType =
applicableColorizerList.Contains(RasterColorizerType.RGBColorizer);
});

基于默认着色器定义创建新的着色器并将其应用于栅格图层

1
2
3
4
5
6
7
8
9
10
11
12
13
14
await QueuedTask.Run(async () =>
{
// Check if the Stretch colorizer can be applied to the raster layer.
if (rasterLayer.GetApplicableColorizers().Contains(RasterColorizerType.StretchColorizer))
{
// Create a new Stretch Colorizer Definition using the default constructor.
StretchColorizerDefinition stretchColorizerDef_default = new StretchColorizerDefinition();
// Create a new Stretch colorizer using the colorizer definition created above.
CIMRasterStretchColorizer newStretchColorizer_default =
await rasterLayer.CreateColorizerAsync(stretchColorizerDef_default) as CIMRasterStretchColorizer;
// Set the new colorizer on the raster layer.
rasterLayer.SetColorizer(newStretchColorizer_default);
}
});

基于自定义着色器定义创建新的着色器并将其应用于栅格图层

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
await QueuedTask.Run(async () =>
{
// Check if the Stretch colorizer can be applied to the raster layer.
if (rasterLayer.GetApplicableColorizers().Contains(RasterColorizerType.StretchColorizer))
{
// Create a new Stretch Colorizer Definition specifying parameters
// for band index, stretch type, gamma and color ramp.
StretchColorizerDefinition stretchColorizerDef_custom =
new StretchColorizerDefinition(1, RasterStretchType.ESRI, 2, colorRamp);
// Create a new stretch colorizer using the colorizer definition created above.
CIMRasterStretchColorizer newStretchColorizer_custom =
await rasterLayer.CreateColorizerAsync(stretchColorizerDef_custom) as CIMRasterStretchColorizer;
// Set the new colorizer on the raster layer.
rasterLayer.SetColorizer(newStretchColorizer_custom);
}
});

使用新的着色器定义创建栅格图层

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// Create a new stretch colorizer definition using default constructor.
StretchColorizerDefinition stretchColorizerDef = new StretchColorizerDefinition();
var rasterLayerCreationParams = new RasterLayerCreationParams(new Uri(url))
{
ColorizerDefinition = stretchColorizerDef,
Name = layerName,
MapMemberIndex = 0
};
await QueuedTask.Run(() =>
{
// Create a raster layer using the colorizer definition created above.
// Note: You can create a raster layer from a url, project item, or data connection.
RasterLayer rasterLayerfromURL =
LayerFactory.Instance.CreateLayer<RasterLayer>(rasterLayerCreationParams, aMap);
});

马赛克图层

创建镶嵌图层

1
2
3
4
5
6
7
8
MosaicLayer mosaicLayer = null;
string url = @"C:\Images\countries.gdb\Italy";
await QueuedTask.Run(() =>
{
// Create a mosaic layer using a path to a mosaic dataset.
// Note: You can create a mosaic layer from a url, project item, or data connection.
mosaicLayer = LayerFactory.Instance.CreateLayer(new Uri(url), aMap) as MosaicLayer;
});

更新镶嵌图层上的栅格着色器

1
2
3
4
5
6
7
8
9
10
11
12
13
await QueuedTask.Run(() =>
{
// Get the image sub-layer from the mosaic layer.
ImageMosaicSubLayer mosaicImageSubLayer = mosaicLayer.GetImageLayer();
// Get the colorizer from the image sub-layer.
CIMRasterColorizer rasterColorizer = mosaicImageSubLayer.GetColorizer();
// Update raster colorizer properties.
rasterColorizer.Brightness = 10;
rasterColorizer.Contrast = -5;
rasterColorizer.ResamplingType = RasterResamplingType.NearestNeighbor;
// Update the image sub-layer with the changed colorizer.
mosaicImageSubLayer.SetColorizer(rasterColorizer);
});

更新镶嵌图层上的 RGB 着色器

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
await QueuedTask.Run(() =>
{
// Get the image sub-layer from the mosaic layer.
ImageMosaicSubLayer mosaicImageSubLayer = mosaicLayer.GetImageLayer();
// Get the colorizer from the image sub-layer.
CIMRasterColorizer rColorizer = mosaicImageSubLayer.GetColorizer();
// Check if the colorizer is an RGB colorizer.
if (rColorizer is CIMRasterRGBColorizer rasterRGBColorizer)
{
// Update RGB colorizer properties.
rasterRGBColorizer.StretchType = RasterStretchType.ESRI;
// Update the image sub-layer with the changed colorizer.
mosaicImageSubLayer.SetColorizer(rasterRGBColorizer);
}
});

检查是否可以将某种着色器应用于马赛克图层

1
2
3
4
5
6
7
8
9
10
11
await QueuedTask.Run(() =>
{
// Get the image sub-layer from the mosaic layer.
ImageMosaicSubLayer mosaicImageSubLayer = mosaicLayer.GetImageLayer();
// Get the list of colorizers that can be applied to the image sub-layer.
IEnumerable<RasterColorizerType> applicableColorizerList =
mosaicImageSubLayer.GetApplicableColorizers();
// Check if the RGB colorizer is part of the list.
bool isTrue_ContainTheColorizerType =
applicableColorizerList.Contains(RasterColorizerType.RGBColorizer);
});

基于默认着色器定义创建新的着色器并将其应用于镶嵌图层

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
await QueuedTask.Run(async () =>
{
// Get the image sub-layer from the mosaic layer.
ImageMosaicSubLayer mosaicImageSubLayer = mosaicLayer.GetImageLayer();
// Check if the Stretch colorizer can be applied to the image sub-layer.
if (mosaicImageSubLayer.GetApplicableColorizers().Contains(RasterColorizerType.StretchColorizer))
{
// Create a new Stretch Colorizer Definition using the default constructor.
StretchColorizerDefinition stretchColorizerDef_default = new StretchColorizerDefinition();
// Create a new Stretch colorizer using the colorizer definition created above.
CIMRasterStretchColorizer newStretchColorizer_default =
await mosaicImageSubLayer.CreateColorizerAsync(stretchColorizerDef_default) as CIMRasterStretchColorizer;
// Set the new colorizer on the image sub-layer.
mosaicImageSubLayer.SetColorizer(newStretchColorizer_default);
}
});

基于自定义着色器定义创建新的着色器并将其应用于镶嵌图层

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
await QueuedTask.Run(async () =>
{
// Get the image sub-layer from the mosaic layer.
ImageMosaicSubLayer mosaicImageSubLayer = mosaicLayer.GetImageLayer();
// Check if the Stretch colorizer can be applied to the image sub-layer.
if (mosaicImageSubLayer.GetApplicableColorizers().Contains(RasterColorizerType.StretchColorizer))
{
// Create a new Stretch colorizer definition specifying parameters
// for band index, stretch type, gamma and color ramp.
StretchColorizerDefinition stretchColorizerDef_custom =
new StretchColorizerDefinition(1, RasterStretchType.ESRI, 2, colorRamp);
// Create a new stretch colorizer using the colorizer definition created above.
CIMRasterStretchColorizer newStretchColorizer_custom =
await mosaicImageSubLayer.CreateColorizerAsync(stretchColorizerDef_custom) as CIMRasterStretchColorizer;
// Set the new colorizer on the image sub-layer.
mosaicImageSubLayer.SetColorizer(newStretchColorizer_custom);
}
});

使用新的着色器定义创建镶嵌图层

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// Create a new colorizer definition using default constructor.
StretchColorizerDefinition stretchColorizerDef = new StretchColorizerDefinition();
var rasterLayerCreationParams = new RasterLayerCreationParams(new Uri(url))
{
Name = layerName,
ColorizerDefinition = stretchColorizerDef,
MapMemberIndex = 0

};
await QueuedTask.Run(() =>
{
// Create a mosaic layer using the colorizer definition created above.
// Note: You can create a mosaic layer from a url, project item, or data connection.
MosaicLayer newMosaicLayer =
LayerFactory.Instance.CreateLayer<MosaicLayer>(rasterLayerCreationParams, aMap);
});

更新镶嵌图层上的排序顺序 - 镶嵌方法

1
2
3
4
5
6
7
8
9
10
11
await QueuedTask.Run(() =>
{
// Get the image sub-layer from the mosaic layer.
ImageServiceLayer mosaicImageSubLayer = mosaicLayer.GetImageLayer() as ImageServiceLayer;
// Get the mosaic rule.
CIMMosaicRule mosaicingRule = mosaicImageSubLayer.GetMosaicRule();
// Set the Mosaic Method to Center.
mosaicingRule.MosaicMethod = RasterMosaicMethod.Center;
// Update the mosaic with the changed mosaic rule.
mosaicImageSubLayer.SetMosaicRule(mosaicingRule);
});

更新镶嵌图层上的解析重叠 - 镶嵌运算符

1
2
3
4
5
6
7
8
9
10
11
await QueuedTask.Run(() =>
{
// Get the image sub-layer from the mosaic layer.
ImageServiceLayer mosaicImageSublayer = mosaicLayer.GetImageLayer() as ImageServiceLayer;
// Get the mosaic rule.
CIMMosaicRule mosaicRule = mosaicImageSublayer.GetMosaicRule();
// Set the Mosaic Operator to Mean.
mosaicRule.MosaicOperatorType = RasterMosaicOperatorType.Mean;
// Update the mosaic with the changed mosaic rule.
mosaicImageSublayer.SetMosaicRule(mosaicRule);
});

影像服务图层

创建影像服务图层

1
2
3
4
5
6
7
8
ImageServiceLayer isLayer = null;
string url =
@"http://imagery.arcgisonline.com/arcgis/services/LandsatGLS/GLS2010_Enhanced/ImageServer";
await QueuedTask.Run(() =>
{
// Create an image service layer using the url for an image service.
isLayer = LayerFactory.Instance.CreateLayer(new Uri(url), aMap) as ImageServiceLayer;
});

更新影像服务图层上的栅格着色器

1
2
3
4
5
6
7
8
9
10
11
await QueuedTask.Run(() =>
{
// Get the colorizer from the image service layer.
CIMRasterColorizer rasterColorizer = isLayer.GetColorizer();
// Update the colorizer properties.
rasterColorizer.Brightness = 10;
rasterColorizer.Contrast = -5;
rasterColorizer.ResamplingType = RasterResamplingType.NearestNeighbor;
// Update the image service layer with the changed colorizer.
isLayer.SetColorizer(rasterColorizer);
});

更新影像服务图层上的 RGB 着色器

1
2
3
4
5
6
7
8
9
10
11
12
13
await QueuedTask.Run(() =>
{
// Get the colorizer from the image service layer.
CIMRasterColorizer rColorizer = isLayer.GetColorizer();
// Check if the colorizer is an RGB colorizer.
if (rColorizer is CIMRasterRGBColorizer rasterRGBColorizer)
{
// Update RGB colorizer properties.
rasterRGBColorizer.StretchType = RasterStretchType.ESRI;
// Update the image service layer with the changed colorizer.
isLayer.SetColorizer((CIMRasterColorizer)rasterRGBColorizer);
}
});

检查是否可以将特定着色器应用于影像服务图层

1
2
3
4
5
6
7
8
await QueuedTask.Run(() =>
{
// Get the list of colorizers that can be applied to the imager service layer.
IEnumerable<RasterColorizerType> applicableColorizerList = isLayer.GetApplicableColorizers();
// Check if the RGB colorizer is part of the list.
bool isTrue_ContainTheColorizerType =
applicableColorizerList.Contains(RasterColorizerType.RGBColorizer);
});

基于默认着色器定义创建新的着色器并将其应用于影像服务图层

1
2
3
4
5
6
7
8
9
10
11
12
13
14
await QueuedTask.Run(async () =>
{
// Check if the Stretch colorizer can be applied to the image service layer.
if (isLayer.GetApplicableColorizers().Contains(RasterColorizerType.StretchColorizer))
{
// Create a new Stretch Colorizer Definition using the default constructor.
StretchColorizerDefinition stretchColorizerDef_default = new StretchColorizerDefinition();
// Create a new Stretch colorizer using the colorizer definition created above.
CIMRasterStretchColorizer newStretchColorizer_default =
await isLayer.CreateColorizerAsync(stretchColorizerDef_default) as CIMRasterStretchColorizer;
// Set the new colorizer on the image service layer.
isLayer.SetColorizer(newStretchColorizer_default);
}
});

基于自定义着色器定义创建新的着色器并将其应用于影像服务图层

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
await QueuedTask.Run(async () =>
{
// Check if the Stretch colorizer can be applied to the image service layer.
if (isLayer.GetApplicableColorizers().Contains(RasterColorizerType.StretchColorizer))
{
// Create a new Stretch Colorizer Definition specifying parameters
// for band index, stretch type, gamma and color ramp.
StretchColorizerDefinition stretchColorizerDef_custom =
new StretchColorizerDefinition(1, RasterStretchType.ESRI, 2, colorRamp);
// Create a new stretch colorizer using the colorizer definition created above.
CIMRasterStretchColorizer newStretchColorizer_custom =
await isLayer.CreateColorizerAsync(stretchColorizerDef_custom) as CIMRasterStretchColorizer;
// Set the new colorizer on the image service layer.
isLayer.SetColorizer(newStretchColorizer_custom);
}
});

使用新的着色器定义创建影像服务图层

1
2
3
4
5
6
7
8
9
10
11
12
13
14
// Create a new colorizer definition using default constructor.
StretchColorizerDefinition stretchColorizerDef = new StretchColorizerDefinition();
var rasterLayerCreationParams = new RasterLayerCreationParams(new Uri(url))
{
Name = layerName,
ColorizerDefinition = stretchColorizerDef,
MapMemberIndex = 0
};
await QueuedTask.Run(() =>
{
// Create an image service layer using the colorizer definition created above.
ImageServiceLayer imageServiceLayer =
LayerFactory.Instance.CreateLayer<ImageServiceLayer>(rasterLayerCreationParams, aMap);
});

更新影像服务图层上的排序顺序 - 镶嵌方法

1
2
3
4
5
6
7
8
9
await QueuedTask.Run(() =>
{
// Get the mosaic rule of the image service.
CIMMosaicRule mosaicRule = isLayer.GetMosaicRule();
// Set the Mosaic Method to Center.
mosaicRule.MosaicMethod = RasterMosaicMethod.Center;
// Update the image service with the changed mosaic rule.
isLayer.SetMosaicRule(mosaicRule);
});

更新影像服务图层上的解决重叠 - 镶嵌运算符

1
2
3
4
5
6
7
8
9
await QueuedTask.Run(() =>
{
// Get the mosaic rule of the image service.
CIMMosaicRule mosaicingRule = isLayer.GetMosaicRule();
// Set the Mosaic Operator to Mean.
mosaicingRule.MosaicOperatorType = RasterMosaicOperatorType.Mean;
// Update the image service with the changed mosaic rule.
isLayer.SetMosaicRule(mosaicingRule);
});

使用独立表

创建独立表

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
//container can be a map or group layer
var container = MapView.Active.Map;
//var container = MapView.Active.Map.GetLayersAsFlattenedList()
// .OfType<GroupLayer>().First();
QueuedTask.Run(() =>
{
//use a local path
var table = StandaloneTableFactory.Instance.CreateStandaloneTable(
new Uri(@"C:\Temp\Data\SDK.gdb\EarthquakeDamage", UriKind.Absolute),
container);
//use a URI to a feature service table endpoint
var table2 = StandaloneTableFactory.Instance.CreateStandaloneTable(
new Uri(@"https://bexdog.esri.com/server/rest/services/FeatureServer" + "/2", UriKind.Absolute),
container);
//Use an item
var item = ItemFactory.Instance.Create(@"C:\Temp\Data\SDK.gdb\ParcelOwners");
var tableCreationParams = new StandaloneTableCreationParams(item);
var table3 = StandaloneTableFactory.Instance.CreateStandaloneTable(tableCreationParams, container);

//use table creation params
var table_params = new StandaloneTableCreationParams(item)
{
// At 2.x - DefinitionFilter = new CIMDefinitionFilter()
//{
// //optional - use a filter
// DefinitionExpression = "LAND_USE = 3"
//}
DefinitionQuery = new DefinitionQuery(whereClause: "LAND_USE = 3", name: "Landuse")
};
var table4 = StandaloneTableFactory.Instance.CreateStandaloneTable(table_params,
container);

});

从表的容器中检索表

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
var container = MapView.Active.Map;

//the map standalone table collection
var table = container.GetStandaloneTablesAsFlattenedList()
.FirstOrDefault(tbl => tbl.Name == "EarthquakeDamage");

//or from a group layer
var grp_layer = MapView.Active.Map.FindLayers("GroupLayer1").First() as GroupLayer;
var table2 = grp_layer.FindStandaloneTables("EarthquakeDamage").First();
//or grp_layer.GetStandaloneTablesAsFlattenedList().First()
//or grp_layer.StandaloneTables.Where(...).First(), etc.

//show the table in a table view
//use FrameworkApplication.Current.Dispatcher.BeginInvoke if not on the UI thread
FrameworkApplication.Panes.OpenTablePane(table2);

移动独立表

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
//get the first group layer that has at least one table
var grp_layer = MapView.Active.Map.GetLayersAsFlattenedList()
.OfType<GroupLayer>().First(g => g.StandaloneTables.Count > 0);
var map = MapView.Active.Map;//assumes non-null
QueuedTask.Run(() =>
{
//move the first table to the bottom of the container
grp_layer.MoveStandaloneTable(grp_layer.StandaloneTables.First(), -1);

//move the last table in the map standalone tables to a group
//layer and place it at position 3. If 3 is invalid, the table
//will be placed at the bottom of the target container
//assumes the map has at least one standalone table...
var table = map.StandaloneTables.Last();
map.MoveStandaloneTable(table, grp_layer, 3);

//move a table from a group layer to the map standalone tables
//collection - assumes a table called 'Earthquakes' exists
var table2 = grp_layer.FindStandaloneTables("Earthquakes").First();
//move to the map container
map.MoveStandaloneTable(table2, 0);//will be placed at the top
});

删除独立表

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
//get the first group layer that has at least one table
var grp_layer = MapView.Active.Map.GetLayersAsFlattenedList()
.OfType<GroupLayer>().First(g => g.StandaloneTables.Count > 0);
var map = MapView.Active.Map;//assumes non-null

QueuedTask.Run(() =>
{
//get the tables from the map container
var tables = map.GetStandaloneTablesAsFlattenedList();
//delete the first...
if (tables.Count() > 0)
{
map.RemoveStandaloneTable(tables.First());
//or delete all of them
map.RemoveStandaloneTables(tables);
}

//delete a table from a group layer
//assumes it has at least one table...
grp_layer.RemoveStandaloneTable(grp_layer.StandaloneTables.First());
});

符号图层绘制 (SLD)

添加 SLD

1
2
3
4
5
6
7
8
9
10
11
QueuedTask.Run(() =>
{
//check if it can be added to the layer
if (featLayer.CanAddSymbolLayerDrawing())
featLayer.AddSymbolLayerDrawing();

//ditto for a group layer...must have at least
//one child feature layer that can participate
if (groupLayer.CanAddSymbolLayerDrawing())
groupLayer.AddSymbolLayerDrawing();
});

确定图层是否添加了 SLD

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
//SLD can be added to feature layers and group layers
//For a group layer, SLD controls all child feature layers
//that are participating in the SLD

//var featLayer = ...;//retrieve the feature layer
//var groupLayer = ...;//retrieve the group layer
QueuedTask.Run(() =>
{
//Check if the layer has SLD added -returns a tuple
var tuple = featLayer.HasSymbolLayerDrawingAdded();
if (tuple.addedOnLayer)
{
//SLD is added on the layer
}
else if (tuple.addedOnParent)
{
//SLD is added on the parent (group layer) -
//check parent...this can be recursive
var parentLayer = GetParentLayerWithSLD(featLayer.Parent as GroupLayer);
/*
*
//Recursively get the parent with SLD
public GroupLayer GetParentLayerWithSLD(GroupLayer groupLayer)
{
if (groupLayer == null)
return null;
//Must be on QueuedTask
var sld_added = groupLayer.HasSymbolLayerDrawingAdded();
if (sld_added.addedOnLayer)
return groupLayer;
else if (sld_added.addedOnParent)
return GetParentLayerWithSLD(groupLayer.Parent as GroupLayer);
return null;
}
*/
}
});

启用/禁用 SLD

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
QueuedTask.Run(() =>
{
//A layer may have SLD added but is not using it
//HasSymbolLayerDrawingAdded returns a tuple - to check
//the layer has SLD (not its parent) check addedOnLayer
if (featLayer.HasSymbolLayerDrawingAdded().addedOnLayer)
{
//the layer has SLD but is the layer currently using it?
//GetUseSymbolLayerDrawing returns a tuple - useOnLayer for
//the layer (and useOnParent for the parent layer)
if (!featLayer.GetUseSymbolLayerDrawing().useOnLayer)
{
//enable it
featLayer.SetUseSymbolLayerDrawing(true);
}
}

//Enable/Disable SLD on a layer parent
if (featLayer.HasSymbolLayerDrawingAdded().addedOnParent)
{
//check parent...this can be recursive
var parent = GetParentLayerWithSLD(featLayer.Parent as GroupLayer);
if (parent.GetUseSymbolLayerDrawing().useOnLayer)
parent.SetUseSymbolLayerDrawing(true);
}
/*
*
//Recursively get the parent with SLD
public GroupLayer GetParentLayerWithSLD(GroupLayer groupLayer)
{
if (groupLayer == null)
return null;
//Must be on QueuedTask
var sld_added = groupLayer.HasSymbolLayerDrawingAdded();
if (sld_added.addedOnLayer)
return groupLayer;
else if (sld_added.addedOnParent)
return GetParentLayerWithSLD(groupLayer.Parent as GroupLayer);
return null;
}
*/
});

设备位置 API、GPS/GNSS 设备

连接到设备位置源

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
var newSrc = new SerialPortDeviceLocationSource();

//Specify the COM port the device is connected to
newSrc.ComPort = "Com3";
newSrc.BaudRate = 4800;
newSrc.AntennaHeight = 3; // meters
//fill in other properties as needed

var props = new DeviceLocationProperties();
props.AccuracyThreshold = 10; // meters

// jump to the background thread
await QueuedTask.Run(() =>
{
//open the device
DeviceLocationService.Instance.Open(newSrc, props);
});

获取当前设备位置源

1
2
3
4
5
var source = DeviceLocationService.Instance.GetSource();
if (source == null)
{
//There is no current source
}

关闭当前设备位置源

1
2
3
4
5
6
7
8
9
//Is there a current device source?
var src = DeviceLocationService.Instance.GetSource();
if (src == null)
return;//no current source

await QueuedTask.Run(() =>
{
DeviceLocationService.Instance.Close();
});

获取当前设备位置源和属性

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
bool isConnected = DeviceLocationService.Instance.IsDeviceConnected();

var src = DeviceLocationService.Instance.GetSource();

if (src is SerialPortDeviceLocationSource serialPortSrc)
{
var port = serialPortSrc.ComPort;
var antennaHeight = serialPortSrc.AntennaHeight;
var dataBits = serialPortSrc.DataBits;
var baudRate = serialPortSrc.BaudRate;
var parity = serialPortSrc.Parity;
var stopBits = serialPortSrc.StopBits;

// retrieving spatial reference needs the MCT
var sr = await QueuedTask.Run(() =>
{
return serialPortSrc.GetSpatialReference();
});

}
var dlProps = DeviceLocationService.Instance.GetProperties();
var accuracy = dlProps.AccuracyThreshold;

更新当前设备位置源上的属性

1
2
3
4
5
6
7
8
await QueuedTask.Run(() =>
{
var dlProps = DeviceLocationService.Instance.GetProperties();
//Change the accuracy threshold
dlProps.AccuracyThreshold = 22.5; // meters

DeviceLocationService.Instance.UpdateProperties(dlProps);
});

订阅设备位置属性更新事件

1
2
3
4
5
6
7
8
9
10
11
12
13
private void SubscribeToPropertiesEvents()
{
DeviceLocationPropertiesUpdatedEvent.Subscribe(OnDeviceLocationPropertiesUpdated);
}
private void OnDeviceLocationPropertiesUpdated(DeviceLocationPropertiesUpdatedEventArgs args)
{
if (args == null)
return;

var properties = args.DeviceLocationProperties;

// TODO - something with the updated properties
}

订阅设备位置源更改事件

1
2
3
4
5
6
7
8
9
10
11
12
13
private void SubscribeToSourceEvents()
{
DeviceLocationSourceChangedEvent.Subscribe(OnDeviceLocationSourceChanged);
}
private void OnDeviceLocationSourceChanged(DeviceLocationSourceChangedEventArgs args)
{
if (args == null)
return;

var source = args.DeviceLocationSource;

// TODO - something with the updated source properties
}

映射设备位置选项

启用/禁用地图的当前设备位置源

1
2
3
4
5
6
bool enabled = MapDeviceLocationService.Instance.IsDeviceLocationEnabled;

await QueuedTask.Run(() =>
{
MapDeviceLocationService.Instance.SetDeviceLocationEnabled(!enabled);
});

获取当前地图设备位置选项

1
2
3
4
5
6
var options = MapDeviceLocationService.Instance.GetDeviceLocationOptions();

var visibility = options.DeviceLocationVisibility;
var navMode = options.NavigationMode;
var trackUp = options.TrackUpNavigation;
var showBuffer = options.ShowAccuracyBuffer;

检查地图上是否启用了当前设备位置

1
2
3
4
if (MapDeviceLocationService.Instance.IsDeviceLocationEnabled)
{
//The Device Location Source is Enabled
}

设置当前地图设备位置选项

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
//Must be on the QueuedTask.Run()

//Check there is a source first...
if (DeviceLocationService.Instance.GetSource() == null)
//Setting DeviceLocationOptions w/ no Device Location Source
//Will throw an InvalidOperationException
return;

var map = MapView.Active.Map;
if (!MapDeviceLocationService.Instance.IsDeviceLocationEnabled)
//Setting DeviceLocationOptions w/ no Device Location Enabled
//Will throw an InvalidOperationException
return;

MapDeviceLocationService.Instance.SetDeviceLocationOptions(
new MapDeviceLocationOptions()
{
DeviceLocationVisibility = true,
NavigationMode = MappingDeviceLocationNavigationMode.KeepAtCenter,
TrackUpNavigation = true
});

缩放/平移地图到最新位置

1
2
3
4
5
6
7
8
9
//Must be on the QueuedTask.Run()

if (!MapDeviceLocationService.Instance.IsDeviceLocationEnabled)
//Calling ZoomOrPanToCurrentLocation w/ no Device Location Enabled
//Will throw an InvalidOperationException
return;

// true for zoom, false for pan
MapDeviceLocationService.Instance.ZoomOrPanToCurrentLocation(true);

将最新位置添加到图形图层

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
//var graphicsLayer = ... ;
//Must be on the QueuedTask.Run()

// get the last location
var pt = DeviceLocationService.Instance.GetCurrentSnapshot()?.GetPositionAsMapPoint();
if (pt != null)
{
//Create a point symbol
var ptSymbol = SymbolFactory.Instance.ConstructPointSymbol(
CIMColor.CreateRGBColor(125, 125, 0), 10, SimpleMarkerStyle.Triangle);
//Add a graphic to the graphics layer
graphicsLayer.AddElement(pt, ptSymbol);
//unselect it
graphicsLayer.ClearSelection();
}

订阅位置快照事件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
private void SubscribeToSnapshotEvents()
{
SnapshotChangedEvent.Subscribe(OnSnapshotChanged);
}
private void OnSnapshotChanged(SnapshotChangedEventArgs args)
{
if (args == null)
return;

var snapshot = args.Snapshot as NMEASnapshot;
if (snapshot == null)
return;

QueuedTask.Run(() =>
{
var pt = snapshot.GetPositionAsMapPoint();
if (pt?.IsEmpty ?? true)
return;

// access properties
var alt = snapshot.Altitude;
var dt = snapshot.DateTime;
var vdop = snapshot.VDOP;
var hdop = snapshot.HDOP;
// etc

//TODO: use the snapshot
});
}

特征遮罩

获取要素的遮罩几何

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
var featureLayer = MapView.Active.Map.GetLayersAsFlattenedList()
.OfType<BasicFeatureLayer>().FirstOrDefault();
if (featureLayer == null)
return;

var mv = MapView.Active;

QueuedTask.Run(() =>
{
using (var table = featureLayer.GetTable())
{
using (var rc = table.Search())
{
//get the first feature...
//...assuming at least one feature gets retrieved
rc.MoveNext();
var oid = rc.Current.GetObjectID();

//Use DrawingOutlineType.BoundingEnvelope to retrieve a generalized
//mask geometry or "Box". The mask will be in the same SpatRef as the map
//At 2.x - var mask_geom = featureLayer.QueryDrawingOutline(oid, mv, DrawingOutlineType.Exact);
var mask_geom = featureLayer.GetDrawingOutline(oid, mv, DrawingOutlineType.Exact);

//TODO - use the mask geometry...
}
}
});

风格管理

如何按名称获取项目中的样式

1
2
3
4
5
//Get all styles in the project
var ProjectStyles = Project.Current.GetItems<StyleProjectItem>();

//Get a specific style in the project by name
StyleProjectItem style = ProjectStyles.First(x => x.Name == "NameOfTheStyle");

如何创建新样式

1
2
3
//Full path for the new style file (.stylx) to be created
string styleToCreate = @"C:\Temp\NewStyle.stylx";
await QueuedTask.Run(() => StyleHelper.CreateStyle(Project.Current, styleToCreate));

如何向项目添加样式

1
2
3
4
5
6
//For ArcGIS Pro system styles, just pass in the name of the style to add to the project
await QueuedTask.Run(() => StyleHelper.AddStyle(Project.Current, "3D Vehicles"));

//For custom styles, pass in the full path to the style file on disk
string customStyleToAdd = @"C:\Temp\CustomStyle.stylx";
await QueuedTask.Run(() => StyleHelper.AddStyle(Project.Current, customStyleToAdd));

如何从项目中删除样式

1
2
3
4
5
6
//For ArcGIS Pro system styles, just pass in the name of the style to remove from the project
await QueuedTask.Run(() => StyleHelper.RemoveStyle(Project.Current, "3D Vehicles"));

//For custom styles, pass in the full path to the style file on disk
string customStyleToAdd = @"C:\Temp\CustomStyle.stylx";
await QueuedTask.Run(() => StyleHelper.RemoveStyle(Project.Current, customStyleToAdd));

如何将样式项添加到样式

1
2
3
4
5
6
7
8
9
10
11
public Task AddStyleItemAsync(StyleProjectItem style, StyleItem itemToAdd)
{
return QueuedTask.Run(() =>
{
if (style == null || itemToAdd == null)
throw new System.ArgumentNullException();

//Add the item to style
style.AddItem(itemToAdd);
});
}

如何从样式中删除样式项

1
2
3
4
5
6
7
8
9
10
11
public Task RemoveStyleItemAsync(StyleProjectItem style, StyleItem itemToRemove)
{
return QueuedTask.Run(() =>
{
if (style == null || itemToRemove == null)
throw new System.ArgumentNullException();

//Remove the item from style
style.RemoveItem(itemToRemove);
});
}

如何确定样式是否可以升级

1
2
3
4
5
6
7
8
9
10
//Pass in the full path to the style file on disk
public async Task<bool> CanUpgradeStyleAsync(string stylePath)
{
//Add the style to the current project
await QueuedTask.Run(() => StyleHelper.AddStyle(Project.Current, stylePath));
StyleProjectItem style = Project.Current.GetItems<StyleProjectItem>().First(x => x.Path == stylePath);

//returns true if style can be upgraded
return style.CanUpgrade;
}

如何确定样式是否为只读

1
2
3
4
5
6
7
8
9
10
//Pass in the full path to the style file on disk
public async Task<bool> IsReadOnly(string stylePath)
{
//Add the style to the current project
await QueuedTask.Run(() => StyleHelper.AddStyle(Project.Current, stylePath));
StyleProjectItem style = Project.Current.GetItems<StyleProjectItem>().First(x => x.Path == stylePath);

//returns true if style is read-only
return style.IsReadOnly;
}

如何确定样式是否为当前样式

1
2
3
4
5
6
7
8
9
10
//Pass in the full path to the style file on disk
public async Task<bool> IsCurrent(string stylePath)
{
//Add the style to the current project
await QueuedTask.Run(() => StyleHelper.AddStyle(Project.Current, stylePath));
StyleProjectItem style = Project.Current.GetItems<StyleProjectItem>().First(x => x.Path == stylePath);

//returns true if style matches the current Pro version
return style.IsCurrent;
}

如何升级样式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
//Pass in the full path to the style file on disk
public async Task<bool> UpgradeStyleAsync(string stylePath)
{
bool success = false;

//Add the style to the current project
await QueuedTask.Run(() => StyleHelper.AddStyle(Project.Current, stylePath));
StyleProjectItem style = Project.Current.GetItems<StyleProjectItem>().First(x => x.Path == stylePath);

//Verify that style can be upgraded
if (style.CanUpgrade)
{
success = await QueuedTask.Run(() => StyleHelper.UpgradeStyle(style));
}
//return true if style was upgraded
return success;
}

符号

如何构建特定颜色和大小的点符号

1
2
3
4
await QueuedTask.Run(() =>
{
CIMPointSymbol pointSymbol = SymbolFactory.Instance.ConstructPointSymbol(ColorFactory.Instance.RedRGB, 10.0);
});

如何构建特定颜色、大小和形状的点符号

1
2
3
4
await QueuedTask.Run(() =>
{
CIMPointSymbol starPointSymbol = SymbolFactory.Instance.ConstructPointSymbol(ColorFactory.Instance.RedRGB, 10.0, SimpleMarkerStyle.Star);
});

如何根据标记构造点符号

1
2
3
4
5
await QueuedTask.Run(() =>
{
CIMMarker marker = SymbolFactory.Instance.ConstructMarker(ColorFactory.Instance.GreenRGB, 8.0, SimpleMarkerStyle.Pushpin);
CIMPointSymbol pointSymbolFromMarker = SymbolFactory.Instance.ConstructPointSymbol(marker);
});

如何从磁盘上的文件构造点符号

1
2
3
4
//The following file formats can be used to create the marker: DAE, 3DS, FLT, EMF, JPG, PNG, BMP, GIF
CIMMarker markerFromFile = await QueuedTask.Run(() => SymbolFactory.Instance.ConstructMarkerFromFile(@"C:\Temp\fileName.dae"));

CIMPointSymbol pointSymbolFromFile = SymbolFactory.Instance.ConstructPointSymbol(markerFromFile);

如何从内存图形构造点符号

1
2
3
4
5
6
7
8
9
10
11
12
//Create a stream for the image
//At 3.0 you need https://www.nuget.org/packages/Microsoft.Windows.Compatibility
//System.Drawing

System.Drawing.Image newImage = System.Drawing.Image.FromFile(@"C:\PathToImage\Image.png");
var stream = new System.IO.MemoryStream();
newImage.Save(stream, System.Drawing.Imaging.ImageFormat.Png);
stream.Position = 0;
//Create marker using the stream
CIMMarker markerFromStream = SymbolFactory.Instance.ConstructMarkerFromStream(stream);
//Create the point symbol from the marker
CIMPointSymbol pointSymbolFromStream = SymbolFactory.Instance.ConstructPointSymbol(markerFromStream);

如何构造特定颜色和填充样式的面符号

1
CIMPolygonSymbol polygonSymbol = SymbolFactory.Instance.ConstructPolygonSymbol(ColorFactory.Instance.RedRGB, SimpleFillStyle.Solid);

如何构建特定颜色、填充样式和轮廓的多边形符号

1
2
CIMStroke outline = SymbolFactory.Instance.ConstructStroke(ColorFactory.Instance.BlueRGB, 2.0, SimpleLineStyle.Solid);
CIMPolygonSymbol fillWithOutline = SymbolFactory.Instance.ConstructPolygonSymbol(ColorFactory.Instance.RedRGB, SimpleFillStyle.Solid, outline);

如何在没有轮廓的情况下构建面符号

1
CIMPolygonSymbol fillWithoutOutline = SymbolFactory.Instance.ConstructPolygonSymbol(ColorFactory.Instance.RedRGB, SimpleFillStyle.Solid, null);

如何构建特定颜色、大小和线条样式的线符号

1
CIMLineSymbol lineSymbol = SymbolFactory.Instance.ConstructLineSymbol(ColorFactory.Instance.BlueRGB, 4.0, SimpleLineStyle.Solid);

如何根据笔划构造线条符号

1
2
CIMStroke stroke = SymbolFactory.Instance.ConstructStroke(ColorFactory.Instance.BlackRGB, 2.0);
CIMLineSymbol lineSymbolFromStroke = SymbolFactory.Instance.ConstructLineSymbol(stroke);

如何构建线端带有圆形标记的多图层线符号

1
2
3
4
5
6
7
8
9
10
11
12
13
//These methods must be called within the lambda passed to QueuedTask.Run
var lineStrokeRed = SymbolFactory.Instance.ConstructStroke(ColorFactory.Instance.RedRGB, 4.0);
var markerCircle = SymbolFactory.Instance.ConstructMarker(ColorFactory.Instance.RedRGB, 12, SimpleMarkerStyle.Circle);
markerCircle.MarkerPlacement = new CIMMarkerPlacementOnVertices()
{
AngleToLine = true,
PlaceOnEndPoints = true,
Offset = 0
};
var lineSymbolWithCircles = new CIMLineSymbol()
{
SymbolLayers = new CIMSymbolLayer[2] { markerCircle, lineStrokeRed }
};

如何构建末端带有箭头的多图层线符号

1
2
3
4
5
6
7
8
9
10
11
//These methods must be called within the lambda passed to QueuedTask.Run
var markerTriangle = SymbolFactory.Instance.ConstructMarker(ColorFactory.Instance.RedRGB, 12, SimpleMarkerStyle.Triangle);
markerTriangle.Rotation = -90; // or -90
markerTriangle.MarkerPlacement = new CIMMarkerPlacementOnLine() { AngleToLine = true, RelativeTo = PlacementOnLineRelativeTo.LineEnd };

var lineSymbolWithArrow = new CIMLineSymbol()
{
SymbolLayers = new CIMSymbolLayer[2] { markerTriangle,
SymbolFactory.Instance.ConstructStroke(ColorFactory.Instance.RedRGB, 2)
}
};

如何从符号获取符号引用

1
2
3
4
CIMPolygonSymbol symbol = SymbolFactory.Instance.ConstructPolygonSymbol(ColorFactory.Instance.RedRGB);

//Get symbol reference from the symbol
CIMSymbolReference symbolReference = symbol.MakeSymbolReference();

修改从字符标记创建的点符号

1
2
3
4
5
6
7
8
9
10
11
//create marker from the Font, char index,size,color
var cimMarker = SymbolFactory.Instance.ConstructMarker(125, "Wingdings 3", "Regular", 6, ColorFactory.Instance.BlueRGB) as CIMCharacterMarker;
var polygonMarker = cimMarker.Symbol;
//modifying the polygon's outline and fill
//This is the outline
polygonMarker.SymbolLayers[0] = SymbolFactory.Instance.ConstructStroke(ColorFactory.Instance.GreenRGB, 2, SimpleLineStyle.Solid);
//This is the fill
polygonMarker.SymbolLayers[1] = SymbolFactory.Instance.ConstructSolidFill(ColorFactory.Instance.BlueRGB);
//create a symbol from the marker
//Note this overload of ConstructPointSymbol does not need to be run within QueuedTask.Run.
var pointSymbol = SymbolFactory.Instance.ConstructPointSymbol(cimMarker);

获取可用字体的列表

1
2
3
4
5
6
7
8
//Must use QueuedTask.Run(...)
//returns a tuple per font: (string fontName, List<string> fontStyles)
var fonts = SymbolFactory.Instance.GetAvailableFonts();
foreach(var font in fonts)
{
var styles = string.Join(",", font.fontStyles);
System.Diagnostics.Debug.WriteLine($"{font.fontName}, styles: {styles}");
}

获取/设置默认字体

1
2
3
4
5
6
7
8
//Must use QueuedTask.Run(...)
var def_font = SymbolFactory.Instance.DefaultFont;
System.Diagnostics.Debug.WriteLine($"{def_font.fontName}, styles: {def_font.styleName}");

//set default font - set through application options
//Must use QueuedTask
ApplicationOptions.TextAndGraphicsElementsOptions.SetDefaultFont("tahoma");
ApplicationOptions.TextAndGraphicsElementsOptions.SetDefaultFont("tahoma","bold");

使用选项构建文本符号

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
QueuedTask.Run(() =>
{
//using the default font
var textSym1 = SymbolFactory.Instance.ConstructTextSymbol();
var textSym2 = SymbolFactory.Instance.ConstructTextSymbol(
ColorFactory.Instance.BlueRGB, 14);

//using a specific font
var textSym3 = SymbolFactory.Instance.ConstructTextSymbol("Arial");
var textSym4 = SymbolFactory.Instance.ConstructTextSymbol(
"Arial", "Narrow Bold");

//or query available fonts to ensure the font is there
var all_fonts = SymbolFactory.Instance.GetAvailableFonts();
var font = all_fonts.FirstOrDefault(f => f.fontName == "Arial");
if (!string.IsNullOrEmpty(font.fontName))
{
var textSym5 = SymbolFactory.Instance.ConstructTextSymbol(font.fontName);
//or with a font+style
var textSym6 = SymbolFactory.Instance.ConstructTextSymbol(
font.fontName, font.fontStyles.First());
}

//overloads - font + color and size, etc
var textSym7 = SymbolFactory.Instance.ConstructTextSymbol(
ColorFactory.Instance.BlueRGB, 14, "Times New Roman", "Italic");

//custom symbol - black stroke, red fill
var poly_symbol = SymbolFactory.Instance.ConstructPolygonSymbol(
SymbolFactory.Instance.ConstructSolidFill(ColorFactory.Instance.RedRGB),
SymbolFactory.Instance.ConstructStroke(ColorFactory.Instance.BlackRGB, 1));
var textSym8 = SymbolFactory.Instance.ConstructTextSymbol(
poly_symbol, 14, "Georgia", "Bold");

});

为给定符号创建色板

1
2
3
4
5
6
7
8
9
10
//Note: call within QueuedTask.Run()
CIMSymbol symbol = SymbolFactory.Instance.ConstructPointSymbol(ColorFactory.Instance.GreenRGB, 1.0, SimpleMarkerStyle.Circle);
//You can generate a swatch for a text symbols also.
var si = new SymbolStyleItem()
{
Symbol = symbol,
PatchHeight = 64,
PatchWidth = 64
};
return si.PreviewImage;

查找符号

1
2
3
4
5
6
7
8
9
10
11
12
13
//Note: Run within QueuedTask.Run
//Get the selection
var selection = featureLayer.GetSelection();
//Get the first Object ID
var firstOID = selection.GetObjectIDs().FirstOrDefault();
//Determine whether the layer's renderer type supports symbol lookup.
if (featureLayer.CanLookupSymbol())
{
//Looks up the symbol for the corresponding feature identified by the object id.
var symbol = featureLayer.LookupSymbol(firstOID, MapView.Active);
var jSon = symbol.ToJson(); //Create a JSON encoding of the symbol
//Do something with symbol
}

符号搜索

如何在样式中搜索特定项目

1
2
3
4
5
6
7
8
9
10
11
12
public Task<SymbolStyleItem> GetSymbolFromStyleAsync(StyleProjectItem style, string key)
{
return QueuedTask.Run(() =>
{
if (style == null)
throw new System.ArgumentNullException();

//Search for a specific point symbol in style
SymbolStyleItem item = (SymbolStyleItem)style.LookupItem(StyleItemType.PointSymbol, key);
return item;
});
}

如何在样式中搜索点符号

1
2
3
4
5
6
7
8
public Task<IList<SymbolStyleItem>> GetPointSymbolsFromStyleAsync(StyleProjectItem style, string searchString)
{
if (style == null)
throw new System.ArgumentNullException();

//Search for point symbols
return QueuedTask.Run(() => style.SearchSymbols(StyleItemType.PointSymbol, searchString));
}

如何在样式中搜索线符号

1
2
3
4
5
6
7
8
public Task<IList<SymbolStyleItem>> GetLineSymbolsFromStyleAsync(StyleProjectItem style, string searchString)
{
if (style == null)
throw new System.ArgumentNullException();

//Search for line symbols
return QueuedTask.Run(() => style.SearchSymbols(StyleItemType.LineSymbol, searchString));
}

如何在样式中搜索面符号

1
2
3
4
5
6
7
8
public async Task<IList<SymbolStyleItem>> GetPolygonSymbolsFromStyleAsync(StyleProjectItem style, string searchString)
{
if (style == null)
throw new System.ArgumentNullException();

//Search for polygon symbols
return await QueuedTask.Run(() => style.SearchSymbols(StyleItemType.PolygonSymbol, searchString));
}

如何在样式中搜索颜色

1
2
3
4
5
6
7
8
public async Task<IList<ColorStyleItem>> GetColorsFromStyleAsync(StyleProjectItem style, string searchString)
{
if (style == null)
throw new System.ArgumentNullException();

//Search for colors
return await QueuedTask.Run(() => style.SearchColors(searchString));
}

如何在样式中搜索色带

1
2
3
4
5
6
7
8
9
10
public async Task<IList<ColorRampStyleItem>> GetColorRampsFromStyleAsync(StyleProjectItem style, string searchString)
{
//StyleProjectItem can be "ColorBrewer Schemes (RGB)", "ArcGIS 2D"...
if (style == null)
throw new System.ArgumentNullException();

//Search for color ramps
//Color Ramp searchString can be "Spectral (7 Classes)", "Pastel 1 (3 Classes)", "Red-Gray (10 Classes)"..
return await QueuedTask.Run(() => style.SearchColorRamps(searchString));
}

如何在样式中搜索指北针

1
2
3
4
5
6
7
8
public Task<IList<NorthArrowStyleItem>> GetNorthArrowsFromStyleAsync(StyleProjectItem style, string searchString)
{
if (style == null)
throw new System.ArgumentNullException();

//Search for north arrows
return QueuedTask.Run(() => style.SearchNorthArrows(searchString));
}

如何在样式中搜索比例尺

1
2
3
4
5
6
7
8
public Task<IList<ScaleBarStyleItem>> GetScaleBarsFromStyleAsync(StyleProjectItem style, string searchString)
{
if (style == null)
throw new System.ArgumentNullException();

//Search for scale bars
return QueuedTask.Run(() => style.SearchScaleBars(searchString));
}

如何在样式中搜索标签展示位置

1
2
3
4
5
6
7
8
public Task<IList<LabelPlacementStyleItem>> GetLabelPlacementsFromStyleAsync(StyleProjectItem style, string searchString)
{
if (style == null)
throw new System.ArgumentNullException();

//Search for standard label placement
return QueuedTask.Run(() => style.SearchLabelPlacements(StyleItemType.StandardLabelPlacement, searchString));
}

如何在样式中搜索图例

1
2
3
4
5
6
7
public Task<IList<LegendStyleItem>> GetLegendFromStyleAsync(StyleProjectItem style, string searchString)
{
if (style == null)
throw new System.ArgumentNullException();

return QueuedTask.Run(() => style.SearchLegends(searchString));
}

如何在样式中搜索图例项

1
2
3
4
5
6
7
public Task<IList<LegendItemStyleItem>> GetLegendItemsFromStyleAsync(StyleProjectItem style, string searchString)
{
if (style == null)
throw new System.ArgumentNullException();

return QueuedTask.Run(() => style.SearchLegendItems(searchString));
}

如何在样式中搜索网格

1
2
3
4
5
6
7
public Task<IList<GridStyleItem>> GetGridsFromStyleAsync(StyleProjectItem style, string searchString)
{
if (style == null)
throw new System.ArgumentNullException();

return QueuedTask.Run(() => style.SearchGrids(searchString));
}

如何在样式中搜索地图整饰

1
2
3
4
5
6
7
public Task<IList<MapSurroundStyleItem>> GetMapSurroundsFromStyleAsync(StyleProjectItem style, string searchString)
{
if (style == null)
throw new System.ArgumentNullException();

return QueuedTask.Run(() => style.SearchMapSurrounds(searchString));
}

如何在样式中搜索表格框

1
2
3
4
5
6
7
public Task<IList<TableFrameStyleItem>> GetTableFramesFromStyleAsync(StyleProjectItem style, string searchString)
{
if (style == null)
throw new System.ArgumentNullException();

return QueuedTask.Run(() => style.SearchTableFrames(searchString));
}

如何在样式中搜索表格框字段

1
2
3
4
5
6
7
public Task<IList<TableFrameFieldStyleItem>> GetTableFrameFieldsFromStyleAsync(StyleProjectItem style, string searchString)
{
if (style == null)
throw new System.ArgumentNullException();

return QueuedTask.Run(() => style.SearchTableFrameFields(searchString));
}

要素图层符号系统

如何为使用简单渲染器符号化的要素图层设置符号

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
public Task SetFeatureLayerSymbolAsync(FeatureLayer ftrLayer, CIMSymbol symbolToApply)
{
if (ftrLayer == null || symbolToApply == null)
throw new System.ArgumentNullException();

return QueuedTask.Run(() =>
{

//Get simple renderer from the feature layer
CIMSimpleRenderer currentRenderer = ftrLayer.GetRenderer() as CIMSimpleRenderer;
if (currentRenderer == null)
return;

//Set symbol's real world setting to be the same as that of the feature layer
symbolToApply.SetRealWorldUnits(ftrLayer.UsesRealWorldSymbolSizes);

//Update the symbol of the current simple renderer
currentRenderer.Symbol = symbolToApply.MakeSymbolReference();
//Update the feature layer renderer
ftrLayer.SetRenderer(currentRenderer);
});
}

如何将样式中的符号应用于要素图层

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
public Task SetFeatureLayerSymbolFromStyleItemAsync(
FeatureLayer ftrLayer, SymbolStyleItem symbolItem)
{
if (ftrLayer == null || symbolItem == null)
throw new System.ArgumentNullException();

return QueuedTask.Run(() =>
{
//Get simple renderer from the feature layer
CIMSimpleRenderer currentRenderer = ftrLayer.GetRenderer() as CIMSimpleRenderer;
if (currentRenderer == null)
return;
//Get symbol from the SymbolStyleItem
CIMSymbol symbol = symbolItem.Symbol;

//Set symbol's real world setting to be the same as that of the feature layer
symbol.SetRealWorldUnits(ftrLayer.UsesRealWorldSymbolSizes);

//Update the symbol of the current simple renderer
currentRenderer.Symbol = symbol.MakeSymbolReference();
//Update the feature layer renderer
ftrLayer.SetRenderer(currentRenderer);
});
}

如何将样式中的点符号应用于要素图层

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
// var map = MapView.Active.Map;
// if (map == null)
// return;
// var pointFeatureLayer =
// map.GetLayersAsFlattenedList()
// .OfType<FeatureLayer>()
// .Where(fl => fl.ShapeType == esriGeometryType.esriGeometryPoint);
// await ApplySymbolToFeatureLayerAsync(pointFeatureLayer.FirstOrDefault(), "Fire Station");

public Task ApplySymbolToFeatureLayerAsync(FeatureLayer featureLayer, string symbolName)
{
return QueuedTask.Run(async () =>
{
//Get the ArcGIS 2D System style from the Project
var arcGIS2DStyle =
Project.Current.GetItems<StyleProjectItem>().FirstOrDefault(s => s.Name == "ArcGIS 2D");

//Search for the symbolName style items within the ArcGIS 2D style project item.
var items = await QueuedTask.Run(() =>
arcGIS2DStyle.SearchSymbols(StyleItemType.PointSymbol, symbolName));

//Gets the CIMSymbol
CIMSymbol symbol = items.FirstOrDefault().Symbol;

//Get the renderer of the point feature layer
CIMSimpleRenderer renderer = featureLayer.GetRenderer() as CIMSimpleRenderer;

//Set symbol's real world setting to be the same as that of the feature layer
symbol.SetRealWorldUnits(featureLayer.UsesRealWorldSymbolSizes);

//Apply the symbol to the feature layer's current renderer
renderer.Symbol = symbol.MakeSymbolReference();

//Appy the renderer to the feature layer
featureLayer.SetRenderer(renderer);
});
}

如何将样式的色带应用于要素图层

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
public async Task ApplyColorRampAsync(FeatureLayer featureLayer, List<string> fields)
{

StyleProjectItem style =
Project.Current.GetItems<StyleProjectItem>()
.FirstOrDefault(s => s.Name == "ColorBrewer Schemes (RGB)");
if (style == null) return;
var colorRampList = await QueuedTask.Run(() =>
style.SearchColorRamps("Red-Gray (10 Classes)"));
if (colorRampList == null || colorRampList.Count == 0) return;
CIMColorRamp cimColorRamp = null;
CIMRenderer renderer = null;
await QueuedTask.Run(() =>
{
cimColorRamp = colorRampList[0].ColorRamp;
var rendererDef = new UniqueValueRendererDefinition(fields, null, cimColorRamp);
renderer = featureLayer?.CreateRenderer(rendererDef);
featureLayer?.SetRenderer(renderer);
});

}

地图创作-注释片段

创建注记构造工具

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
//In your config.daml...set the categoryRefID
//<tool id="..." categoryRefID="esri_editing_construction_annotation" caption="Create Anno" ...>

//Sketch type Point or Line or BezierLine in the constructor...
//internal class AnnoConstructionTool : MapTool {
// public AnnoConstructionTool() {
// IsSketchTool = true;
// UseSnapping = true;
// SketchType = SketchGeometryType.Point;
//

protected async override Task<bool> OnSketchCompleteAsync(Geometry geometry)
{
if (CurrentTemplate == null || geometry == null)
return false;

// Create an edit operation
var createOperation = new EditOperation();
createOperation.Name = string.Format("Create {0}", CurrentTemplate.Layer.Name);
createOperation.SelectNewFeatures = true;

// update the geometry point into a 2 point line
//annotation needs at minimum a 2 point line for the text to be placed
double tol = 0.01;
var polyline = await CreatePolylineFromPointAsync((MapPoint)geometry, tol);

// Queue feature creation
createOperation.Create(CurrentTemplate, polyline);

// Execute the operation
return await createOperation.ExecuteAsync();
}

internal Task<Polyline> CreatePolylineFromPointAsync(MapPoint pt, double tolerance)
{
return QueuedTask.Run(() =>
{
// create a polyline from a starting point
//use a tolerance to construct the second point
MapPoint pt2 = MapPointBuilderEx.CreateMapPoint(pt.X + tolerance, pt.Y, pt.SpatialReference);
return PolylineBuilderEx.CreatePolyline(new List<MapPoint>() { pt, pt2 });
});
}

通过属性更新批注文本。警告:TEXTSTRING Anno 属性必须存在

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
//See "Change Annotation Text Graphic" for an alternative if TEXTSTRING is missing from the schema
await QueuedTask.Run(() =>
{
//annoLayer is ~your~ Annotation layer...

// use the inspector methodology
var insp = new Inspector();
insp.Load(annoLayer, oid);

// make sure TextString attribute exists.
//It is not guaranteed to be in the schema
ArcGIS.Desktop.Editing.Attributes.Attribute att = insp.FirstOrDefault(a => a.FieldName == "TEXTSTRING");
if (att != null)
{
insp["TEXTSTRING"] = "Hello World";

//create and execute the edit operation
EditOperation op = new EditOperation();
op.Name = "Update annotation";
op.Modify(insp);

//OR using a Dictionary - again TEXTSTRING has to exist in the schema
//Dictionary<string, object> newAtts = new Dictionary<string, object>();
//newAtts.Add("TEXTSTRING", "hello world");
//op.Modify(annoLayer, oid, newAtts);

op.Execute();
}
});

旋转或移动批注

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
await QueuedTask.Run(() =>
{
//Don't use 'Shape'....Shape is the bounding box of the annotation text. This is NOT what you want...
//
//var insp = new Inspector();
//insp.Load(annoLayer, oid);
//var shape = insp["SHAPE"] as Polygon;
//...wrong shape...

//Instead, we must get the TextGraphic from the anno feature.
//The TextGraphic shape will be the anno baseline...
//At 2.1 the only way to retrieve this textLine is to obtain the TextGraphic from the AnnotationFeature
QueryFilter qf = new QueryFilter()
{
WhereClause = "OBJECTID = 1"
};

//annoLayer is ~your~ Annotation layer

using (var rowCursor = annoLayer.Search(qf))
{
if (rowCursor.MoveNext())
{
using (var annoFeature = rowCursor.Current as
ArcGIS.Core.Data.Mapping.AnnotationFeature)
{
var graphic = annoFeature.GetGraphic();
var textGraphic = graphic as CIMTextGraphic;
var textLine = textGraphic.Shape as Polyline;
// rotate the shape 90 degrees
var origin = GeometryEngine.Instance.Centroid(textLine);
Geometry rotatedPolyline = GeometryEngine.Instance.Rotate(textLine, origin, System.Math.PI / 2);
//Move the line 5 "units" in the x and y direction
//GeometryEngine.Instance.Move(textLine, 5, 5);

EditOperation op = new EditOperation();
op.Name = "Change annotation angle";
op.Modify(annoLayer, oid, rotatedPolyline);
op.Execute();
}
}
}
});

获取批注文本图形

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
await QueuedTask.Run(() =>
{
using (var table = annoLayer.GetTable())
{
using (var rc = table.Search())
{
rc.MoveNext();
using (var af = rc.Current as AnnotationFeature)
{
var graphic = af.GetGraphic();
var textGraphic = graphic as CIMTextGraphic;

//Note:
//var outline_geom = af.GetGraphicOutline();
//gets the anno text outline geometry...
}
}
}
});

获取注释的轮廓几何图形

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
var annoLayer = MapView.Active.Map.GetLayersAsFlattenedList()
.OfType<AnnotationLayer>().FirstOrDefault();
if (annoLayer == null)
return;

QueuedTask.Run(() =>
{
//get the first annotation feature...
//...assuming at least one feature gets selected
using (var fc = annoLayer.GetFeatureClass())
{
using (var rc = fc.Search())
{
rc.MoveNext();
using (var af = rc.Current as AnnotationFeature)
{
var outline_geom = af.GetGraphicOutline();
//TODO - use the outline...

//Note:
//var graphic = annoFeature.GetGraphic();
//gets the CIMTextGraphic...
}
}
}
});

获取注释的遮罩几何图形

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
var annoLayer = MapView.Active.Map.GetLayersAsFlattenedList()
.OfType<AnnotationLayer>().FirstOrDefault();
if (annoLayer == null)
return;
var mv = MapView.Active;

QueuedTask.Run(() =>
{
//get the first annotation feature...
//...assuming at least one feature gets selected
using (var fc = annoLayer.GetFeatureClass())
{
using (var rc = fc.Search())
{
rc.MoveNext();
using (var row = rc.Current)
{
var oid = row.GetObjectID();

//Use DrawingOutlineType.BoundingEnvelope to retrieve a generalized
//mask geometry or "Box". The mask will be in the same SpatRef as the map.
//The mask will be constructed using the anno class reference scale
//At 2.x - var mask_geom = annoLayer.QueryDrawingOutline(oid, mv, DrawingOutlineType.Exact);

var mask_geom = annoLayer.GetDrawingOutline(oid, mv, DrawingOutlineType.Exact);
}
}
}
});

地图创作标记代码段

获取活动地图的标注引擎 - Maplex 或标准标注引擎

1
2
3
4
5
6
//Note: call within QueuedTask.Run()

//Get the active map's definition - CIMMap.
var cimMap = MapView.Active.Map.GetDefinition();
//Get the labeling engine from the map definition
CIMGeneralPlacementProperties labelEngine = cimMap.GeneralPlacementProperties;

将活动地图的标注引擎从标准更改为 Maplex,反之亦然

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
//Note: call within QueuedTask.Run()

//Get the active map's definition - CIMMap.
var cimMap = MapView.Active.Map.GetDefinition();
//Get the labeling engine from the map definition
var cimGeneralPlacement = cimMap.GeneralPlacementProperties;

if (cimGeneralPlacement is CIMMaplexGeneralPlacementProperties)
{
//Current labeling engine is Maplex labeling engine
//Create a new standard label engine properties
var cimStandardPlacementProperties = new CIMStandardGeneralPlacementProperties();
//Set the CIMMap's GeneralPlacementProperties to the new label engine
cimMap.GeneralPlacementProperties = cimStandardPlacementProperties;
}
else
{
//Current labeling engine is Standard labeling engine
//Create a new Maplex label engine properties
var cimMaplexGeneralPlacementProperties = new CIMMaplexGeneralPlacementProperties();
//Set the CIMMap's GeneralPlacementProperties to the new label engine
cimMap.GeneralPlacementProperties = cimMaplexGeneralPlacementProperties;
}
//Set the map's definition
MapView.Active.Map.SetDefinition(cimMap);

将文本符号应用于要素图层

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
//Note: call within QueuedTask.Run()

//Get the layer's definition
var lyrDefn = featureLayer.GetDefinition() as CIMFeatureLayer;
//Get the label classes - we need the first one
var listLabelClasses = lyrDefn.LabelClasses.ToList();
var theLabelClass = listLabelClasses.FirstOrDefault();
//Set the label classes' symbol to the custom text symbol
//Refer to the ProSnippets-TextSymbols wiki page for help with creating custom text symbols.
//Example: var textSymbol = await CreateTextSymbolWithHaloAsync();
theLabelClass.TextSymbol.Symbol = textSymbol;
lyrDefn.LabelClasses = listLabelClasses.ToArray(); //Set the labelClasses back
featureLayer.SetDefinition(lyrDefn); //set the layer's definition
//set the label's visiblity
featureLayer.SetLabelVisibility(true);

启用图层标注

1
2
3
4
5
//Note: call within QueuedTask.Run()

if (!featureLayer.IsLabelVisible)
//set the label's visiblity
featureLayer.SetLabelVisibility(true);

修改标签的位置/位置 - 点几何

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
//Note: call within QueuedTask.Run()

//Get the layer's definition
var lyrDefn = featureLayer.GetDefinition() as CIMFeatureLayer;
//Get the label classes - we need the first one
var listLabelClasses = lyrDefn.LabelClasses.ToList();
var theLabelClass = listLabelClasses.FirstOrDefault();

//Modify label Placement
//Check if the label engine is Maplex or standard.
CIMGeneralPlacementProperties labelEngine =
MapView.Active.Map.GetDefinition().GeneralPlacementProperties;
if (labelEngine is CIMStandardGeneralPlacementProperties) //Current labeling engine is Standard labeling engine
theLabelClass.StandardLabelPlacementProperties.PointPlacementMethod =
StandardPointPlacementMethod.OnTopPoint;
else //Current labeling engine is Maplex labeling engine
theLabelClass.MaplexLabelPlacementProperties.PointPlacementMethod =
MaplexPointPlacementMethod.CenteredOnPoint;

lyrDefn.LabelClasses = listLabelClasses.ToArray(); //Set the labelClasses back
featureLayer.SetDefinition(lyrDefn); //set the layer's definition

修改标签的位置/位置 - 线几何

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
//Note: call within QueuedTask.Run()

//Get the layer's definition
var lyrDefn = featureLayer.GetDefinition() as CIMFeatureLayer;
//Get the label classes - we need the first one
var listLabelClasses = lyrDefn.LabelClasses.ToList();
var theLabelClass = listLabelClasses.FirstOrDefault();
//Modify label Placement
//Check if the label engine is Maplex or standard.
CIMGeneralPlacementProperties labelEngine =
MapView.Active.Map.GetDefinition().GeneralPlacementProperties;
if (labelEngine is CIMStandardGeneralPlacementProperties)
{
//Current labeling engine is Standard labeling engine
var lineLablePosition = new CIMStandardLineLabelPosition
{
Perpendicular = true,
Parallel = false,
ProduceCurvedLabels = false,
Horizontal = false,
OnTop = true
};
theLabelClass.StandardLabelPlacementProperties.LineLabelPosition =
lineLablePosition;
}
else //Current labeling engine is Maplex labeling engine
{
theLabelClass.MaplexLabelPlacementProperties.LinePlacementMethod =
MaplexLinePlacementMethod.CenteredPerpendicularOnLine;
theLabelClass.MaplexLabelPlacementProperties.LineFeatureType =
MaplexLineFeatureType.General;
}
//theLabelClass.MaplexLabelPlacementProperties.LinePlacementMethod = MaplexLinePlacementMethod.CenteredPerpendicularOnLine;
lyrDefn.LabelClasses = listLabelClasses.ToArray(); //Set the labelClasses back
featureLayer.SetDefinition(lyrDefn); //set the layer's definition

修改标注的位置/位置 - 多边形几何

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
//Note: call within QueuedTask.Run()

//Get the layer's definition
var lyrDefn = featureLayer.GetDefinition() as CIMFeatureLayer;
//Get the label classes - we need the first one
var listLabelClasses = lyrDefn.LabelClasses.ToList();
var theLabelClass = listLabelClasses.FirstOrDefault();
//Modify label Placement
//Check if the label engine is Maplex or standard.
CIMGeneralPlacementProperties labelEngine = MapView.Active.Map.GetDefinition().GeneralPlacementProperties;
if (labelEngine is CIMStandardGeneralPlacementProperties)
{
//Current labeling engine is Standard Labeling engine
theLabelClass.StandardLabelPlacementProperties.PolygonPlacementMethod =
StandardPolygonPlacementMethod.AlwaysHorizontal;
theLabelClass.StandardLabelPlacementProperties.PlaceOnlyInsidePolygon = true;
}
else
{
//Current labeling engine is Maplex labeling engine
theLabelClass.MaplexLabelPlacementProperties.PolygonFeatureType =
MaplexPolygonFeatureType.LandParcel;
theLabelClass.MaplexLabelPlacementProperties.AvoidPolygonHoles = true;
theLabelClass.MaplexLabelPlacementProperties.PolygonPlacementMethod =
MaplexPolygonPlacementMethod.HorizontalInPolygon;
theLabelClass.MaplexLabelPlacementProperties.CanPlaceLabelOutsidePolygon = true;
}

lyrDefn.LabelClasses = listLabelClasses.ToArray(); //Set the labelClasses back
featureLayer.SetDefinition(lyrDefn); //set the layer's definition
//set the label's visiblity
featureLayer.SetLabelVisibility(true);

使用 MaplexEngine 修改标注的方向 - 点和面几何

1
2
3
4
5
6
7
8
9
10
11
12
13
//Note: call within QueuedTask.Run()

//Get the layer's definition
var lyrDefn = featureLayer.GetDefinition() as CIMFeatureLayer;
//Get the label classes - we need the first one
var listLabelClasses = lyrDefn.LabelClasses.ToList();
var theLabelClass = listLabelClasses.FirstOrDefault();
//Modify label Orientation
theLabelClass.MaplexLabelPlacementProperties.GraticuleAlignment = true;
theLabelClass.MaplexLabelPlacementProperties.GraticuleAlignmentType = MaplexGraticuleAlignmentType.Curved;

lyrDefn.LabelClasses = listLabelClasses.ToArray(); //Set the labelClasses back
featureLayer.SetDefinition(lyrDefn); //set the layer's definition

使用 MaplexEngine - 线几何修改标注的方向

1
2
3
4
5
6
7
8
9
10
11
12
//Note: call within QueuedTask.Run()

//Get the layer's definition
var lyrDefn = featureLayer.GetDefinition() as CIMFeatureLayer;
//Get the label classes - we need the first one
var listLabelClasses = lyrDefn.LabelClasses.ToList();
var theLabelClass = listLabelClasses.FirstOrDefault();
//Modify label Orientation
theLabelClass.MaplexLabelPlacementProperties.AlignLabelToLineDirection = true;

lyrDefn.LabelClasses = listLabelClasses.ToArray(); //Set the labelClasses back
featureLayer.SetDefinition(lyrDefn); //set the layer's definition

修改标签旋转 - 点几何

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
//Note: call within QueuedTask.Run()

//Get the layer's definition
var lyrDefn = featureLayer.GetDefinition() as CIMFeatureLayer;
//Get the label classes - we need the first one
var listLabelClasses = lyrDefn.LabelClasses.ToList();
var theLabelClass = listLabelClasses.FirstOrDefault();
//Modify label Rotation
CIMMaplexRotationProperties rotationProperties = new CIMMaplexRotationProperties
{
Enable = true, //Enable rotation
RotationField = "ELEVATION", //Field that is used to define rotation angle
AdditionalAngle = 15, //Additional rotation
RotationType = MaplexLabelRotationType.Arithmetic,
AlignmentType = MaplexRotationAlignmentType.Perpendicular,
AlignLabelToAngle = true
};
theLabelClass.MaplexLabelPlacementProperties.RotationProperties = rotationProperties;
lyrDefn.LabelClasses = listLabelClasses.ToArray(); //Set the labelClasses back
featureLayer.SetDefinition(lyrDefn); //set the layer's definition

在多边形几何中展开标注

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
//Note: call within QueuedTask.Run()

//Get the layer's definition
var lyrDefn = featureLayer.GetDefinition() as CIMFeatureLayer;
//Get the label classes - we need the first one
var listLabelClasses = lyrDefn.LabelClasses.ToList();
var theLabelClass = listLabelClasses.FirstOrDefault();
//Spread Labels (words and characters to fill feature)
// Spread words to fill feature
theLabelClass.MaplexLabelPlacementProperties.SpreadWords = true;
//Spread Characters to a fixed limit of 50%
theLabelClass.MaplexLabelPlacementProperties.SpreadCharacters = true;
theLabelClass.MaplexLabelPlacementProperties.MaximumCharacterSpacing = 50.0;
lyrDefn.LabelClasses = listLabelClasses.ToArray(); //Set the labelClasses back
featureLayer.SetDefinition(lyrDefn); //set the layer's definition

修改标签的引出线锚点属性 - 多边形几何

1
2
3
4
5
6
7
8
9
10
11
//Note: call within QueuedTask.Run()

//Get the layer's definition
var lyrDefn = featureLayer.GetDefinition() as CIMFeatureLayer;
//Get the label classes - we need the first one
var listLabelClasses = lyrDefn.LabelClasses.ToList();
var theLabelClass = listLabelClasses.FirstOrDefault();
//If TextSymbol is a callout the leader line anachor point can be modified
theLabelClass.MaplexLabelPlacementProperties.PolygonAnchorPointType = MaplexAnchorPointType.Perimeter;
lyrDefn.LabelClasses = listLabelClasses.ToArray(); //Set the labelClasses back
featureLayer.SetDefinition(lyrDefn); //set the layer's definition

地图创作-体素图层

创建体素图层

检查是否可以创建体素图层

1
2
3
4
5
6
7
//Map must be a local scene
bool canCreateVoxel = (MapView.Active.ViewingMode == MapViewingMode.SceneLocal);

if (canCreateVoxel)
{
//TODO - use the voxel api methods
}

创建体素图层

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
//Must be on the QueuedTask.Run()

//Must be a .NetCDF file for voxels
var url = @"C:\MyData\AirQuality_Redlands.nc";
var cim_connection = new CIMVoxelDataConnection()
{
URI = url
};
//Create a VoxelLayerCreationParams
var createParams = VoxelLayerCreationParams.Create(cim_connection);
createParams.IsVisible = true;

//Can also just use the path directly...
//var createParams = VoxelLayerCreationParams.Create(url);

//Use VoxelLayerCreationParams to enumerate the variables within
//the voxel
var variables = createParams.Variables;
foreach (var variable in variables)
{
var line = $"{variable.Variable}: {variable.DataType}, " +
$"{variable.Description}, {variable.IsDefault}, {variable.IsSelected}";
System.Diagnostics.Debug.WriteLine(line);
}
//Optional: set the default variable
createParams.SetDefaultVariable(variables.Last());

//Create the layer - map must be a local scene
VoxelLayer voxelLayer = LayerFactory.Instance.CreateLayer<VoxelLayer>(createParams, map);

体素图层设置和属性

从目录中获取体素图层

1
2
3
4
5
6
7
8
9
//Get selected layer if a voxel layer is selected
var voxelLayer = MapView.Active.GetSelectedLayers().OfType<VoxelLayer>().FirstOrDefault();
if (voxelLayer == null)
{
//just get the first voxel layer in the TOC
voxelLayer = MapView.Active.Map.GetLayersAsFlattenedList().OfType<VoxelLayer>().FirstOrDefault();
if (voxelLayer == null)
return;
}

操作体素图层目录组

1
2
3
4
5
6
7
8
9
10
11
12
13
14
//var voxelLayer = ...
//Must be on the QueuedTask.Run()

//Toggle containers and visibility in the TOC
voxelLayer.SetExpanded(!voxelLayer.IsExpanded);
voxelLayer.SetVisibility(!voxelLayer.IsVisible);
voxelLayer.SetIsosurfaceContainerExpanded(!voxelLayer.IsIsosurfaceContainerExpanded);
voxelLayer.SetIsosurfaceContainerVisibility(!voxelLayer.IsIsosurfaceContainerVisible);
voxelLayer.SetSliceContainerExpanded(voxelLayer.IsSliceContainerExpanded);
voxelLayer.SetSliceContainerVisibility(!voxelLayer.IsSliceContainerVisible);
voxelLayer.SetSectionContainerExpanded(!voxelLayer.IsSectionContainerExpanded);
voxelLayer.SetSectionContainerVisibility(!voxelLayer.IsSectionContainerVisible);
voxelLayer.SetLockedSectionContainerExpanded(!voxelLayer.IsLockedSectionContainerExpanded);
voxelLayer.SetLockedSectionContainerVisibility(!voxelLayer.IsLockedSectionContainerVisible);

从目录中获取/设置选定的体素资源

1
2
3
4
5
6
7
8
var surfaces = MapView.Active.GetSelectedIsosurfaces();
//set selected w/ MapView.Active.SelectVoxelIsosurface(isoSurface)
var slices = MapView.Active.GetSelectedSlices();
//set selected w/ MapView.Active.SelectVoxelSlice(slice)
var sections = MapView.Active.GetSelectedSections();
//set selected w/ MapView.Active.SelectVoxelSection(section)
var locked_sections = MapView.Active.GetSelectedLockedSections();
//set selected w/ MapView.Active.SelectVoxelLockedSection(locked_section)

更改体素可视化效果

1
2
3
4
5
6
7
8
9
10
//var voxelLayer = ... ;
//Must be on the QueuedTask.Run()

//Change the visualization to Volume
//e.g. for creating slices
voxelLayer.SetVisualization(VoxelVisualization.Volume);

//Change the visualization to Surface
//e.g. to create isosurfaces and sections
voxelLayer.SetVisualization(VoxelVisualization.Surface);

照明属性、偏移、垂直夸大

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
//var voxelLayer = ... ;
//Must be on the QueuedTask.Run()

//Offset
var offset = voxelLayer.CartographicOffset;
//apply an offset
voxelLayer.SetCartographicOffset(offset + 100.0);

//VerticalExaggeration
var exaggeration = voxelLayer.VerticalExaggeration;
//apply an exaggeration
voxelLayer.SetVerticalExaggeration(exaggeration + 100.0);

//Change the exaggeration mode to "ScaleZ" - corresponds to 'Z-coordinates'
//on the Layer properties UI - must use the CIM
var def = voxelLayer.GetDefinition() as CIMVoxelLayer;
def.Layer3DProperties.ExaggerationMode = ExaggerationMode.ScaleZ;
//can set vertical exaggeration via the CIM also
//def.Layer3DProperties.VerticalExaggeration = exaggeration + 100.0;

//apply the change
voxelLayer.SetDefinition(def);

//Diffuse Lighting
if (!voxelLayer.IsDiffuseLightingEnabled)
voxelLayer.SetDiffuseLightingEnabled(true);
var diffuse = voxelLayer.DiffuseLighting;
//set Diffuse lighting to a value between 0 and 1
voxelLayer.SetDiffuseLighting(0.5); //50%

//Specular Lighting
if (!voxelLayer.IsSpecularLightingEnabled)
voxelLayer.SetSpecularLightingEnabled(true);
var specular = voxelLayer.SpecularLighting;
//set Diffuse lighting to a value between 0 and 1
voxelLayer.SetSpecularLighting(0.5); //50%

获取体素体积维度

1
2
3
4
5
6
7
8
9
10
11
12
13
//At 2.x - var volume = voxelLayer.GetVolumeSize();
//var x_max = volume.Item1;
//var y_max = volume.Item2;
//var z_max = volume.Item3;

var x_max = voxelLayer.GetVolumes().Max(v => v.GetVolumeSize().X);
var y_max = voxelLayer.GetVolumes().Max(v => v.GetVolumeSize().Y);
var z_max = voxelLayer.GetVolumes().Max(v => v.GetVolumeSize().Z);

//Get the dimensions of just one volume
var dimensions = voxelLayer.GetVolumes().FirstOrDefault();
//Get the dimensions of the volume associated with the selected variable
var dimensions2 = voxelLayer.SelectedVariableProfile.Volume.GetVolumeSize();

事件

订阅对体素图层的更改

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
ArcGIS.Desktop.Mapping.Events.MapMemberPropertiesChangedEvent.Subscribe((args) =>
{
var voxel = args.MapMembers.OfType<VoxelLayer>().FirstOrDefault();
if (voxel == null)
return;
//Anything changed on a voxel layer?
//At 2.x - if (args.EventHints.Any(hint => hint == MapMemberEventHint.VoxelSelectedVariableProfileIndex))
if (args.EventHints.Any(hint => hint == MapMemberEventHint.VoxelSelectedVariable))
{
//Voxel variable profile selection changed
var changed_variable_name = voxel.SelectedVariableProfile.Variable;
//TODO respond to change, use QueuedTask if needed

}
else if (args.EventHints.Any(hint => hint == MapMemberEventHint.Renderer))
{
//This can fire when a renderer becomes ready on a new layer; the selected variable profile
//is changed; visualization is changed, etc.
var renderer = voxel.SelectedVariableProfile.Renderer;
//TODO respond to change, use QueuedTask if needed

}
});

ArcGIS.Desktop.Mapping.Voxel.Events.VoxelAssetChangedEvent.Subscribe((args) =>
{
//An asset changed on a voxel layer
System.Diagnostics.Debug.WriteLine("");
System.Diagnostics.Debug.WriteLine("VoxelAssetChangedEvent");
System.Diagnostics.Debug.WriteLine($" AssetType: {args.AssetType}, ChangeType: {args.ChangeType}");

if (args.ChangeType == VoxelAssetEventArgs.VoxelAssetChangeType.Remove)
return;
//Get "what"changed - add or update
//eg IsoSurface
VoxelLayer voxelLayer = null;
if (args.AssetType == VoxelAssetEventArgs.VoxelAssetType.Isosurface)
{
var surface = MapView.Active.GetSelectedIsosurfaces().FirstOrDefault();
//there will only be one selected...
if (surface != null)
{
voxelLayer = surface.Layer;
//TODO respond to change, use QueuedTask if needed
}
}
//Repeat for Slices, Sections, LockedSections...
//GetSelectedSlices(), GetSelectedSections(), GetSelectedLockedSections();
});

变量配置文件 + 渲染器

获取选定的变量配置文件

1
2
3
4
5
6
7
//var voxelLayer = ... ;
//Must be on the QueuedTask.Run()

var sel_profile = voxelLayer.SelectedVariableProfile;

//Get the variable profile name
var profile_name = sel_profile.Variable;

更改选定的变量配置文件

1
2
3
4
5
6
7
8
9
10
11
//var voxelLayer = ... ;
//Must be on the QueuedTask.Run()

var profiles = voxelLayer.GetVariableProfiles();

//Select any profile as long as it is not the current selected variable
var not_selected = profiles.Where(p => p.Variable != sel_profile.Variable).ToList();
if (not_selected.Count() > 0)
{
voxelLayer.SetSelectedVariableProfile(not_selected.First());
}

获取变量配置文件

1
2
3
4
//var voxelLayer = ... ;
//Must be on the QueuedTask.Run()

var variable_profiles = voxelLayer.GetVariableProfiles();

获取变量渲染器

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
//var voxelLayer = ... ;
//Must be on the QueuedTask.Run()

var variable = voxelLayer.GetVariableProfiles().First();
var renderer = variable.Renderer;
if (variable.DataType == VoxelVariableDataType.Continuous)
{
//Renderer will be stretch
var stretchRenderer = renderer as CIMVoxelStretchRenderer;
//access the renderer

}
else //VoxelVariableDataType.Discrete
{
//Renderer will be unique value
var uvr = renderer as CIMVoxelUniqueValueRenderer;
//access the renderer
}

访问拉伸渲染器的统计信息和颜色范围

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
//var voxelLayer = ... ;
//Must be on the QueuedTask.Run()

//Get the variable profile on which to access the data
var variable = voxelLayer.SelectedVariableProfile;
//or use ...voxelLayer.GetVariableProfiles()

//Data range
//At 2.x -
//var min = variable.GetVariableStatistics().MinimumValue;
//var max = variable.GetVariableStatistics().MaximumValue;

var min = variable.Statistics.MinimumValue;
var max = variable.Statistics.MaximumValue;

//Color range (Continuous only)
double color_min, color_max;
if (variable.DataType == VoxelVariableDataType.Continuous)
{
var renderer = variable.Renderer as CIMVoxelStretchRenderer;
color_min = renderer.ColorRangeMin;
color_max = renderer.ColorRangeMax;
}

更改拉伸渲染器颜色范围

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
//Typically, the default color range covers the most
//commonly occuring voxel values. Usually, the data
//range is much broader than the color range

//Get the variable profile whose renderer will be changed
var variable = voxelLayer.SelectedVariableProfile;

//Check DataType
if (variable.DataType != VoxelVariableDataType.Continuous)
return;//must be continuous to have a Stretch Renderer...

var renderer = variable.Renderer as CIMVoxelStretchRenderer;
var color_min = renderer.ColorRangeMin;
var color_max = renderer.ColorRangeMax;
//increase range by 10% of the current difference
var dif = (color_max - color_min) * 0.05;
color_min -= dif;
color_max += dif;

//make sure we do not exceed data range
//At 2.x -
//if (color_min < variable.GetVariableStatistics().MinimumValue)
// color_min = variable.GetVariableStatistics().MinimumValue;
//if (color_max > variable.GetVariableStatistics().MaximumValue)
// color_max = variable.GetVariableStatistics().MaximumValue;

if (color_min < variable.Statistics.MinimumValue)
color_min = variable.Statistics.MinimumValue;
if (color_max > variable.Statistics.MaximumValue)
color_max = variable.Statistics.MaximumValue;

//variable.Statistics.MinimumValue
renderer.ColorRangeMin = color_min;
renderer.ColorRangeMax = color_max;

//apply changes
variable.SetRenderer(renderer);

更改 CIMVoxelColorUniqueValue 类的可见性

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
//Get the variable profile whose renderer will be changed
var variable = voxelLayer.SelectedVariableProfile;

//Check DataType
if (variable.DataType != VoxelVariableDataType.Discrete)
return;//must be Discrete to have a UV Renderer...

var renderer = variable.Renderer as CIMVoxelUniqueValueRenderer;

//A CIMVoxelUniqueValueRenderer consists of a collection of
//CIMVoxelColorUniqueValue classes - one per discrete value
//in the associated variable profile value array

//Get the first class
var classes = renderer.Classes.ToList();
var unique_value_class = classes.First();
//Set its visibility off
unique_value_class.Visible = false;

//Apply the change to the renderer
renderer.Classes = classes.ToArray();
//apply the changes
variable.SetRenderer(renderer);

等值面

检查变量的最大等值面数

1
2
3
4
5
6
7
8
9
//var voxelLayer = ... ;
//Must be on the QueuedTask.Run()

var variable = voxelLayer.GetVariableProfiles().First();
var max = variable.MaxNumberOfIsosurfaces;
if (max >= variable.GetIsosurfaces().Count)
{
//no more surfaces can be created on this variable
}

检查变量的数据类型

1
2
3
4
5
6
7
8
9
//var voxelLayer = ... ;
//Must be on the QueuedTask.Run()

var variable = voxelLayer.GetVariableProfiles().First();
if (variable.DataType != VoxelVariableDataType.Continuous)
{
//No iso surfaces
//Iso surface can only be created for VoxelVariableDataType.Continuous
}

检查CanCreateIsoSurface

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
//var voxelLayer = ... ;
//Must be on the QueuedTask.Run()

//Visualization must be surface or CanCreateIsosurface will return
//false
if (voxelLayer.Visualization != VoxelVisualization.Surface)
voxelLayer.SetVisualization(VoxelVisualization.Surface);

//Get the variable profile on which to create the iso surface
var variable = voxelLayer.SelectedVariableProfile;
//or use ...voxelLayer.GetVariableProfiles().First(....

// o Visualization must be Surface
// o Variable profile must be continuous
// o Variable MaxNumberofIsoSurfaces must not have been reached...
if (variable.CanCreateIsosurface)
{
//Do the create
}

创建等值面

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
//var voxelLayer = ... ;
//Must be on the QueuedTask.Run()

//Visualization must be surface
if (voxelLayer.Visualization != VoxelVisualization.Surface)
voxelLayer.SetVisualization(VoxelVisualization.Surface);

//Get the variable profile on which to create the iso surface
var variable = voxelLayer.SelectedVariableProfile;

// o Visualization must be Surface
// o Variable profile must be continuous
// o Variable MaxNumberofIsoSurfaces must not have been reached...
if (variable.CanCreateIsosurface)
{
//Note: calling create if variable.CanCreateIsosurface == false
//will trigger an InvalidOperationException

//Specify a voxel value for the iso surface
//At 2.x -
//var min = variable.GetVariableStatistics().MinimumValue;
//var max = variable.GetVariableStatistics().MaximumValue;

var min = variable.Statistics.MinimumValue;
var max = variable.Statistics.MaximumValue;
var mid = (max + min) / 2;

//color range (i.e. values that are being rendered)
var renderer = variable.Renderer as CIMVoxelStretchRenderer;
var color_min = renderer.ColorRangeMin;
var color_max = renderer.ColorRangeMax;

//keep the surface within the current color range (or it
//won't render)
if (mid < color_min)
{
mid = renderer.ColorRangeMin;
}
else if (mid > color_max)
{
mid = renderer.ColorRangeMax;
}

//Create the iso surface
var suffix = Math.Truncate(mid * 100) / 100;
variable.CreateIsosurface(new IsosurfaceDefinition()
{
Name = $"Surface {suffix}",
Value = mid,
IsVisible = true
});
}

如何更改等值面上的值和颜色

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
//var voxelLayer = ... ;
//Must be on the QueuedTask.Run()

var variable = voxelLayer.SelectedVariableProfile;

//Change the color of the first surface for the given profile
var surface = variable.GetIsosurfaces().FirstOrDefault();
if (surface != null)
{
if (voxelLayer.Visualization != VoxelVisualization.Surface)
voxelLayer.SetVisualization(VoxelVisualization.Surface);

//Change the iso surface voxel value
surface.Value = surface.Value * 0.9;

//get a random color
var count = new Random().Next(0, 100);
var colors = ColorFactory.Instance.GenerateColorsFromColorRamp(
((CIMVoxelStretchRenderer)variable.Renderer).ColorRamp, count);

var idx = new Random().Next(0, count - 1);
surface.Color = colors[idx];
//set the custom color flag true to lock the color
//locking the color prevents it from being changed if the
//renderer color range or color theme is updated
surface.IsCustomColor = true;

//update the surface
variable.UpdateIsosurface(surface);
}

将 Isourface 颜色更改回默认值

1
2
3
4
5
6
7
8
9
10
11
12
//var voxelLayer = ... ;
//Must be on the QueuedTask.Run()
//var variable = ...;
//var surface = ...;

if (surface.IsCustomColor)
{
surface.Color = variable.GetIsosurfaceColor((double)surface.Value);
surface.IsCustomColor = false;
//update the surface
variable.UpdateIsosurface(surface);
}

删除等值面

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
//var voxelLayer = ... ;
//Must be on the QueuedTask.Run()

var variable = voxelLayer.SelectedVariableProfile;

//delete the last surface
var last_surface = variable.GetIsosurfaces().LastOrDefault();

if (last_surface != null)
{
variable.DeleteIsosurface(last_surface);
}

//delete all the surfaces
foreach (var surface in variable.GetIsosurfaces())
variable.DeleteIsosurface(surface);

//Optional - set visualization back to Volume
if (variable.GetIsosurfaces().Count() == 0)
{
voxelLayer.SetVisualization(VoxelVisualization.Volume);
}

获取切片集合

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
//var voxelLayer = ... ;
//Must be on the QueuedTask.Run()

//At 2.x - var slices = voxelLayer.GetSlices();

//Use the SelectedVariableProfile to get the slices currently in the TOC
//via its associated volume
var volume = voxelLayer.SelectedVariableProfile.Volume;
var slices = volume.GetSlices();

//Do something... e.g. make them visible
foreach (var slice in slices)
{
slice.IsVisible = true;
//at 2.x - voxelLayer.UpdateSlice(slice);
volume.UpdateSlice(slice);
}

//expand the slice container and make sure container visibility is true
voxelLayer.SetSliceContainerExpanded(true);
voxelLayer.SetSliceContainerVisibility(true);

获取切片

1
2
3
4
5
6
7
8
9
10
11
12
//var voxelLayer = ... ;
//Must be on the QueuedTask.Run()

//At 2.x -
//var slice = voxelLayer.GetSlices().FirstOrDefault();
//var slice2 = voxelLayer.GetSlices().First(s => s.Id == my_slice_id);

//Use the SelectedVariableProfile to get the slices currently in the TOC
//via its associated volume
var volume = voxelLayer.SelectedVariableProfile.Volume;
var slice = volume.GetSlices().FirstOrDefault();
var slice2 = volume.GetSlices().First(s => s.Id == my_slice_id);

获取目录中的选定切片

1
2
3
4
5
6
7
8
9
//Must be on the QueuedTask.Run()

// cref: ArcGIS.Desktop.Mapping.MapView.GetSelectedSlices()
// cref: ArcGIS.Desktop.Mapping.Voxel.SliceDefinition
var slice = MapView.Active?.GetSelectedSlices()?.FirstOrDefault();
if (slice != null)
{

}

获取目录中所选切片的体素图层

1
2
3
4
5
6
7
8
9
//Must be on the QueuedTask.Run()

VoxelLayer voxelLayer = null;
var slice = MapView.Active?.GetSelectedSlices()?.FirstOrDefault();
if (slice != null)
{
voxelLayer = slice.Layer;
//TODO - use the layer
}

创建切片

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
//var voxelLayer = ... ;
//Must be on the QueuedTask.Run()

if (voxelLayer.Visualization != VoxelVisualization.Volume)
voxelLayer.SetVisualization(VoxelVisualization.Volume);
voxelLayer.SetSliceContainerExpanded(true);
voxelLayer.SetSliceContainerVisibility(true);

//To stop the Voxel Exploration Dockpane activating use:
voxelLayer.AutoShowExploreDockPane = false;
//This is useful if u have your own dockpane currently activated...

//At 2.x - var volumeSize = voxelLayer.GetVolumeSize();

//Use the SelectedVariableProfile to get the slices currently in the TOC
//via its associated volume
var volume = voxelLayer.SelectedVariableProfile.Volume;
var volumeSize = volume.GetVolumeSize();

//Orientation 90 degrees (West), Tilt 0.0 (vertical)
//Convert to a normal
var normal = voxelLayer.GetNormal(90, 0.0);

//Create the slice at the voxel mid-point. VoxelPosition
//is specified in voxel-space coordinates

//At 2.x -
//voxelLayer.CreateSlice(new SliceDefinition()
//{
// Name = "Middle Slice",
// VoxelPosition = new Coordinate3D(volume.Item1 / 2, volume.Item2 / 2, volume.Item3 / 2),
// Normal = normal,
// IsVisible = true
//});

//Create the slice on the respective volume
volume.CreateSlice(new SliceDefinition()
{
Name = "Middle Slice",
VoxelPosition = new Coordinate3D(volumeSize.X / 2, volumeSize.Y / 2, volumeSize.Z / 2),
Normal = normal,
IsVisible = true
});

//reset if needed...
voxelLayer.AutoShowExploreDockPane = true;

更改切片的倾斜度

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
//var voxelLayer = ... ;
//Must be on the QueuedTask.Run()

//To stop the Voxel Exploration Dockpane activating use:
voxelLayer.AutoShowExploreDockPane = false;
//This is useful if u have your own dockpane currently activated...
//Normally, it would be set in your dockpane

if (voxelLayer.Visualization != VoxelVisualization.Volume)
voxelLayer.SetVisualization(VoxelVisualization.Volume);
voxelLayer.SetSliceContainerVisibility(true);

//At 2.x - var slice = voxelLayer.GetSlices().First(s => s.Name == "Change Tilt Slice");

//Use the SelectedVariableProfile to get the slices currently in the TOC
//via its associated volume
var volume = voxelLayer.SelectedVariableProfile.Volume;
var slice = volume.GetSlices().First(s => s.Name == "Change Tilt Slice");

(double orientation, double tilt) = voxelLayer.GetOrientationAndTilt(slice.Normal);

//Convert orientation and tilt to a normal
slice.Normal = voxelLayer.GetNormal(orientation, 45.0);
//At 2.x - voxelLayer.UpdateSlice(slice);
volume.UpdateSlice(slice);

//reset if needed...Normally this might be when your dockpane
//was de-activated (ie "closed")
voxelLayer.AutoShowExploreDockPane = true;

删除切片

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
//var voxelLayer = ... ;
//Must be on the QueuedTask.Run()

//At 2.x
//var last_slice = voxelLayer.GetSlices().LastOrDefault();
// if (last_slice != null)
// voxelLayer.DeleteSlice(last_slice);

// //Delete all slices
// var slices = voxelLayer.GetSlices();
// foreach (var slice in slices)
// voxelLayer.DeleteSlice(slice);

//Use the SelectedVariableProfile to get the slices currently in the TOC
//via its associated volume
var volume = voxelLayer.SelectedVariableProfile.Volume;

var last_slice = volume.GetSlices().LastOrDefault();
if (last_slice != null)
volume.DeleteSlice(last_slice);

//Delete all slices
var slices = volume.GetSlices();
foreach (var slice in slices)
volume.DeleteSlice(slice);

部分

获取部分

1
2
3
4
5
6
7
8
9
10
11
12
13
//var voxelLayer = ... ;
//Must be on the QueuedTask.Run()

//At 2.x -
//var section = voxelLayer.GetSections().FirstOrDefault();
//var section2 = voxelLayer.GetSections().First(sec => sec.Id == my_section_id);

//Use the SelectedVariableProfile to get the sections currently in the TOC
//via its associated volume
var volume = voxelLayer.SelectedVariableProfile.Volume;

var section = volume.GetSections().FirstOrDefault();
var section2 = volume.GetSections().First(sec => sec.ID == my_section_id);

获取当前部分集合

1
2
3
4
5
6
7
8
9
10
11
12
13
14
//var voxelLayer = ... ;
//Must be on the QueuedTask.Run()

if (voxelLayer.Visualization != VoxelVisualization.Surface)
voxelLayer.SetVisualization(VoxelVisualization.Surface);
voxelLayer.SetSectionContainerExpanded(true);
voxelLayer.SetSectionContainerVisibility(true);

//At 2.x - var sections = voxelLayer.GetSections();

//Use the SelectedVariableProfile to get the sections currently in the TOC
//via its associated volume
var volume = voxelLayer.SelectedVariableProfile.Volume;
var sections = volume.GetSections();

获取目录中的选定部分

1
2
3
4
5
6
7
8
//var voxelLayer = ... ;
//Must be on the QueuedTask.Run()

var section = MapView.Active?.GetSelectedSections()?.FirstOrDefault();
if (section != null)
{

}

获取目录中所选部分的体素图层

1
2
3
4
5
6
7
8
9
10
//var voxelLayer = ... ;
//Must be on the QueuedTask.Run()

VoxelLayer voxelLayer = null;
var section = MapView.Active?.GetSelectedSections()?.FirstOrDefault();
if (section != null)
{
voxelLayer = section.Layer;
//TODO - use the layer
}

在体素中点处创建一个剖面

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
//var voxelLayer = ... ;
//Must be on the QueuedTask.Run()

if (voxelLayer.Visualization != VoxelVisualization.Surface)
voxelLayer.SetVisualization(VoxelVisualization.Surface);
voxelLayer.SetSectionContainerExpanded(true);
voxelLayer.SetSectionContainerVisibility(true);

//To stop the Voxel Exploration Dockpane activating use:
voxelLayer.AutoShowExploreDockPane = false;
//This is useful if u have your own dockpane currently activated...
//Normally, it would be set in your dockpane

//Create a section that cuts the volume in two on the vertical plane

//At 2.x - var volume = voxelLayer.GetVolumeSize();

//Use the SelectedVariableProfile to get the sections
//via its associated volume
var volume = voxelLayer.SelectedVariableProfile.Volume;
var volumeSize = volume.GetVolumeSize();

//Orientation 90 degrees (due West), Tilt 0 degrees
var normal = voxelLayer.GetNormal(90, 0.0);

//Position must be specified in voxel space

//At 2.x -
//voxelLayer.CreateSection(new SectionDefinition()
//{
// Name = "Middle Section",
// VoxelPosition = new Coordinate3D(volume.Item1 / 2, volume.Item2 / 2, volume.Item3 / 2),
// Normal = normal,
// IsVisible = true
//});
volume.CreateSection(new SectionDefinition()
{
Name = "Middle Section",
VoxelPosition = new Coordinate3D(volumeSize.X / 2, volumeSize.Y / 2, volumeSize.Z / 2),
Normal = normal,
IsVisible = true
});

//reset if needed...Normally this might be when your dockpane
//was de-activated (ie "closed")
voxelLayer.AutoShowExploreDockPane = true;

创建水平剖面

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
//var voxelLayer = ... ;
//Must be on the QueuedTask.Run()

if (voxelLayer.Visualization != VoxelVisualization.Surface)
voxelLayer.SetVisualization(VoxelVisualization.Surface);
voxelLayer.SetSectionContainerExpanded(true);
voxelLayer.SetSectionContainerVisibility(true);

//Create a section that cuts the volume in two on the horizontal plane

//At 2.x - var volumeSize = voxelLayer.GetVolumeSize();

//Use the SelectedVariableProfile to get the sections
//via its associated volume
var volume = voxelLayer.SelectedVariableProfile.Volume;
var volumeSize = volume.GetVolumeSize();

//Or use normal (0, 0, 1) or (0, 0, -1)...
var horz_section = SectionDefinition.CreateHorizontalSectionDefinition();

horz_section.Name = "Horizontal Section";
horz_section.IsVisible = true;
horz_section.VoxelPosition = new Coordinate3D(volumeSize.X / 2, volumeSize.Y / 2, volumeSize.Z / 2);

//At 2.x - voxelLayer.CreateSection(horz_section);
volume.CreateSection(horz_section);

以圆形模式创建截面

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
//var voxelLayer = ... ;
//Must be on the QueuedTask.Run()

if (voxelLayer.Visualization != VoxelVisualization.Surface)
voxelLayer.SetVisualization(VoxelVisualization.Surface);
voxelLayer.SetSectionContainerExpanded(true);
voxelLayer.SetSectionContainerVisibility(true);

//At 2.x - var volumeSize = voxelLayer.GetVolumeSize();

//Use the SelectedVariableProfile to get the sections
//via its associated volume
var volume = voxelLayer.SelectedVariableProfile.Volume;
var volumeSize = volume.GetVolumeSize();

//180 degrees orientation is due South. 90 degrees orientation is due west.
var south = 180.0;
var num_sections = 12;
var spacing = 1 / (double)num_sections;

//Create a section every nth degree of orientation. Each section
//bisects the middle of the voxel
for (int s = 0; s < num_sections; s++)
{
var orientation = south * (s * spacing);
//At 2.x -
//voxelLayer.CreateSection(new SectionDefinition()
//{
// Name = $"Circle {s + 1}",
// VoxelPosition = new Coordinate3D(volumeSize.Item1 / 2, volumeSize.Item2 / 2, volumeSize.Item3 / 2),
// Normal = voxelLayer.GetNormal(orientation, 0.0),
// IsVisible = true
//});

volume.CreateSection(new SectionDefinition()
{
Name = $"Circle {s + 1}",
VoxelPosition = new Coordinate3D(volumeSize.X / 2, volumeSize.Y / 2, volumeSize.Z / 2),
Normal = voxelLayer.GetNormal(orientation, 0.0),
IsVisible = true
});
}

创建将体素平分的部分

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
//var voxelLayer = ... ;
//Must be on the QueuedTask.Run()

if (voxelLayer.Visualization != VoxelVisualization.Surface)
voxelLayer.SetVisualization(VoxelVisualization.Surface);
voxelLayer.SetSectionContainerExpanded(true);
voxelLayer.SetSectionContainerVisibility(true);

//At 2.x - var volumeSize = voxelLayer.GetVolumeSize();

//Use the SelectedVariableProfile to get the sections
//via its associated volume
var volume = voxelLayer.SelectedVariableProfile.Volume;
var volumeSize = volume.GetVolumeSize();

//Make three Normals - each is a Unit Vector (x, y, z)
var north_south = new Coordinate3D(1, 0, 0);
var east_west = new Coordinate3D(0, 1, 0);
var horizontal = new Coordinate3D(0, 0, 1);

int n = 0;
//The two verticals bisect the x,y plane. The horizontal normal bisects
//the Z plane.
foreach (var normal in new List<Coordinate3D> { north_south, east_west, horizontal })
{
//At 2.x -
//voxelLayer.CreateSection(new SectionDefinition()
//{
// Name = $"Cross {++n}",
// VoxelPosition = new Coordinate3D(volumeSize.Item1 / 2, volumeSize.Item2 / 2, volumeSize.Item3 / 2),
// Normal = normal,
// IsVisible = true
//});

volume.CreateSection(new SectionDefinition()
{
Name = $"Cross {++n}",
VoxelPosition = new Coordinate3D(volumeSize.X / 2, volumeSize.Y / 2, volumeSize.Z / 2),
Normal = normal,
IsVisible = true
});
}

在体素对角线上创建截面

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
//var voxelLayer = ... ;
//Must be on the QueuedTask.Run()

if (voxelLayer.Visualization != VoxelVisualization.Surface)
voxelLayer.SetVisualization(VoxelVisualization.Surface);
voxelLayer.SetSectionContainerExpanded(true);
voxelLayer.SetSectionContainerVisibility(true);

//At 2.x - var volumeSize = voxelLayer.GetVolumeSize();

//Use the SelectedVariableProfile to get the sections
//via its associated volume
var volume = voxelLayer.SelectedVariableProfile.Volume;
var volumeSize = volume.GetVolumeSize();

//make a diagonal across the voxel
var voxel_pos = new Coordinate3D(0, 0, volumeSize.Z);
var voxel_pos_ur = new Coordinate3D(volumeSize.X, volumeSize.Y, volumeSize.Z);

var lineBuilder = new LineBuilderEx(voxel_pos, voxel_pos_ur, null);
var diagonal = PolylineBuilderEx.CreatePolyline(lineBuilder.ToSegment());

var num_sections = 12;
var spacing = 1 / (double)num_sections;

//change as needed
var orientation = 20.0; //(approx NNW)
var tilt = -15.0;

var normal = voxelLayer.GetNormal(orientation, tilt);

for (int s = 0; s < num_sections; s++)
{
Coordinate2D end_pt = new Coordinate2D(0, 0);
if (s > 0)
{
//position each section evenly spaced along the diagonal
var segments = new List<Segment>() as ICollection<Segment>;
var part = GeometryEngine.Instance.GetSubCurve3D(
diagonal, 0.0, s * spacing, AsRatioOrLength.AsRatio);
part.GetAllSegments(ref segments);
end_pt = segments.First().EndCoordinate;
}

//At 2.x -
//voxelLayer.CreateSection(new SectionDefinition()
//{
// Name = $"Diagonal {s + 1}",
// VoxelPosition = new Coordinate3D(end_pt.X, end_pt.Y, volumeSize.Item3),
// Normal = normal,
// IsVisible = true
//});

volume.CreateSection(new SectionDefinition()
{
Name = $"Diagonal {s + 1}",
VoxelPosition = new Coordinate3D(end_pt.X, end_pt.Y, volumeSize.Z),
Normal = normal,
IsVisible = true
});
}

更新截面方向和倾斜度

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
//var voxelLayer = ... ;
//Must be on the QueuedTask.Run()

if (voxelLayer.Visualization != VoxelVisualization.Surface)
voxelLayer.SetVisualization(VoxelVisualization.Surface);
voxelLayer.SetSectionContainerExpanded(true);
voxelLayer.SetSectionContainerVisibility(true);

//Use the SelectedVariableProfile to get the sections
//via its associated volume
var volume = voxelLayer.SelectedVariableProfile.Volume;

//At 2.x - foreach (var section in voxelLayer.GetSections())
foreach (var section in volume.GetSections())
{
//set each normal to 45.0 orientation and tilt
section.Normal = voxelLayer.GetNormal(45.0, 45.0);
//apply the change
//At 2.x - voxelLayer.UpdateSection(section);
volume.UpdateSection(section);
}

更新版块可见性

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
//var voxelLayer = ... ;
//Must be on the QueuedTask.Run()

if (voxelLayer.Visualization != VoxelVisualization.Surface)
voxelLayer.SetVisualization(VoxelVisualization.Surface);
voxelLayer.SetSectionContainerExpanded(true);
voxelLayer.SetSectionContainerVisibility(true);

//At 2.x - var sections = voxelLayer.GetSections().Where(s => !s.IsVisible);

//Use the SelectedVariableProfile to get the sections
//via its associated volume
var volume = voxelLayer.SelectedVariableProfile.Volume;
var sections = volume.GetSections().Where(s => !s.IsVisible);

//Make them all visible
foreach (var section in sections)
{
section.IsVisible = true;
//apply the change
//At 2.x - voxelLayer.UpdateSection(section);
volume.UpdateSection(section);
}

删除部分

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
//var voxelLayer = ... ;
//Must be on the QueuedTask.Run()

//Use the SelectedVariableProfile to get the sections
//via its associated volume
var volume = voxelLayer.SelectedVariableProfile.Volume;

//At 2.x - foreach (var section in voxelLayer.GetSections())
// voxelLayer.DeleteSection(section);
foreach (var section in volume.GetSections())
volume.DeleteSection(section);

//optional...
if (voxelLayer.Visualization != VoxelVisualization.Volume)
voxelLayer.SetVisualization(VoxelVisualization.Volume);

锁定部分

获取锁定部分的当前集合

1
2
3
4
5
6
7
8
9
//var voxelLayer = ... ;
//Must be on the QueuedTask.Run()

if (voxelLayer.Visualization != VoxelVisualization.Surface)
voxelLayer.SetVisualization(VoxelVisualization.Surface);
voxelLayer.SetLockedSectionContainerExpanded(true);
voxelLayer.SetLockedSectionContainerVisibility(true);

var locked_sections = voxelLayer.GetLockedSections();

获取锁定的部分

1
2
3
4
5
6
//var voxelLayer = ... ;
//Must be on the QueuedTask.Run()

var locked_section = voxelLayer.GetLockedSections().FirstOrDefault();
var locked_section2 = voxelLayer.GetLockedSections()
.First(lsec => lsec.ID == my_locked_section_id);

在目录中获取选定的锁定部分

1
2
3
4
5
6
7
8
//var voxelLayer = ... ;
//Must be on the QueuedTask.Run()

var locked_section = MapView.Active?.GetSelectedLockedSections()?.FirstOrDefault();
if (locked_section != null)
{

}

获取目录中所选锁定部分的体素图层

1
2
3
4
5
6
7
8
9
10
//var voxelLayer = ... ;
//Must be on the QueuedTask.Run()

VoxelLayer voxelLayer = null;
var locked_section = MapView.Active?.GetSelectedLockedSections()?.FirstOrDefault();
if (locked_section != null)
{
voxelLayer = locked_section.Layer;
//TODO - use the layer
}

为选定的锁定部分设置活动的变量配置文件

1
2
3
4
5
6
7
8
//Must be on the QueuedTask.Run()

var locked_section = MapView.Active?.GetSelectedLockedSections()?.FirstOrDefault();
if (locked_section != null)
{
var variable = locked_section.Layer.GetVariableProfile(locked_section.VariableName);
locked_section.Layer.SetSelectedVariableProfile(variable);
}

锁定分区/“创建”锁定分区

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
//var voxelLayer = ... ;
//Must be on the QueuedTask.Run()

if (voxelLayer.Visualization != VoxelVisualization.Surface)
voxelLayer.SetVisualization(VoxelVisualization.Surface);
voxelLayer.SetSectionContainerExpanded(true);
voxelLayer.SetLockedSectionContainerExpanded(true);
voxelLayer.SetLockedSectionContainerVisibility(true);

//Use the SelectedVariableProfile to get the sections
//via its associated volume
var volume = voxelLayer.SelectedVariableProfile.Volume;

//get the selected section
var section = MapView.Active.GetSelectedSections().FirstOrDefault();
if (section == null)
{
//At 2.x - section = voxelLayer.GetSections().FirstOrDefault();
section = volume.GetSections().FirstOrDefault();
}

if (section == null)
return;

//Lock the section (Creates a locked section, deletes
//the section)
//if (voxelLayer.CanLockSection(section))
// voxelLayer.LockSection(section);
if (volume.CanLockSection(section))
volume.LockSection(section);

更新锁定部分可见性

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
//var voxelLayer = ... ;
//Must be on the QueuedTask.Run()

if (voxelLayer.Visualization != VoxelVisualization.Surface)
voxelLayer.SetVisualization(VoxelVisualization.Surface);
voxelLayer.SetLockedSectionContainerExpanded(true);
voxelLayer.SetLockedSectionContainerVisibility(true);

var locked_sections = voxelLayer.GetLockedSections().Where(ls => !ls.IsVisible);

//Make them visible
foreach (var locked_section in locked_sections)
{
locked_section.IsVisible = true;
//apply change
voxelLayer.UpdateSection(locked_section);
}

解锁锁定部分

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
//var voxelLayer = ... ;
//Must be on the QueuedTask.Run()

if (voxelLayer.Visualization != VoxelVisualization.Surface)
voxelLayer.SetVisualization(VoxelVisualization.Surface);
voxelLayer.SetSectionContainerExpanded(true);
voxelLayer.SetSectionContainerVisibility(true);
voxelLayer.SetLockedSectionContainerExpanded(true);

//get the selected locked section
var locked_section = MapView.Active.GetSelectedLockedSections().FirstOrDefault();
if (locked_section == null)
locked_section = voxelLayer.GetLockedSections().FirstOrDefault();
if (locked_section == null)
return;

//Unlock the locked section (Deletes the locked section, creates
//a section)
if (voxelLayer.CanUnlockSection(locked_section))
voxelLayer.UnlockSection(locked_section);

删除锁定的分区

1
2
3
4
5
6
7
8
9
//var voxelLayer = ... ;
//Must be on the QueuedTask.Run()

if (voxelLayer.GetLockedSections().Count() == 0)
return;

//Delete the last locked section from the collection of
//locked sections
voxelLayer.DeleteSection(voxelLayer.GetLockedSections().Last());

地图探索

地图视图

测试视图是否为 3D 视图

1
2
3
4
5
6
7
8
9
10
11
public bool IsView3D()
{
//Get the active map view.
var mapView = MapView.Active;
if (mapView == null)
return false;

//Return whether the viewing mode is SceneLocal or SceneGlobal
return mapView.ViewingMode == ArcGIS.Core.CIM.MapViewingMode.SceneLocal ||
mapView.ViewingMode == ArcGIS.Core.CIM.MapViewingMode.SceneGlobal;
}

设置查看模式

1
2
3
4
5
6
7
8
9
10
11
public void SetViewingModeToSceneLocal()
{
//Get the active map view.
var mapView = MapView.Active;
if (mapView == null)
return;

//Check if the view can be set to SceneLocal and if it can set it.
if (mapView.CanSetViewingMode(ArcGIS.Core.CIM.MapViewingMode.SceneLocal))
mapView.SetViewingModeAsync(ArcGIS.Core.CIM.MapViewingMode.SceneLocal);
}

启用视图链接

1
2
3
4
5
6
7
8
9
10
public void EnableViewLinking()
{
//Get the active map view.
var mapView = MapView.Active;
if (mapView == null)
return;

//Set the view linking mode to Center and Scale.
MapView.LinkMode = LinkMode.Center | LinkMode.Scale;
}

更新地图视图范围(缩放、平移等)

转到上一个相机

1
2
3
4
5
6
7
8
9
10
11
12
13
public Task<bool> ZoomToPreviousCameraAsync()
{
//Get the active map view.
var mapView = MapView.Active;
if (mapView == null)
return Task.FromResult(false);

//Zoom to the selected layers in the TOC
if (mapView.HasPreviousCamera())
return mapView.PreviousCameraAsync();

return Task.FromResult(false);
}

转到下一个相机

1
2
3
4
5
6
7
8
9
10
11
12
13
public Task<bool> ZoomToNextCameraAsync()
{
//Get the active map view.
var mapView = MapView.Active;
if (mapView == null)
return Task.FromResult(false);

//Zoom to the selected layers in the TOC
if (mapView.HasNextCamera())
return mapView.NextCameraAsync();

return Task.FromResult(false);
}

缩放至全图范围

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
public Task<bool> ZoomToFullExtent()
{
return QueuedTask.Run(() =>
{
//Get the active map view.
var mapView = MapView.Active;
if (mapView == null)
return false;

//Zoom to the map's full extent
return mapView.ZoomToFullExtent();
});
}

public Task<bool> ZoomToFullExtentAsync()
{
//Get the active map view.
var mapView = MapView.Active;
if (mapView == null)
return Task.FromResult(false);

//Zoom to the map's full extent
return mapView.ZoomToFullExtentAsync(TimeSpan.FromSeconds(2));
}

固定放大

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
public Task<bool> ZoomInFixed()
{
return QueuedTask.Run(() =>
{
//Get the active map view.
var mapView = MapView.Active;
if (mapView == null)
return false;

//Zoom in the map view by a fixed amount.
return mapView.ZoomInFixed();
});
}

public Task<bool> ZoomInFixedAsync()
{
//Get the active map view.
var mapView = MapView.Active;
if (mapView == null)
return Task.FromResult(false);

//Zoom in the map view by a fixed amount.
return mapView.ZoomInFixedAsync();
}

固定缩小

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
public Task<bool> ZoomOutFixed()
{
return QueuedTask.Run(() =>
{
//Get the active map view.
var mapView = MapView.Active;
if (mapView == null)
return false;

//Zoom out in the map view by a fixed amount.
return mapView.ZoomOutFixed();
});
}

public Task<bool> ZoomOutFixedAsync()
{
//Get the active map view.
var mapView = MapView.Active;
if (mapView == null)
return Task.FromResult(false);

//Zoom in the map view by a fixed amount.
return mapView.ZoomOutFixedAsync();
}

缩放至某个范围

1
2
3
4
5
6
7
8
9
10
11
12
13
public Task<bool> ZoomToExtent(double xMin, double yMin, double xMax, double yMax, ArcGIS.Core.Geometry.SpatialReference spatialReference)
{
//Get the active map view.
var mapView = MapView.Active;
if (mapView == null)
return Task.FromResult(false);

//Create the envelope
var envelope = ArcGIS.Core.Geometry.EnvelopeBuilderEx.CreateEnvelope(xMin, yMin, xMax, yMax, spatialReference);

//Zoom the view to a given extent.
return mapView.ZoomToAsync(envelope, TimeSpan.FromSeconds(2));
}

缩放至点

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
public Task<bool> ZoomToPoint(double x, double y, ArcGIS.Core.Geometry.SpatialReference spatialReference)
{
//Get the active map view.
var mapView = MapView.Active;
if (mapView == null)
return Task.FromResult(false);

return QueuedTask.Run(() =>
{
//Note: Run within QueuedTask
//Create a point
var pt = MapPointBuilderEx.CreateMapPoint(x, y, spatialReference);
//Buffer it - for purpose of zoom
var poly = GeometryEngine.Instance.Buffer(pt, buffer_size);

//do we need to project the buffer polygon?
if (!MapView.Active.Map.SpatialReference.IsEqual(poly.SpatialReference))
{
//project the polygon
poly = GeometryEngine.Instance.Project(poly, MapView.Active.Map.SpatialReference);
}

//Zoom - add in a delay for animation effect
return mapView.ZoomTo(poly, new TimeSpan(0, 0, 0, 3));
});
}

缩放至所选要素

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
public Task<bool> ZoomToSelected()
{
return QueuedTask.Run(() =>
{
//Get the active map view.
var mapView = MapView.Active;
if (mapView == null)
return false;

//Zoom to the map's selected features.
return mapView.ZoomToSelected();
});
}

public Task<bool> ZoomToSelectedAsync()
{
//Get the active map view.
var mapView = MapView.Active;
if (mapView == null)
return Task.FromResult(false);

//Zoom to the map's selected features.
return mapView.ZoomToSelectedAsync(TimeSpan.FromSeconds(2));
}

按名称缩放至书签

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
public Task<bool> ZoomToBookmark(string bookmarkName)
{
return QueuedTask.Run(() =>
{
//Get the active map view.
var mapView = MapView.Active;
if (mapView == null)
return false;

//Get the first bookmark with the given name.
var bookmark = mapView.Map.GetBookmarks().FirstOrDefault(b => b.Name == bookmarkName);
if (bookmark == null)
return false;

//Zoom the view to the bookmark.
return mapView.ZoomTo(bookmark);
});
}

public async Task<bool> ZoomToBookmarkAsync(string bookmarkName)
{
//Get the active map view.
var mapView = MapView.Active;
if (mapView == null)
return false;

//Get the first bookmark with the given name.
var bookmark = await QueuedTask.Run(() => mapView.Map.GetBookmarks().FirstOrDefault(b => b.Name == bookmarkName));
if (bookmark == null)
return false;

//Zoom the view to the bookmark.
return await mapView.ZoomToAsync(bookmark, TimeSpan.FromSeconds(2));
}

缩放至可见图层

1
2
3
4
5
6
7
8
9
10
11
12
13
14
public Task<bool> ZoomToAllVisibleLayersAsync()
{
return QueuedTask.Run(() =>
{
//Get the active map view.
var mapView = MapView.Active;
if (mapView == null)
return false;

//Zoom to all visible layers in the map.
var visibleLayers = mapView.Map.Layers.Where(l => l.IsVisible);
return mapView.ZoomTo(visibleLayers);
});
}

缩放至所选图层

1
2
3
4
5
6
7
8
9
10
11
public Task<bool> ZoomToTOCSelectedLayersAsync()
{
//Get the active map view.
var mapView = MapView.Active;
if (mapView == null)
return Task.FromResult(false);

//Zoom to the selected layers in the TOC
var selectedLayers = mapView.GetSelectedLayers();
return mapView.ZoomToAsync(selectedLayers);
}

在一定程度上平移

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
public Task<bool> PanToExtent(double xMin, double yMin, double xMax, double yMax, ArcGIS.Core.Geometry.SpatialReference spatialReference)
{
return QueuedTask.Run(() =>
{
//Get the active map view.
var mapView = MapView.Active;
if (mapView == null)
return false;

//Pan the view to a given extent.
var envelope = ArcGIS.Core.Geometry.EnvelopeBuilderEx.CreateEnvelope(xMin, yMin, xMax, yMax, spatialReference);
return mapView.PanTo(envelope);
});
}

public Task<bool> PanToExtentAsync(double xMin, double yMin, double xMax, double yMax, ArcGIS.Core.Geometry.SpatialReference spatialReference)
{
//Get the active map view.
var mapView = MapView.Active;
if (mapView == null)
return Task.FromResult(false);

//Create the envelope
var envelope = ArcGIS.Core.Geometry.EnvelopeBuilderEx.CreateEnvelope(xMin, yMin, xMax, yMax, spatialReference);

//Pan the view to a given extent.
return mapView.PanToAsync(envelope, TimeSpan.FromSeconds(2));
}

平移到所选要素

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
public Task<bool> PanToSelected()
{
return QueuedTask.Run(() =>
{
//Get the active map view.
var mapView = MapView.Active;
if (mapView == null)
return false;

//Pan to the map's selected features.
return mapView.PanToSelected();
});
}

public Task<bool> PanToSelectedAsync()
{
//Get the active map view.
var mapView = MapView.Active;
if (mapView == null)
return Task.FromResult(false);

//Pan to the map's selected features.
return mapView.PanToSelectedAsync(TimeSpan.FromSeconds(2));
}

平移到书签

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
public Task<bool> PanToBookmark(string bookmarkName)
{
return QueuedTask.Run(() =>
{
//Get the active map view.
var mapView = MapView.Active;
if (mapView == null)
return false;

//Get the first bookmark with the given name.
var bookmark = mapView.Map.GetBookmarks().FirstOrDefault(b => b.Name == bookmarkName);
if (bookmark == null)
return false;

//Pan the view to the bookmark.
return mapView.PanTo(bookmark);
});
}

public async Task<bool> PanToBookmarkAsync(string bookmarkName)
{
//Get the active map view.
var mapView = MapView.Active;
if (mapView == null)
return false;

//Get the first bookmark with the given name.
var bookmark = await QueuedTask.Run(() => mapView.Map.GetBookmarks().FirstOrDefault(b => b.Name == bookmarkName));
if (bookmark == null)
return false;

//Pan the view to the bookmark.
return await mapView.PanToAsync(bookmark, TimeSpan.FromSeconds(2));
}

平移到可见图层

1
2
3
4
5
6
7
8
9
10
11
12
13
14
public Task<bool> PanToAllVisibleLayersAsync()
{
return QueuedTask.Run(() =>
{
//Get the active map view.
var mapView = MapView.Active;
if (mapView == null)
return false;

//Pan to all visible layers in the map.
var visibleLayers = mapView.Map.Layers.Where(l => l.IsVisible);
return mapView.PanTo(visibleLayers);
});
}

异步平移到所选图层

1
2
3
4
5
6
7
8
9
10
11
public Task<bool> PanToTOCSelectedLayersAsync()
{
//Get the active map view.
var mapView = MapView.Active;
if (mapView == null)
return Task.FromResult(false);

//Pan to the selected layers in the TOC
var selectedLayers = mapView.GetSelectedLayers();
return mapView.PanToAsync(selectedLayers);
}

旋转地图视图

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
public Task<bool> RotateView(double heading)
{
//Get the active map view.
var mapView = MapView.Active;
if (mapView == null)
return Task.FromResult(false);

//Get the camera for the view, adjust the heading and zoom to the new camera position.
var camera = mapView.Camera;
camera.Heading = heading;
return mapView.ZoomToAsync(camera, TimeSpan.Zero);
}

// or use the synchronous method
public Task<bool> RotateViewAsync(double heading)
{
return QueuedTask.Run(() =>
{
//Get the active map view.
var mapView = MapView.Active;
if (mapView == null)
return false;

//Get the camera for the view, adjust the heading and zoom to the new camera position.
var camera = mapView.Camera;
camera.Heading = heading;
return mapView.ZoomTo(camera, TimeSpan.Zero);
});
}

展开范围

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public Task<bool> ExpandExtentAsync(double dx, double dy)
{
return QueuedTask.Run(() =>
{
//Get the active map view.
var mapView = MapView.Active;
if (mapView == null)
return false;

//Expand the current extent by the given ratio.
var extent = mapView.Extent;
var newExtent = ArcGIS.Core.Geometry.GeometryEngine.Instance.Expand(extent, dx, dy, true);
return mapView.ZoomTo(newExtent);
});
}

地图

获取活动地图的名称

1
2
3
4
5
6
7
8
9
10
public string GetActiveMapName()
{
//Get the active map view.
var mapView = MapView.Active;
if (mapView == null)
return null;

//Return the name of the map currently displayed in the active map view.
return mapView.Map.Name;
}

清除活动地图中的所有选择

1
2
3
4
5
6
7
QueuedTask.Run(() =>
{
if (MapView.Active.Map != null)
{
MapView.Active.Map.SetSelection(null);
}
});

以地图单位计算选择容差

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
//Selection tolerance for the map in pixels
var selectionTolerance = SelectionEnvironment.SelectionTolerance;
QueuedTask.Run(() =>
{
//Get the map center
var mapExtent = MapView.Active.Map.GetDefaultExtent();
var mapPoint = mapExtent.Center;
//Map center as screen point
var screenPoint = MapView.Active.MapToScreen(mapPoint);
//Add selection tolerance pixels to get a "radius".
var radiusScreenPoint = new System.Windows.Point((screenPoint.X + selectionTolerance), screenPoint.Y);
var radiusMapPoint = MapView.Active.ScreenToMap(radiusScreenPoint);
//Calculate the selection tolerance distance in map uints.
var searchRadius = GeometryEngine.Instance.Distance(mapPoint, radiusMapPoint);
});

地图视图叠加控制

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
//Creat a Progress Bar user control
var progressBarControl = new System.Windows.Controls.ProgressBar();
//Configure the progress bar
progressBarControl.Minimum = 0;
progressBarControl.Maximum = 100;
progressBarControl.IsIndeterminate = true;
progressBarControl.Width = 300;
progressBarControl.Value = 10;
progressBarControl.Height = 25;
progressBarControl.Visibility = System.Windows.Visibility.Visible;
//Create a MapViewOverlayControl.
var mapViewOverlayControl = new MapViewOverlayControl(progressBarControl, true, true, true, OverlayControlRelativePosition.BottomCenter, .5, .8);
//Add to the active map
MapView.Active.AddOverlayControl(mapViewOverlayControl);
await QueuedTask.Run(() =>
{
//Wait 3 seconds to remove the progress bar from the map.
Thread.Sleep(3000);

});
//Remove from active map
MapView.Active.RemoveOverlayControl(mapViewOverlayControl);

选择目录中的所有要素图层

1
2
3
4
5
6
7
8
9
10
11
public void SelectAllFeatureLayersInTOC()
{
//Get the active map view.
var mapView = MapView.Active;
if (mapView == null)
return;

//Zoom to the selected layers in the TOC
var featureLayers = mapView.Map.Layers.OfType<FeatureLayer>();
mapView.SelectLayers(featureLayers.ToList());
}

闪烁所选功能

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
public Task FlashSelectedFeaturesAsync()
{
return QueuedTask.Run(() =>
{
//Get the active map view.
var mapView = MapView.Active;
if (mapView == null)
return;

//Get the selected features from the map and filter out the standalone table selection.

//At 2.x
//var selectedFeatures = mapView.Map.GetSelection()
// .Where(kvp => kvp.Key is BasicFeatureLayer)
// .ToDictionary(kvp => (BasicFeatureLayer)kvp.Key, kvp => kvp.Value);

////Flash the collection of features.
//mapView.FlashFeature(selectedFeatures);

var selectedFeatures = mapView.Map.GetSelection();

//Flash the collection of features.
mapView.FlashFeature(selectedFeatures);
});
}

检查图层在给定的地图视图中是否可见

1
2
3
4
5
6
7
8
var mapView = MapView.Active;
var layer = mapView.Map.GetLayersAsFlattenedList().OfType<Layer>().FirstOrDefault();
if (mapView == null) return;
bool isLayerVisibleInView = layer.IsVisibleInView(mapView);
if (isLayerVisibleInView)
{
//Do Something
}

选择一个图层并打开其图层属性页面

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
// get the layer you want
var layer = MapView.Active.Map.GetLayersAsFlattenedList().OfType<FeatureLayer>().FirstOrDefault();

// select it in the TOC
List<Layer> layersToSelect = new List<Layer>();
layersToSelect.Add(layer);
MapView.Active.SelectLayers(layersToSelect);

// now execute the layer properties command
var wrapper = FrameworkApplication.GetPlugInWrapper("esri_mapping_selectedLayerPropertiesButton");
var command = wrapper as ICommand;
if (command == null)
return;

// execute the command
if (command.CanExecute(null))
command.Execute(null);

清除特定图层的选择

1
2
3
4
5
var lyr = MapView.Active.Map.GetLayersAsFlattenedList().OfType<FeatureLayer>().FirstOrDefault();
QueuedTask.Run(() =>
{
lyr.ClearSelection();
});

地图成员的显示表窗格

1
2
3
4
5
6
7
8
9
10
11
var mapMember = MapView.Active.Map.GetLayersAsFlattenedList().OfType<MapMember>().FirstOrDefault();
//Gets or creates the CIMMapTableView for a MapMember.
var tableView = FrameworkApplication.Panes.GetMapTableView(mapMember);
//Configure the table view
tableView.DisplaySubtypeDomainDescriptions = false;
tableView.SelectionMode = false;
tableView.ShowOnlyContingentValueFields = true;
tableView.HighlightInvalidContingentValueFields = true;
//Open the table pane using the configured tableView. If a table pane is already open it will be activated.
//You must be on the UI thread to call this function.
var tablePane = FrameworkApplication.Panes.OpenTablePane(tableView);

特征

遮罩功能

1
2
3
4
5
6
7
8
9
//Get the layer to be masked
var lineLyrToBeMasked = MapView.Active.Map.Layers.FirstOrDefault(lyr => lyr.Name == "TestLine") as FeatureLayer;
//Get the layer's definition
var lyrDefn = lineLyrToBeMasked.GetDefinition();
//Create an array of Masking layers (polygon only)
//Set the LayerMasks property of the Masked layer
lyrDefn.LayerMasks = new string[] { "CIMPATH=map3/testpoly.xml" };
//Re-set the Masked layer's defintion
lineLyrToBeMasked.SetDefinition(lyrDefn);

弹出窗口

显示要素的弹出窗口

1
2
3
4
5
6
7
8
9
public void ShowPopup(MapMember mapMember, long objectID)
{
//Get the active map view.
var mapView = MapView.Active;
if (mapView == null)
return;

mapView.ShowPopup(mapMember, objectID);
}

显示自定义弹出窗口

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public void ShowCustomPopup()
{
//Get the active map view.
var mapView = MapView.Active;
if (mapView == null)
return;

//Create custom popup content
var popups = new List<PopupContent>
{
new PopupContent("<b>This text is bold.</b>", "Custom tooltip from HTML string"),
new PopupContent(new Uri("http://www.esri.com/"), "Custom tooltip from Uri")
};
mapView.ShowCustomPopup(popups);
}

使用弹出窗口属性显示要素的弹出窗口

1
2
3
4
5
6
7
8
9
10
11
12
13
14
public void ShowPopupWithWindowDef(MapMember mapMember, long objectID)
{
if (MapView.Active == null) return;
// Sample code: https://github.com/Esri/arcgis-pro-sdk-community-samples/blob/master/Map-Exploration/CustomIdentify/CustomIdentify.cs
var topLeftCornerPoint = new System.Windows.Point(200, 200);
var popupDef = new PopupDefinition()
{
Append = true, // if true new record is appended to existing (if any)
Dockable = true, // if true popup is dockable - if false Append is not applicable
Position = topLeftCornerPoint, // Position of top left corner of the popup (in pixels)
Size = new System.Windows.Size(200, 400) // size of the popup (in pixels)
};
MapView.Active.ShowPopup(mapMember, objectID, popupDef);
}

使用弹出窗口属性显示自定义弹出窗口

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
public void ShowCustomPopupWithWindowDef()
{
if (MapView.Active == null) return;

//Create custom popup content
var popups = new List<PopupContent>
{
new PopupContent("<b>This text is bold.</b>", "Custom tooltip from HTML string"),
new PopupContent(new Uri("http://www.esri.com/"), "Custom tooltip from Uri")
};
// Sample code: https://github.com/Esri/arcgis-pro-sdk-community-samples/blob/master/Framework/DynamicMenu/DynamicFeatureSelectionMenu.cs
var topLeftCornerPoint = new System.Windows.Point(200, 200);
var popupDef = new PopupDefinition()
{
Append = true, // if true new record is appended to existing (if any)
Dockable = true, // if true popup is dockable - if false Append is not applicable
Position = topLeftCornerPoint, // Position of top left corner of the popup (in pixels)
Size = new System.Windows.Size(200, 400) // size of the popup (in pixels)
};
MapView.Active.ShowCustomPopup(popups, null, true, popupDef);
}

显示带有自定义命令的弹出窗口

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
public void ShowCustomPopup(MapMember mapMember, long objectID)
{
//Get the active map view.
var mapView = MapView.Active;
if (mapView == null)
return;

//Create custom popup content from existing map member and object id
var popups = new List<PopupContent>();
popups.Add(new PopupContent(mapMember, objectID));

//Create a new custom command to add to the popup window
var commands = new List<PopupCommand>();
commands.Add(new PopupCommand(
p => MessageBox.Show(string.Format("Map Member: {0}, ID: {1}", p.MapMember, p.IDString)),
p => { return p != null; },
"My custom command",
new BitmapImage(new Uri("pack://application:,,,/ArcGIS.Desktop.Resources;component/Images/GenericCheckMark16.png")) as ImageSource));

mapView.ShowCustomPopup(popups, commands, true);
}

显示动态弹出窗口

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
public void ShowDynamicPopup(MapMember mapMember, List<long> objectIDs)
{
//Get the active map view.
var mapView = MapView.Active;
if (mapView == null)
return;

//Create popup whose content is created the first time the item is requested.
var popups = new List<PopupContent>();
foreach (var id in objectIDs)
{
popups.Add(new DynamicPopupContent(mapMember, id));
}

mapView.ShowCustomPopup(popups);
}

internal class DynamicPopupContent : PopupContent
{
public DynamicPopupContent(MapMember mapMember, long objectID)
{
MapMember = mapMember;
IDString = objectID.ToString();
IsDynamicContent = true;
}

//Called when the pop-up is loaded in the window.
protected override Task<string> OnCreateHtmlContent()
{
return QueuedTask.Run(() => string.Format("<b>Map Member: {0}, ID: {1}</b>", MapMember, IDString));
}
}

书签

使用活动地图视图创建新书签

1
2
3
4
5
6
7
8
9
10
11
12
13
public Task<Bookmark> AddBookmarkAsync(string name)
{
return QueuedTask.Run(() =>
{
//Get the active map view.
var mapView = MapView.Active;
if (mapView == null)
return null;

//Adding a new bookmark using the active view.
return mapView.Map.AddBookmark(mapView, name);
});
}

从联昌国际添加新书签

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
public Task<Bookmark> AddBookmarkFromCameraAsync(Camera camera, string name)
{
return QueuedTask.Run(() =>
{
//Set properties for Camera
CIMViewCamera cimCamera = new CIMViewCamera()
{
X = camera.X,
Y = camera.Y,
Z = camera.Z,
Scale = camera.Scale,
Pitch = camera.Pitch,
Heading = camera.Heading,
Roll = camera.Roll
};

//Create new CIM bookmark and populate its properties
var cimBookmark = new CIMBookmark() { Camera = cimCamera, Name = name, ThumbnailImagePath = "" };

//Get the active map view.
var mapView = MapView.Active;
if (mapView == null)
return null;

//Add a new bookmark for the active map.
return mapView.Map.AddBookmark(cimBookmark);
});
}

获取项目的书签集合

1
2
3
4
5
public Task<ReadOnlyObservableCollection<Bookmark>> GetProjectBookmarksAsync()
{
//Get the collection of bookmarks for the project.
return QueuedTask.Run(() => Project.Current.GetBookmarks());
}

获取地图书签

1
2
3
4
5
6
7
8
9
10
11
12
13
public Task<ReadOnlyObservableCollection<Bookmark>> GetActiveMapBookmarksAsync()
{
return QueuedTask.Run(() =>
{
//Get the active map view.
var mapView = MapView.Active;
if (mapView == null)
return null;

//Return the collection of bookmarks for the map.
return mapView.Map.GetBookmarks();
});
}

将书签移到顶部

1
2
3
4
5
6
7
8
9
10
11
12
13
public Task MoveBookmarkToTopAsync(Map map, string name)
{
return QueuedTask.Run(() =>
{
//Find the first bookmark with the name
var bookmark = map.GetBookmarks().FirstOrDefault(b => b.Name == name);
if (bookmark == null)
return;

//Remove the bookmark
map.MoveBookmark(bookmark, 0);
});
}

重命名书签

1
2
3
4
public Task RenameBookmarkAsync(Bookmark bookmark, string newName)
{
return QueuedTask.Run(() => bookmark.Rename(newName));
}

删除具有给定名称的书签

1
2
3
4
5
6
7
8
9
10
11
12
13
public Task RemoveBookmarkAsync(Map map, string name)
{
return QueuedTask.Run(() =>
{
//Find the first bookmark with the name
var bookmark = map.GetBookmarks().FirstOrDefault(b => b.Name == name);
if (bookmark == null)
return;

//Remove the bookmark
map.RemoveBookmark(bookmark);
});
}

更改书签的缩略图

1
2
3
4
5
6
public Task SetThumbnailAsync(Bookmark bookmark, string imagePath)
{
//Set the thumbnail to an image on disk, ie. C:\Pictures\MyPicture.png.
BitmapImage image = new BitmapImage(new Uri(imagePath, UriKind.RelativeOrAbsolute));
return QueuedTask.Run(() => bookmark.SetThumbnail(image));
}

更新书签

1
2
3
4
5
6
7
8
9
10
11
12
13
public Task UpdateBookmarkAsync(Bookmark bookmark)
{
return QueuedTask.Run(() =>
{
//Get the active map view.
var mapView = MapView.Active;
if (mapView == null)
return;

//Update the bookmark using the active map view.
bookmark.Update(mapView);
});
}

更新书签的范围

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public Task UpdateBookmarkExtentAsync(Bookmark bookmark, ArcGIS.Core.Geometry.Envelope envelope)
{
return QueuedTask.Run(() =>
{
//Get the bookmark's definition
var bookmarkDef = bookmark.GetDefinition();

//Modify the bookmark's location
bookmarkDef.Location = envelope;

//Clear the camera as it is no longer valid.
bookmarkDef.Camera = null;

//Set the bookmark definition
bookmark.SetDefinition(bookmarkDef);
});
}

时间

时间提前 1 个月

1
2
3
4
5
6
7
8
9
10
11
public void StepMapTime()
{
//Get the active view
MapView mapView = MapView.Active;
if (mapView == null)
return;

//Step current map time forward by 1 month
TimeDelta timeDelta = new TimeDelta(1, TimeUnit.Months);
mapView.Time = mapView.Time.Offset(timeDelta);
}

禁用地图中的时间。

1
2
MapView.Active.Time.Start = null;
MapView.Active.Time.End = null;

动画

设置动画长度

1
2
3
4
5
6
7
8
9
10
11
12
13
14
public void SetAnimationLength(TimeSpan length)
{
var mapView = MapView.Active;
if (mapView != null)
return;

var animation = mapView.Map.Animation;
var duration = animation.Duration;
if (duration == TimeSpan.Zero)
return;

var factor = length.TotalSeconds / duration.TotalSeconds;
animation.ScaleDuration(factor);
}

缩放动画

1
2
3
4
5
6
7
8
9
10
11
12
13
14
public void ScaleAnimationAfterTime(TimeSpan afterTime, TimeSpan length)
{
var mapView = MapView.Active;
if (mapView != null)
return;

var animation = mapView.Map.Animation;
var duration = animation.Duration;
if (duration == TimeSpan.Zero || duration <= afterTime)
return;

var factor = length.TotalSeconds / (duration.TotalSeconds - afterTime.TotalSeconds);
animation.ScaleDuration(afterTime, duration, factor);
}

相机关键帧

1
2
3
4
5
6
7
8
9
10
public List<CameraKeyframe> GetCameraKeyframes()
{
var mapView = MapView.Active;
if (mapView != null)
return null;

var animation = mapView.Map.Animation;
var cameraTrack = animation.Tracks.OfType<CameraTrack>().First(); //There will always be only 1 CameraTrack in the animation.
return cameraTrack.Keyframes.OfType<CameraKeyframe>().ToList();
}

插值相机

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
public Task<List<Camera>> GetInterpolatedCameras()
{
//Return the collection representing the camera for each frame in animation.
return QueuedTask.Run(() =>
{
var mapView = MapView.Active;
if (mapView != null || mapView.Animation == null)
return null;

var animation = mapView.Map.Animation;

var cameras = new List<Camera>();
//We will use ticks here rather than milliseconds to get the highest precision possible.
var ticksPerFrame = Convert.ToInt64(animation.Duration.Ticks / (animation.NumberOfFrames - 1));
for (int i = 0; i < animation.NumberOfFrames; i++)
{
var time = TimeSpan.FromTicks(i * ticksPerFrame);
//Because of rounding for ticks the last calculated time may be greating than the duration.
if (time > animation.Duration)
time = animation.Duration;
cameras.Add(mapView.Animation.GetCameraAtTime(time));
}
return cameras;
});
}

插值时间

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
public Task<List<TimeRange>> GetInterpolatedMapTimes()
{
//Return the collection representing the map time for each frame in animation.
return QueuedTask.Run(() =>
{
var mapView = MapView.Active;
if (mapView != null || mapView.Animation == null)
return null;

var animation = mapView.Map.Animation;

var timeRanges = new List<TimeRange>();
//We will use ticks here rather than milliseconds to get the highest precision possible.
var ticksPerFrame = Convert.ToInt64(animation.Duration.Ticks / (animation.NumberOfFrames - 1));
for (int i = 0; i < animation.NumberOfFrames; i++)
{
var time = TimeSpan.FromTicks(i * ticksPerFrame);
//Because of rounding for ticks the last calculated time may be greating than the duration.
if (time > animation.Duration)
time = animation.Duration;
timeRanges.Add(mapView.Animation.GetCurrentTimeAtTime(time));
}
return timeRanges;
});
}

插值范围

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
public Task<List<ArcGIS.Desktop.Mapping.Range>> GetInterpolatedMapRanges()
{
//Return the collection representing the map time for each frame in animation.
return QueuedTask.Run(() =>
{
var mapView = MapView.Active;
if (mapView != null || mapView.Animation == null)
return null;

var animation = mapView.Map.Animation;

var ranges = new List<ArcGIS.Desktop.Mapping.Range>();
//We will use ticks here rather than milliseconds to get the highest precision possible.
var ticksPerFrame = Convert.ToInt64(animation.Duration.Ticks / (animation.NumberOfFrames - 1));
for (int i = 0; i < animation.NumberOfFrames; i++)
{
var time = TimeSpan.FromTicks(i * ticksPerFrame);
//Because of rounding for ticks the last calculated time may be greeting than the duration.
if (time > animation.Duration)
time = animation.Duration;
ranges.Add(mapView.Animation.GetCurrentRangeAtTime(time));
}
return ranges;
});
}

创建摄像机关键帧

1
2
3
4
5
6
7
8
9
10
public void CreateCameraKeyframe(TimeSpan atTime)
{
var mapView = MapView.Active;
if (mapView != null)
return;

var animation = mapView.Map.Animation;
var cameraTrack = animation.Tracks.OfType<CameraTrack>().First(); //There will always be only 1 CameraTrack in the animation.
cameraTrack.CreateKeyframe(mapView.Camera, atTime, ArcGIS.Core.CIM.AnimationTransition.FixedArc);
}

创建时间关键帧

1
2
3
4
5
6
7
8
9
10
public void CreateTimeKeyframe(TimeSpan atTime)
{
var mapView = MapView.Active;
if (mapView != null)
return;

var animation = mapView.Map.Animation;
var timeTrack = animation.Tracks.OfType<TimeTrack>().First(); //There will always be only 1 TimeTrack in the animation.
timeTrack.CreateKeyframe(mapView.Time, atTime, ArcGIS.Core.CIM.AnimationTransition.Linear);
}

创建范围关键帧

1
2
3
4
5
6
7
8
9
10
public void CreateRangeKeyframe(ArcGIS.Desktop.Mapping.Range range, TimeSpan atTime)
{
var mapView = MapView.Active;
if (mapView != null)
return;

var animation = mapView.Map.Animation;
var rangeTrack = animation.Tracks.OfType<RangeTrack>().First(); //There will always be only 1 RangeTrack in the animation.
rangeTrack.CreateKeyframe(range, atTime, ArcGIS.Core.CIM.AnimationTransition.Linear);
}

创建图层关键帧

1
2
3
4
5
6
7
8
9
10
public void CreateLayerKeyframe(Layer layer, double transparency, TimeSpan atTime)
{
var mapView = MapView.Active;
if (mapView != null)
return;

var animation = mapView.Map.Animation;
var layerTrack = animation.Tracks.OfType<LayerTrack>().First(); //There will always be only 1 LayerTrack in the animation.
layerTrack.CreateKeyframe(layer, atTime, true, transparency, ArcGIS.Core.CIM.AnimationTransition.Linear);
}

图形叠加

图形叠加

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
//Defined elsewhere
private IDisposable _graphic = null;
public async void GraphicOverlaySnippetTest()
{
// get the current mapview and point
var mapView = MapView.Active;
if (mapView == null)
return;
var myextent = mapView.Extent;
var point = myextent.Center;

// add point graphic to the overlay at the center of the mapView
_graphic = await QueuedTask.Run(() =>
{
//add these to the overlay
return mapView.AddOverlay(point,
SymbolFactory.Instance.ConstructPointSymbol(
ColorFactory.Instance.RedRGB, 30.0, SimpleMarkerStyle.Star).MakeSymbolReference());
});

// update the overlay with new point graphic symbol
MessageBox.Show("Now to update the overlay...");
await QueuedTask.Run(() =>
{
mapView.UpdateOverlay(_graphic, point, SymbolFactory.Instance.ConstructPointSymbol(
ColorFactory.Instance.BlueRGB, 20.0, SimpleMarkerStyle.Circle).MakeSymbolReference());
});

// clear the overlay display by disposing of the graphic
MessageBox.Show("Now to clear the overlay...");
_graphic.Dispose();

}

图形叠加与 CIMPicture图形

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
// get the current mapview
var mapView = MapView.Active;
if (mapView == null)
return;

//Valid formats for PictureURL are:
// e.g. local file URL:
// file:///<path>
// file:///c:/images/symbol.png
//
// e.g. network file URL:
// file://<host>/<path>
// file://server/share/symbol.png
//
// e.g. data URL:
// data:<mediatype>;base64,<data>
// data:image/jpeg;base64,/9j/4AAQSkZJRgABAQEASABIAAD/2wBDAAU ...
//
// image/bmp
// image/gif
// image/jpeg
// image/png
// image/tiff
// image/x-esri-bglf

var pictureGraphic = new CIMPictureGraphic
{
PictureURL = @"file:///C:/Images/MyImage.png",
Box = envelope
};

IDisposable _graphic = mapView.AddOverlay(pictureGraphic);

添加带有文本的叠加图形

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
internal class AddOverlayWithText : MapTool
{
private IDisposable _graphic = null;
private CIMLineSymbol _lineSymbol = null;
public AddOverlayWithText()
{
IsSketchTool = true;
SketchType = SketchGeometryType.Line;
SketchOutputMode = SketchOutputMode.Map;
}

protected override async Task<bool> OnSketchCompleteAsync(Geometry geometry)
{
//Add an overlay graphic to the map view
_graphic = await this.AddOverlayAsync(geometry, _lineSymbol.MakeSymbolReference());

//define the text symbol
var textSymbol = new CIMTextSymbol();
//define the text graphic
var textGraphic = new CIMTextGraphic();

await QueuedTask.Run(() =>
{
//Create a simple text symbol
textSymbol = SymbolFactory.Instance.ConstructTextSymbol(ColorFactory.Instance.BlackRGB, 8.5, "Corbel", "Regular");
//Sets the geometry of the text graphic
textGraphic.Shape = geometry;
//Sets the text string to use in the text graphic
textGraphic.Text = "This is my line";
//Sets symbol to use to draw the text graphic
textGraphic.Symbol = textSymbol.MakeSymbolReference();
//Draw the overlay text graphic
_graphic = this.ActiveMapView.AddOverlay(textGraphic);
});

return true;
}
}

工具

更改草图工具的符号

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
internal class SketchTool_WithSymbol : MapTool
{
public SketchTool_WithSymbol()
{
IsSketchTool = true;
SketchOutputMode = SketchOutputMode.Map; //Changing the Sketch Symbol is only supported with map sketches.
SketchType = SketchGeometryType.Rectangle;
}

protected override Task OnToolActivateAsync(bool hasMapViewChanged)
{
return QueuedTask.Run(() =>
{
//Set the Sketch Symbol if it hasn't already been set.
if (SketchSymbol != null)
return;
var polygonSymbol = SymbolFactory.Instance.ConstructPolygonSymbol(ColorFactory.Instance.CreateRGBColor(24, 69, 59),
SimpleFillStyle.Solid,
SymbolFactory.Instance.ConstructStroke(ColorFactory.Instance.BlackRGB, 1.0, SimpleLineStyle.Dash));
SketchSymbol = polygonSymbol.MakeSymbolReference();
});
}
}

创建用于地图中单击的点的返回坐标的工具

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
internal class GetMapCoordinates : MapTool
{
protected override void OnToolMouseDown(MapViewMouseButtonEventArgs e)
{
if (e.ChangedButton == System.Windows.Input.MouseButton.Left)
e.Handled = true; //Handle the event args to get the call to the corresponding async method
}

protected override Task HandleMouseDownAsync(MapViewMouseButtonEventArgs e)
{
return QueuedTask.Run(() =>
{
//Convert the clicked point in client coordinates to the corresponding map coordinates.
var mapPoint = MapView.Active.ClientToMap(e.ClientPoint);
ArcGIS.Desktop.Framework.Dialogs.MessageBox.Show(string.Format("X: {0} Y: {1} Z: {2}",
mapPoint.X, mapPoint.Y, mapPoint.Z), "Map Coordinates");
});
}
}

创建用于识别与草图几何相交的特征的工具

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
internal class CustomIdentify : MapTool
{
public CustomIdentify()
{
IsSketchTool = true;
SketchType = SketchGeometryType.Rectangle;

//To perform a interactive selection or identify in 3D or 2D, sketch must be created in screen coordinates.
SketchOutputMode = SketchOutputMode.Screen;
}

protected override Task<bool> OnSketchCompleteAsync(Geometry geometry)
{
return QueuedTask.Run(() =>
{
var mapView = MapView.Active;
if (mapView == null)
return true;

//Get all the features that intersect the sketch geometry and flash them in the view.
var results = mapView.GetFeatures(geometry);
mapView.FlashFeature(results);

var debug = String.Join("\n", results.ToDictionary()
.Select(kvp => String.Format("{0}: {1}", kvp.Key.Name, kvp.Value.Count())));
System.Diagnostics.Debug.WriteLine(debug);
return true;
});
}
}

更改工具的光标

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
internal class CustomMapTool : MapTool
{
public CustomMapTool()
{
IsSketchTool = true;
SketchType = SketchGeometryType.Rectangle;
SketchOutputMode = SketchOutputMode.Map;
//A custom cursor file as an embedded resource
var cursorEmbeddedResource = new Cursor(new MemoryStream(Resource1.red_cursor));
//A built in system cursor
var systemCursor = System.Windows.Input.Cursors.ArrowCD;
//Set the "CustomMapTool's" Cursor property to either one of the cursors defined above
Cursor = cursorEmbeddedResource;
//or
Cursor = systemCursor;
}

具有可嵌入控件的工具

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
// Using the Visual Studio SDK templates, add a MapTool and an EmbeddableControl
// The EmbeddableControl is registered in the "esri_embeddableControls" category in the config.daml file
//
// <categories>
// <updateCategory refID = "esri_embeddableControls" >
// <insertComponent id="mapTool_EmbeddableControl" className="EmbeddableControl1ViewModel">
// <content className = "EmbeddableControl1View" />
// </insertComponent>
// <updateCategory>
// </categories>
internal class MapTool_WithControl : MapTool
{
public MapTool_WithControl()
{
// substitute this string with the daml ID of the embeddable control you added
ControlID = "mapTool_EmbeddableControl";
}

protected override void OnToolMouseDown(MapViewMouseButtonEventArgs e)
{
e.Handled = true;
}

protected override Task HandleMouseDownAsync(MapViewMouseButtonEventArgs e)
{
//Get the instance of the ViewModel
var vm = EmbeddableControl;
if (vm == null)
return Task.FromResult(0);

// cast vm to your viewModel in order to access your properties

//Get the map coordinates from the click point and set the property on the ViewMode.
return QueuedTask.Run(() =>
{
var mapPoint = MapView.Active.ClientToMap(e.ClientPoint);
string clickText = string.Format("X: {0}, Y: {1}, Z: {2}", mapPoint.X, mapPoint.Y, mapPoint.Z);
});
}
}

具有可嵌入叠加控件的工具

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
// Using the Visual Studio SDK templates, add a MapTool and an EmbeddableControl
// The EmbeddableControl is registered in the "esri_embeddableControls" category in the config.daml file
//
// <categories>
// <updateCategory refID = "esri_embeddableControls" >
// <insertComponent id="mapTool_EmbeddableControl" className="EmbeddableControl1ViewModel">
// <content className = "EmbeddableControl1View" />
// </insertComponent>
// <updateCategory>
// </categories>

internal class MapTool_WithOverlayControl : MapTool
{
public MapTool_WithOverlayControl()
{
// substitute this string with the daml ID of the embeddable control you added
OverlayControlID = "mapTool_EmbeddableControl";
}

protected override void OnToolMouseDown(MapViewMouseButtonEventArgs e)
{
e.Handled = true;
}

protected override Task HandleMouseDownAsync(MapViewMouseButtonEventArgs e)
{
//Get the instance of the ViewModel
var vm = OverlayEmbeddableControl;
if (vm == null)
return Task.FromResult(0);

// cast vm to your viewModel in order to access your properties

//Get the map coordinates from the click point and set the property on the ViewMode.
return QueuedTask.Run(() =>
{
var mapPoint = MapView.Active.ClientToMap(e.ClientPoint);
string clickText = string.Format("X: {0}, Y: {1}, Z: {2}", mapPoint.X, mapPoint.Y, mapPoint.Z);
});
}
}

共享

ArcGIS 项目管理器:获取当前活动门户

1
2
var active_portal = ArcGISPortalManager.Current.GetActivePortal();
string uri = active_portal.PortalUri.ToString();

ArcGIS 项目管理器:获取所有门户的列表

1
2
3
var portals = ArcGISPortalManager.Current.GetPortals();
//Make a list of all the Uris
var portalUris = portals.Select(p => p.PortalUri.ToString()).ToList();

ArcGIS 项目管理器:将门户添加到门户列表

1
2
var portalUri = new Uri("http://myportal.esri.com/portal/", UriKind.Absolute);
ArcGISPortalManager.Current.AddPortal(portalUri);

ArcGIS 项目管理器:获取门户并登录,将其设置为活动状态

1
2
3
4
5
6
7
8
9
10
11
12
//Find the portal to sign in with using its Uri...
var portal = ArcGISPortalManager.Current.GetPortal(new Uri(uri, UriKind.Absolute));
if (!portal.IsSignedOn())
{
//Calling "SignIn" will trigger the OAuth popup if your credentials are
//not cached (eg from a previous sign in in the session)
if (portal.SignIn().success)
{
//Set this portal as my active portal
ArcGISPortalManager.Current.SetActivePortal(portal);
}
}

ArcGIS 程序管理器:侦听门户事件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
ArcGIS.Desktop.Core.Events.ActivePortalChangedEvent.Subscribe((args) =>
{

var active_uri = args.ActivePortal?.PortalUri.ToString();
//etc
});

ArcGIS.Desktop.Core.Events.ArcGISPortalAddedEvent.Subscribe((args) =>
{
var added_portal = args.Portal;
//etc
});

ArcGIS.Desktop.Core.Events.ArcGISPortalRemovedEvent.Subscribe((args) =>
{
var old_uri = args.RemovedPortalUri;
//etc
});

ArcGIS.Desktop.Core.Events.PortalSignOnChangedEvent.Subscribe((args) =>
{
var portal = args.Portal;
var isSignedOn = args.IsSignedOn;
//etc
});

门户:从活动门户获取当前登录用户

1
2
3
4
5
6
7
var portal = ArcGISPortalManager.Current.GetActivePortal();
//Force login
if (!portal.IsSignedOn())
{
portal.SignIn();
}
var user = portal.GetSignOnUsername();

门户:获取当前用户的“联机”门户视图

1
2
3
4
//If no-one is signed in, this will be the default view for
//the anonymous user.
var online = ArcGISPortalManager.Current.GetPortal(new Uri("http://www.arcgis.com"));
var portalInfo = await online.GetPortalInfoAsync();

门户:获取当前用户的组织 ID

1
2
3
var portal = ArcGISPortalManager.Current.GetPortal(new Uri(portalUri));
var portalInfo = await portal.GetPortalInfoAsync();
var orgid = portalInfo.OrganizationId;

门户:从活动门户获取活动用户的用户内容

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
var portal = ArcGISPortalManager.Current.GetActivePortal();
var owner = portal.GetSignOnUsername();
var userContent = await portal.GetUserContentAsync(owner);
//Get content for a specific folder (identified by its folder id)
//var userContent = await portal.GetUserContentAsync(owner, folderId);

//Get all the folders
foreach (var pf in userContent.PortalFolders)
{
//Do something with the folders

}

//Get all the content items
foreach (var pi in userContent.PortalItems)
{
//Do something with the portal items
}

门户:下载用户内容中的任何包项

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
//user content previously from...
//var userContent = await portal.GetUserContentAsync(owner);

var packages = new List<PortalItemType>
{
PortalItemType.BasemapPackage,
PortalItemType.GeoprocessingPackage,
PortalItemType.LayerPackage,
PortalItemType.LocatorPackage,
PortalItemType.MapPackage,
PortalItemType.ProjectPackage,
PortalItemType.ScenePackage,
PortalItemType.RulePackage,
PortalItemType.VectorTilePackage
};
var folder = @"E:\Temp\PortalAPITest\";
foreach (var di in userContent.PortalItems.Where(pi => packages.Contains(pi.PortalItemType)))
{
var path = System.IO.Path.Combine(folder, di.Name);
await di.GetItemDataAsync(path);
}

门户:获取指定用户的组

1
2
3
4
5
6
7
//elsewhere...
//var owner = portal.GetSignOnUsername();
var groups = await portal.GetGroupsFromUserAsync(owner);
foreach (var group in groups)
{
//Do something with the portal groups
}

门户:执行门户搜索

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
var portal = ArcGISPortalManager.Current.GetPortal(portalUri);
var owner = portal.GetSignOnUsername();
var portalInfo = await portal.GetPortalInfoAsync();

//1. Get all web maps
var query1 = PortalQueryParameters.CreateForItemsOfType(PortalItemType.WebMap);

//2. Get all web maps and map services - include user, organization
// and "usa" in the title
var query2 = PortalQueryParameters.CreateForItemsOfTypes(new List<PortalItemType>() {
PortalItemType.WebMap, PortalItemType.MapService}, owner, "", "title:usa");
query2.OrganizationId = portalInfo.OrganizationId;

//retrieve in batches of up to a 100 each time
query2.Limit = 100;

//Loop until done
var portalItems = new List<PortalItem>();
while (query2 != null)
{
//run the search
PortalQueryResultSet<PortalItem> results = await portal.SearchForContentAsync(query2);
portalItems.AddRange(results.Results);
query2 = results.NextQueryParameters;
}

//process results
foreach (var pi in portalItems)
{
//Do something with the portal items
}

EsriHttpClient:获取当前登录用户

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
//Reference Newtonsoft - Json.Net
//Reference System.Net.Http
UriBuilder selfURL = new UriBuilder(ArcGISPortalManager.Current.GetActivePortal().PortalUri)
{
Path = "sharing/rest/portals/self",
Query = "f=json"
};
EsriHttpResponseMessage response = new EsriHttpClient().Get(selfURL.Uri.ToString());

dynamic portalSelf = JObject.Parse(await response.Content.ReadAsStringAsync());
// if the response doesn't contain the user information then it is essentially
// an anonymous request against the portal
if (portalSelf.user == null)
return;
string userName = portalSelf.user.username;

获取当前登录用户的组

1
2
3
4
5
6
7
8
9
10
//Assume that you have executed the "Get the Current signed on User" snippet and have 'userName'
UriBuilder groupsURL = new UriBuilder(ArcGISPortalManager.Current.GetActivePortal().PortalUri)
{
Path = String.Format("sharing/rest/community/users/{0}", userName),
Query = "f=json"
};
var groupResponse = new EsriHttpClient().Get(groupsURL.Uri.ToString());
dynamic portalGroups = JObject.Parse(await groupResponse.Content.ReadAsStringAsync());

string groups = portalGroups.groups.ToString();

EsriHttpClient:查询活动门户上的 Esri 内容

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
//http://www.arcgis.com/sharing/search?q=owner:esri&f=json

UriBuilder searchURL = new UriBuilder(ArcGISPortalManager.Current.GetActivePortal().PortalUri)
{
Path = "sharing/rest/search",
Query = "q=owner:esri&f=json"
};
EsriHttpClient httpClient = new EsriHttpClient();
var searchResponse = httpClient.Get(searchURL.Uri.ToString());
dynamic resultItems = JObject.Parse(await searchResponse.Content.ReadAsStringAsync());

long numberOfTotalItems = resultItems.total.Value;
long currentCount = 0;

List<dynamic> resultItemList = new List<dynamic>();
// store the first results in the list
resultItemList.AddRange(resultItems.results);
currentCount = currentCount + resultItems.num.Value;
//Up to 50
while (currentCount < numberOfTotalItems && currentCount <= 50)
{
searchURL.Query = String.Format("q=owner:esri&start={0}&f=json", resultItems.nextStart.Value);
searchResponse = httpClient.Get(searchURL.Uri.ToString());
resultItems = JObject.Parse(await searchResponse.Content.ReadAsStringAsync());
resultItemList.AddRange(resultItems.results);
currentCount = currentCount + resultItems.num.Value;
}

EsriHttpClient:获取当前用户的 web 地图并将其添加到专业版

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
UriBuilder searchURL = new UriBuilder(ArcGISPortalManager.Current.GetActivePortal().PortalUri)
{
Path = "sharing/rest/portals/self",
Query = "f=json"
};
EsriHttpClient httpClient = new EsriHttpClient();
EsriHttpResponseMessage response = httpClient.Get(searchURL.Uri.ToString());

dynamic portalSelf = JObject.Parse(await response.Content.ReadAsStringAsync());
// if the response doesn't contain the user information then it is essentially
// an anonymous request against the portal
if (portalSelf.user == null)
return;
string userName = portalSelf.user.username;

searchURL.Path = "sharing/rest/search";
string webMaps = "(type:\"Web Map\" OR type:\"Explorer Map\" OR type:\"Web Mapping Application\" OR type:\"Online Map\")";
searchURL.Query = string.Format("q=owner:{0} {1}&f=json", userName, webMaps);

var searchResponse = httpClient.Get(searchURL.Uri.ToString());
dynamic resultItems = JObject.Parse(await searchResponse.Content.ReadAsStringAsync());

long numberOfTotalItems = resultItems.total.Value;
if (numberOfTotalItems == 0)
return;

List<dynamic> resultItemList = new List<dynamic>();
resultItemList.AddRange(resultItems.results);
//get the first result
dynamic item = resultItemList[0];

string itemID = item.id;
Item currentItem = ItemFactory.Instance.Create(itemID, ItemFactory.ItemType.PortalItem);

if (MapFactory.Instance.CanCreateMapFrom(currentItem))
{
Map newMap = MapFactory.Instance.CreateMapFromItem(currentItem);
await ProApp.Panes.CreateMapPaneAsync(newMap);
}

EsriHttpClient:获取服务图层并将其添加到专业版

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
UriBuilder searchURL = new UriBuilder(ArcGISPortalManager.Current.GetActivePortal().PortalUri)
{
Path = "sharing/rest/search"
};
string layers = "(type:\"Map Service\" OR type:\"Image Service\" OR type:\"Feature Service\" OR type:\"WMS\" OR type:\"KML\")";
//any public layer content
searchURL.Query = string.Format("q={0}&f=json", layers);

EsriHttpClient httpClient = new EsriHttpClient();

var searchResponse = httpClient.Get(searchURL.Uri.ToString());
dynamic resultItems = JObject.Parse(await searchResponse.Content.ReadAsStringAsync());

long numberOfTotalItems = resultItems.total.Value;
if (numberOfTotalItems == 0)
return;

List<dynamic> resultItemList = new List<dynamic>();
resultItemList.AddRange(resultItems.results);
//get the first result
dynamic item = resultItemList[0];

string itemID = item.id;
Item currentItem = ItemFactory.Instance.Create(itemID, ItemFactory.ItemType.PortalItem);

await QueuedTask.Run(() =>
{
//Create a LayerCreationParam
var layerParam = new LayerCreationParams(currentItem);
// if we have an item that can be turned into a layer
// add it to the map
if (LayerFactory.Instance.CanCreateLayerFrom(currentItem))
LayerFactory.Instance.CreateLayer<FeatureLayer>(layerParam, MapView.Active.Map);
});

公共设施网络

获取公共设施网络

从表中获取公共设施网络

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
public static UtilityNetwork GetUtilityNetworkFromTable(Table table)
{
UtilityNetwork utilityNetwork = null;

if (table.IsControllerDatasetSupported())
{
// Tables can belong to multiple controller datasets, but at most one of them will be a UtilityNetwork
IReadOnlyList<Dataset> controllerDatasets = table.GetControllerDatasets();

foreach (Dataset controllerDataset in controllerDatasets)
{
if (controllerDataset is UtilityNetwork)
{
utilityNetwork = controllerDataset as UtilityNetwork;
}
else
{
controllerDataset.Dispose();
}
}
}
return utilityNetwork;
}

从图层获取公共设施网络

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
// This routine obtains a utility network from a FeatureLayer, SubtypeGroupLayer, or UtilityNetworkLayer
public static UtilityNetwork GetUtilityNetworkFromLayer(Layer layer)
{
UtilityNetwork utilityNetwork = null;

if (layer is UtilityNetworkLayer)
{
UtilityNetworkLayer utilityNetworkLayer = layer as UtilityNetworkLayer;
utilityNetwork = utilityNetworkLayer.GetUtilityNetwork();
}

else if (layer is SubtypeGroupLayer)
{
CompositeLayer compositeLayer = layer as CompositeLayer;
utilityNetwork = GetUtilityNetworkFromLayer(compositeLayer.Layers.First());
}

else if (layer is FeatureLayer)
{
FeatureLayer featureLayer = layer as FeatureLayer;
using (FeatureClass featureClass = featureLayer.GetFeatureClass())
{
if (featureClass.IsControllerDatasetSupported())
{
IReadOnlyList<Dataset> controllerDatasets = new List<Dataset>();
controllerDatasets = featureClass.GetControllerDatasets();
foreach (Dataset controllerDataset in controllerDatasets)
{
if (controllerDataset is UtilityNetwork)
{
utilityNetwork = controllerDataset as UtilityNetwork;
}
else
{
controllerDataset.Dispose();
}
}
}
}
}
return utilityNetwork;
}

元素

从元素中获取行

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
// usage :   using (var row = FetchRowFromElement(...))
public static Row FetchRowFromElement(UtilityNetwork utilityNetwork, Element element)
{
// Get the table from the element
using (Table table = utilityNetwork.GetTable(element.NetworkSource))
{
// Create a query filter to fetch the appropriate row
QueryFilter queryFilter = new QueryFilter()
{
ObjectIDs = new List<long>() { element.ObjectID }
};

// Fetch and return the row
using (RowCursor rowCursor = table.Search(queryFilter))
{
if (rowCursor.MoveNext())
{
return rowCursor.Current;
}
return null;
}
}
}

编辑关联

创建公共设施网络关联

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
// Create edit operation
EditOperation editOperation = new EditOperation();
editOperation.Name = "Create structural attachment association";

// Create a RowHandle for the pole

Element poleElement = utilityNetwork.CreateElement(poleAssetType, poleGlobalID);
RowHandle poleRowHandle = new RowHandle(poleElement, utilityNetwork);

// Create a RowHandle for the transformer bank

Element transformerBankElement = utilityNetwork.CreateElement(transformerBankAssetType, transformerBankGlobalID);
RowHandle transformerBankRowHandle = new RowHandle(transformerBankElement, utilityNetwork);

// Attach the transformer bank to the pole

AssociationDescription structuralAttachmentAssociationDescription = new AssociationDescription(AssociationType.Attachment, poleRowHandle, transformerBankRowHandle);
editOperation.Create(structuralAttachmentAssociationDescription);
editOperation.Execute();

在单个编辑操作中创建公共设施网络要素和关联

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
// Create an EditOperation
EditOperation editOperation = new EditOperation();
editOperation.Name = "Create pole; create transformer bank; attach transformer bank to pole";

// Create the transformer bank
RowToken transformerBankToken = editOperation.Create(transformerBankLayer, transformerBankAttributes);

// Create a pole
RowToken poleToken = editOperation.Create(poleLayer, poleAttributes);

// Create a structural attachment association between the pole and the transformer bank
RowHandle poleHandle = new RowHandle(poleToken);
RowHandle transformerBankHandle = new RowHandle(transformerBankToken);

AssociationDescription poleAttachment = new AssociationDescription(AssociationType.Attachment, poleHandle, transformerBankHandle);

editOperation.Create(poleAttachment);

// Execute the EditOperation
editOperation.Execute();

遍历关联

获取向下遍历产生的遍历关联

1
2
3
4
5
6
7
8
9
10
11
public static void GetTraverseAssociationsResultFromDownwardTraversal(UtilityNetwork utilityNetwork, IReadOnlyList<Element> startingElements)
{
// Set downward traversal with maximum depth
TraverseAssociationsDescription traverseAssociationsDescription = new TraverseAssociationsDescription(TraversalDirection.Descending);

// Get traverse associations result from the staring element up to maximum depth
TraverseAssociationsResult traverseAssociationsResult = utilityNetwork.TraverseAssociations(startingElements, traverseAssociationsDescription);

// Get associations participated in traversal
IReadOnlyList<Association> associations = traverseAssociationsResult.Associations;
}

获取具有深度限制的向上遍历产生的遍历关联

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
public static void GetTraverseAssociationsResultFromUpwardTraversalWithDepthLimit(UtilityNetwork utilityNetwork, IReadOnlyList<Element> startingElements)
{
// List of fields whose values will be fetched as name-values pairs during association traversal operation
List<string> additionalFieldsToFetch = new List<string> { "ObjectId", "AssetName", "AssetGroup", "AssetType" };

// Set downward traversal with maximum depth level of 3
TraverseAssociationsDescription traverseAssociationsDescription = new TraverseAssociationsDescription(TraversalDirection.Ascending, 3)
{
AdditionalFields = additionalFieldsToFetch
};

// Get traverse associations result from the staring element up to depth level 3
TraverseAssociationsResult traverseAssociationsResult = utilityNetwork.TraverseAssociations(startingElements, traverseAssociationsDescription);

// List of associations participated in traversal
IReadOnlyList<Association> associations = traverseAssociationsResult.Associations;

// KeyValue mapping between involved elements and their field name-values
//At 2.x - IReadOnlyDictionary<Element, IReadOnlyList<AssociationElementFieldValue>> associationElementValuePairs = traverseAssociationsResult.AdditionalFieldValues;
IReadOnlyDictionary<Element, IReadOnlyList<FieldValue>> associationElementValuePairs =
traverseAssociationsResult.AdditionalFieldValues;

foreach (KeyValuePair<Element, IReadOnlyList<FieldValue>> keyValuePair in associationElementValuePairs)
{
// Element
Element element = keyValuePair.Key;

// List of field names and their values
//At 2.x - IReadOnlyList<AssociationElementFieldValue> elementFieldValues = keyValuePair.Value;
IReadOnlyList<FieldValue> elementFieldValues = keyValuePair.Value;
}
}

子网和层

查找给定域网络名称和层名称的层

1
2
3
4
5
using (UtilityNetworkDefinition utilityNetworkDefinition = utilityNetwork.GetDefinition())
{
DomainNetwork domainNetwork = utilityNetworkDefinition.GetDomainNetwork(domainNetworkName);
Tier tier = domainNetwork.GetTier(tierName);
}

更新层中的所有脏子网

1
2
3
4
5
6
using (SubnetworkManager subnetworkManager = utilityNetwork.GetSubnetworkManager())
{
subnetworkManager.UpdateAllSubnetworks(tier, true);

mapView.Redraw(true);
}

具有一个控制器的简单径向子网的生命周期

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
// Create a subnetwork named "Radial1" with a single controller
// elementR1 represents the device that serves as the subnetwork controller (e.g., circuit breaker)
Subnetwork subnetworkRadial1 = subnetworkManager.EnableControllerInEditOperation(mediumVoltageTier, elementR1, "Radial1", "R1", "my description", "my notes");

// ...

// Update the subnetwork and refresh the map
subnetworkRadial1.Update();
MapView.Active.Redraw(true);

// ...

// At some point, a subnetwork will need to be deleted.

// First step is to disable the controller
subnetworkManager.DisableControllerInEditOperation(elementR1);

// At this point, the subnetwork is deleted, but all of the rows that have been labeled with the subnetwork ID need to be updated
subnetworkRadial1.Update();
MapView.Active.Redraw(true);

// The final step is to notify external systems (if any) using the Export Subnetwork geoprocessing tool

具有多个控制器的网格子网的生命周期

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
// Create a subnetwork named "Mesh1" from three controllers
// elementM1, elementM2, and elementM3 represent the devices that serve as subnetwork controllers (e.g., network protectors)
subnetworkManager.EnableController(lowVoltageMeshTier, elementM1, "Mesh1", "M1", "my description", "my notes");
subnetworkManager.EnableController(lowVoltageMeshTier, elementM2, "Mesh1", "M2", "my description", "my notes");
Subnetwork subnetworkMesh1 = subnetworkManager.EnableController(lowVoltageMeshTier, elementM3, "Mesh1", "M3", "my description", "my notes");
subnetworkMesh1.Update();
MapView.Active.Redraw(true);

// ...

// When deleting the subnetwork, each controller must be disabled before the subnetwork itself is deleted
subnetworkManager.DisableControllerInEditOperation(elementM1);
subnetworkManager.DisableControllerInEditOperation(elementM2);
subnetworkManager.DisableControllerInEditOperation(elementM3);

// After the subnetwork is deleted, all of the rows that have been labeled with the subnetwork ID need to be updated
subnetworkMesh1.Update();
MapView.Active.Redraw(true);

// The final step is to notify external systems (if any) using the Export Subnetwork geoprocessing tool

具有两个控制器的重馈径向子网的生命周期

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// Create a subnetwork named "R2, R3" from two controllers
// elementR2 and elementR3 represent the devices that serve as subnetwork controllers (e.g., circuit breakers)
subnetworkManager.EnableControllerInEditOperation(mediumVoltageTier, elementR2, "R2, R3", "R2", "my description", "my notes");
subnetworkManager.EnableControllerInEditOperation(mediumVoltageTier, elementR3, "R2, R3", "R3", "my description", "my notes");

// If the tie switch between them is opened, the original subnetwork controllers must be disabled and re-enabled with different names
// This will create two new subnetworks, named "R2" and "R3"
subnetworkManager.DisableControllerInEditOperation(elementR2);
subnetworkManager.DisableControllerInEditOperation(elementR3);

Subnetwork subnetworkR2 = subnetworkManager.EnableControllerInEditOperation(mediumVoltageTier, elementR2, "R2", "R2", "my description", "my notes");
Subnetwork subnetworkR3 = subnetworkManager.EnableControllerInEditOperation(mediumVoltageTier, elementR3, "R3", "R3", "my description", "my notes");

subnetworkR2.Update();
subnetworkR3.Update();
MapView.Active.Redraw(true);

描图

创建下游跟踪程序

1
2
3
4
using (TraceManager traceManager = utilityNetwork.GetTraceManager())
{
DownstreamTracer downstreamTracer = traceManager.GetTracer<DownstreamTracer>();
}

创建跟踪参数

1
2
3
4
5
6
7
8
9
IReadOnlyList<Element> startingPointList = new List<Element>();

// Code to fill in list of starting points goes here...
TraceArgument traceArgument = new TraceArgument(startingPointList);

TraceConfiguration traceConfiguration = new TraceConfiguration();

// Code to fill in trace configuration goes here...
traceArgument.Configuration = traceConfiguration;

创建条件以将网络属性与一组值进行比较

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// Create a NetworkAttribute object for the Lifecycle network attribute from the UtilityNetworkDefinition
using (NetworkAttribute lifecycleNetworkAttribute = utilityNetworkDefinition.GetNetworkAttribute("Lifecycle"))
{
// Create a NetworkAttributeComparison that stops traversal if Lifecycle <> "In Design" (represented by the constant InDesign)
NetworkAttributeComparison inDesignNetworkAttributeComparison = new NetworkAttributeComparison(lifecycleNetworkAttribute, Operator.NotEqual, InDesign);

// Create a NetworkAttributeComparison to stop traversal if Lifecycle <> "In Service" (represented by the constant InService)
NetworkAttributeComparison inServiceNetworkAttributeComparison = new NetworkAttributeComparison(lifecycleNetworkAttribute, Operator.NotEqual, InService);

// Combine these two comparisons together with "And"
And lifecycleFilter = new And(inDesignNetworkAttributeComparison, inServiceNetworkAttributeComparison);

// Final condition stops traversal if Lifecycle <> "In Design" and Lifecycle <> "In Service"
traceConfiguration.Traversability.Barriers = lifecycleFilter;
}

创建函数

1
2
3
4
5
6
7
8
9
// Get a NetworkAttribute object for the Load network attribute from the UtilityNetworkDefinition
using (NetworkAttribute loadNetworkAttribute = utilityNetworkDefinition.GetNetworkAttribute("Load"))
{
// Create a function to sum the Load
Add sumLoadFunction = new Add(loadNetworkAttribute);

// Add this function to our trace configuration
traceConfiguration.Functions = new List<Function>() { sumLoadFunction };
}

创建功能屏障

1
2
3
4
5
6
7
8
9
10
11
12
// Create a NetworkAttribute object for the Shape length network attribute from the UtilityNetworkDefinition
using (NetworkAttribute shapeLengthNetworkAttribute = utilityNetworkDefinition.GetNetworkAttribute("Shape length"))
{
// Create a function that adds up shape length
Add lengthFunction = new Add(shapeLengthNetworkAttribute);

// Create a function barrier that stops traversal after 1000 feet
FunctionBarrier distanceBarrier = new FunctionBarrier(lengthFunction, Operator.GreaterThan, 1000.0);

// Set this function barrier
traceConfiguration.Traversability.FunctionBarriers = new List<FunctionBarrier>() { distanceBarrier };
}

创建输出条件

1
2
3
// Create an output category to filter the trace results to only include
// features with the "Service Point" category assigned
traceConfiguration.OutputCondition = new CategoryComparison(CategoryOperator.IsEqual, "Service Point");

创建传播器

1
2
3
4
5
6
7
8
9
10
11
// Get a NetworkAttribute object for the Phases Normal attribute from the UtilityNetworkDefinition
using (NetworkAttribute normalPhaseAttribute = utilityNetworkDefinition.GetNetworkAttribute("Phases Normal"))
{
// Create a propagator to propagate the Phases Normal attribute downstream from the source, using a Bitwise And function
// Allow traversal to continue as long as the Phases Normal value includes any of the ABC phases
// (represented by the constant ABCPhase)
Propagator phasePropagator = new Propagator(normalPhaseAttribute, PropagatorFunction.BitwiseAnd, Operator.IncludesAny, ABCPhase);

// Assign this propagator to our trace configuration
traceConfiguration.Propagators = new List<Propagator>() { phasePropagator };
}

使用函数结果

1
2
3
4
5
6
7
8
9
// Get the FunctionOutputResult from the trace results
FunctionOutputResult functionOutputResult = traceResults.OfType<FunctionOutputResult>().First();

// First() can be used here if only one Function was included in the TraceConfiguration.Functions collection.
// Otherwise you will have to search the list for the correct FunctionOutput object.
FunctionOutput functionOutput = functionOutputResult.FunctionOutputs.First();

// Extract the total load from the GlobalValue property
double totalLoad = (double)functionOutput.Value;

按名称获取命名跟踪配置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
private void GetNamedTraceConfigurationsByName(UtilityNetwork utilityNetwork, string configurationName)
{
// Query to find named trace configurations
NamedTraceConfigurationQuery namedTraceConfigurationQuery = new NamedTraceConfigurationQuery { Names = new List<string> { configurationName } };

// Get the trace manager from the utility network
using (TraceManager traceManager = utilityNetwork.GetTraceManager())
{
// A set of named trace configurations specified by the named traced configuration query
IReadOnlyList<NamedTraceConfiguration> namedTraceConfigurations = traceManager.GetNamedTraceConfigurations(namedTraceConfigurationQuery);

foreach (NamedTraceConfiguration namedTraceConfiguration in namedTraceConfigurations)
{
// Use NamedTraceConfiguration's object
}
}
}

从公共设施网络图层获取指定追踪配置

1
2
3
4
5
6
7
8
9
10
private void GetNamedTraceConfigurationsFromUtilityNetworkLayer(UtilityNetworkLayer utilityNetworkLayer)
{
// Get all named trace configurations in the utility network
IReadOnlyList<NamedTraceConfiguration> namedTraceConfigurations = utilityNetworkLayer.GetNamedTraceConfigurations();

foreach (NamedTraceConfiguration namedTraceConfiguration in namedTraceConfigurations)
{
// Use NamedTraceConfiguration's object
}
}

使用指定追踪配置追踪公共设施网络

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
private void TraceUtilityNetworkUsingNamedTraceConfiguration(UtilityNetwork utilityNetwork, NamedTraceConfiguration namedTraceConfiguration, Element startElement)
{
// Get the trace manager from the utility network
using (TraceManager traceManager = utilityNetwork.GetTraceManager())
{
// Get a tracer from the trace manager using the named trace configuration
Tracer upstreamTracer = traceManager.GetTracer(namedTraceConfiguration);

// Trace argument holding the trace input parameters
TraceArgument upstreamTraceArgument = new TraceArgument(namedTraceConfiguration, new List<Element> {startElement});

// Trace results
IReadOnlyList<Result> upstreamTraceResults = upstreamTracer.Trace(upstreamTraceArgument);
}
}

网络图

获取图管理器

1
2
3
4
using (DiagramManager diagramManager = utilityNetwork.GetDiagramManager())
{
// Todo - do something
}

获取网络图

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
using (DiagramManager diagramManager = utilityNetwork.GetDiagramManager())
{
// get all the diagrams
IReadOnlyList<NetworkDiagram> diagrams = diagramManager.GetNetworkDiagrams();

// get a diagram by name
NetworkDiagram diagram = diagramManager.GetNetworkDiagram(diagrameName);

// get diagrams by extent
diagrams = diagramManager.GetNetworkDiagrams(extentOfInterest);

// get diagrams from a set of utility network feature GlobalIDs
diagrams = diagramManager.GetNetworkDiagrams(globalIDs);

// get diagrams from a set of utility network feature GlobalIDs within an extent
diagrams = diagramManager.GetNetworkDiagrams(extentOfInterest, globalIDs);
}

获取具有不一致一致性状态的网络图列表

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
public List<NetworkDiagram> GetInconsistentDiagrams(UtilityNetwork utilityNetwork)
{
// Get the DiagramManager from the utility network

using (DiagramManager diagramManager = utilityNetwork.GetDiagramManager())
{
List<NetworkDiagram> myList = new List<NetworkDiagram>();

// Loop through the network diagrams in the diagram manager

foreach (NetworkDiagram diagram in diagramManager.GetNetworkDiagrams())
{
NetworkDiagramInfo diagramInfo = diagram.GetDiagramInfo();

// If the diagram is not a system diagram and is in an inconsistent state, add it to our list

if (!diagramInfo.IsSystem && diagram.GetConsistencyState() != NetworkDiagramConsistencyState.DiagramIsConsistent)
{
myList.Add(diagram);
}
else
{
diagram.Dispose(); // If we are not returning it we need to Dispose it
}
}

return myList;
}
}

从网络逻辑示意图中打开逻辑示意图窗格

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// Create a diagram layer from a NetworkDiagram (myDiagram)
DiagramLayer diagramLayer = await QueuedTask.Run<DiagramLayer>(() =>
{
// Create the diagram map
var newMap = MapFactory.Instance.CreateMap(myDiagram.Name, ArcGIS.Core.CIM.MapType.NetworkDiagram, MapViewingMode.Map);
if (newMap == null)
return null;

// Open the diagram map
var mapPane = ArcGIS.Desktop.Core.ProApp.Panes.CreateMapPaneAsync(newMap, MapViewingMode.Map);
if (mapPane == null)
return null;

//Add the diagram to the map
return newMap.AddDiagramLayer(myDiagram);
});

从关系图层获取关系图

1
2
3
4
5
6
7
8
9
10
11
12
public void GetDiagram(DiagramLayer diagramLayer)
{
// note - methods need to run on MCT

NetworkDiagram diagram = diagramLayer.GetNetworkDiagram();

// get the consistency state from the layer
DiagramLayerConsistencyState dlState = diagramLayer.ConsistencyState;

// or from the diagram
NetworkDiagramConsistencyState ndState = diagram.GetConsistencyState();
}

获取图表模板

1
2
3
4
5
6
7
8
9
10
11
public void RetrieveDiagramTemplates(UtilityNetwork utilityNetwork)
{
using (DiagramManager diagramManager = utilityNetwork.GetDiagramManager())
{
// get all templates
IReadOnlyList<DiagramTemplate> templates = diagramManager.GetDiagramTemplates();

// get a template by name
DiagramTemplate template = diagramManager.GetDiagramTemplate(templateName);
}
}

从逻辑示意图模板获取网络逻辑示意图

1
2
3
4
5
6
7
8
9
10
11
12
13
14
public void GetNetworkDiagramFromDiagramTemplates(UtilityNetwork utilityNetwork)
{
using (DiagramManager diagramManager = utilityNetwork.GetDiagramManager())
{
// get the first templates
DiagramTemplate template = diagramManager.GetDiagramTemplates().FirstOrDefault();

// get the network diagrams fromt he template
IEnumerable<NetworkDiagram> diagrams = template.GetNetworkDiagrams();

// or get a network diagram by name
NetworkDiagram diagram = template.GetNetworkDiagram(diagrameName);
}
}

创建网络图

1
2
3
4
5
6
7
8
9
10
11
public void CreateNetworkDiagram(UtilityNetwork utilityNetwork, IEnumerable<Guid> globalIDs)
{
using (DiagramManager diagramManager = utilityNetwork.GetDiagramManager())
{
// get the template
DiagramTemplate template = diagramManager.GetDiagramTemplate(templateName);

// create the diagram
NetworkDiagram diagram = diagramManager.CreateNetworkDiagram(template, globalIDs);
}
}

以 JSON 字符串形式获取网络逻辑示意图信息

1
2
3
4
5
6
7
8
9
10
public void GetDiagramContent(UtilityNetwork utilityNetwork)
{
using (DiagramManager diagramManager = utilityNetwork.GetDiagramManager())
{
// get a diagram by name
NetworkDiagram diagram = diagramManager.GetNetworkDiagram(templateName);

string json_content = diagram.GetContent(true, true, true, true);
}
}

获取图元素

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
public void GetDiagramElements(MapView mapView, NetworkDiagram networkDiagram)
{
// Create a DiagramElementQueryByExtent to retrieve diagram element junctions whose extent
// intersects the active map extent

DiagramElementQueryByExtent elementQuery = new DiagramElementQueryByExtent();
elementQuery.ExtentOfInterest = MapView.Active.Extent;
elementQuery.AddContents = false;
elementQuery.QueryDiagramJunctionElement = true;
elementQuery.QueryDiagramEdgeElement = false;
elementQuery.QueryDiagramContainerElement = false;

// Use this DiagramElementQueryByExtent as an argument to the QueryDiagramElements method
DiagramElementQueryResult result = networkDiagram.QueryDiagramElements(elementQuery);

// get the container, junction, edge elements
// in this case result.DiagramJunctionElements and result.DiagramEdgeElements will be empty
// since elementQuery.QueryDiagramEdgeElement and elementQuery.QueryDiagramContainerElement are set to false
IReadOnlyList<DiagramContainerElement> containerElements = result.DiagramContainerElements;

IReadOnlyList<DiagramJunctionElement> junctionElements = result.DiagramJunctionElements;

IReadOnlyList<DiagramEdgeElement> edgeElements = result.DiagramEdgeElements;
}

获取逻辑示意图聚合

1
2
3
4
5
6
7
8
public void GetDiagramAggregation(NetworkDiagram networkDiagram)
{
IReadOnlyList<DiagramAggregation> aggregations = networkDiagram.GetAggregations();
foreach (var aggregation in aggregations)
{
var type = aggregation.AggregationType;
}
}

查找一组公共设施网络行的逻辑示意图要素

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public void FindDiagramFeatures(NetworkDiagram diagram, List<Guid> globalIDs)
{
FindDiagramFeatureQuery featureQuery = new FindDiagramFeatureQuery();
featureQuery.NetworkRowGlobalIDs = globalIDs;
featureQuery.AddAggregations = true;
featureQuery.AddConnectivityAssociations = true;
featureQuery.AddStructuralAttachments = true;

IReadOnlyList<FindResultItem> features = diagram.FindDiagramFeatures(featureQuery);
foreach (var findFeature in features)
{
long objectID = findFeature.ObjectID;
Guid guid = findFeature.GlobalID;
GeometryType geometryType = findFeature.GeometryType;
int sourceID = findFeature.SourceID;
}
}

查找一组逻辑示意图要素的公共设施网络行

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public void FindDiagramRows(NetworkDiagram diagram, List<Guid> globalIDs)
{
FindNetworkRowQuery rowQuery = new FindNetworkRowQuery();
rowQuery.DiagramFeatureGlobalIDs = globalIDs;
rowQuery.AddAggregations = true;

IReadOnlyList<FindResultItem> rows = diagram.FindNetworkRows(rowQuery);
foreach (var findRow in rows)
{
long objectID = findRow.ObjectID;
Guid guid = findRow.GlobalID;
GeometryType geometryType = findRow.GeometryType;
int sourceID = findRow.SourceID;
}
}

查找用于创建网络逻辑示意图的初始网络行

1
2
3
4
5
6
7
8
9
10
11
public void FindInitialNetworkRows(NetworkDiagram diagram)
{
IReadOnlyList<FindResultItem> rows = diagram.FindInitialNetworkRows();
foreach (var findRow in rows)
{
long objectID = findRow.ObjectID;
Guid guid = findRow.GlobalID;
GeometryType geometryType = findRow.GeometryType;
int sourceID = findRow.SourceID;
}
}

更改网络逻辑示意图的布局

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
public void DiagramElementQueryResultAndNetworkDiagramSubsetClasses(Geodatabase geodatabase, DiagramManager diagramManager, string diagramName)
{
// Retrieve a diagram
using (NetworkDiagram diagramTest = diagramManager.GetNetworkDiagram(diagramName))
{
// Create a DiagramElementQueryByElementTypes query object to get the diagram elements we want to work with
DiagramElementQueryByElementTypes query = new DiagramElementQueryByElementTypes();
query.QueryDiagramJunctionElement = true;
query.QueryDiagramEdgeElement = true;
query.QueryDiagramContainerElement = true;

// Retrieve those diagram elements
DiagramElementQueryResult elements = diagramTest.QueryDiagramElements(query);

// Create a NetworkDiagramSubset object to edit this set of diagram elements
NetworkDiagramSubset subset = new NetworkDiagramSubset();
subset.DiagramJunctionElements = elements.DiagramJunctionElements;
subset.DiagramEdgeElements = elements.DiagramEdgeElements;
subset.DiagramContainerElements = elements.DiagramContainerElements;

// Edit the shapes of the diagram elements - left as an exercise for the student
TranslateDiagramElements(subset);

// Save the new layout of the diagram elements
diagramTest.SaveLayout(subset, true);
}
}

编辑网络图

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
public void EditDiagram(NetworkDiagram diagram, List<Guid> globalIDs)
{
// These routines generate their own editing transaction, and therefore cannot be wrapped
// in a separate transaction. Because the editing performed by these routines cannot
// be undone, thise routines can also not be called within an editing session. All
// edits in the current edit session must be saved or discarded before calling these
// routines.

// refresh the diagram - synchronizes it based on the latest network topology
diagram.Update();

// append features to the diagram
diagram.Append(globalIDs);

// overite the diagram with a set of features
diagram.Overwrite(globalIDs);

NetworkDiagramInfo info = diagram.GetDiagramInfo();
if (info.CanExtend)
{
diagram.Extend(NetworkDiagramExtendType.ExtendByContainment);

// or extend for only a set of utility network globalIDs
diagram.Extend(NetworkDiagramExtendType.ExtendByContainment, globalIDs);
}
// delete a diagran
diagram.Delete();
}

宗地结构

获取活动记录

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
string errorMessage = await QueuedTask.Run(() =>
{
try
{
var myParcelFabricLayer = MapView.Active.Map.GetLayersAsFlattenedList().OfType<ParcelLayer>().FirstOrDefault();
//if there is no fabric in the map then bail
if (myParcelFabricLayer == null)
return "There is no fabric in the map.";
var theActiveRecord = myParcelFabricLayer.GetActiveRecord();
if (theActiveRecord == null)
return "There is no Active Record. Please set the active record and try again.";
}
catch (Exception ex)
{
return ex.Message;
}
return "";
});
if (!string.IsNullOrEmpty(errorMessage))
MessageBox.Show(errorMessage, "Get Active Record.");

设置活动记录

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
string errorMessage = await QueuedTask.Run(async () =>
{
try
{
string sExistingRecord = "MyRecordName";
var myParcelFabricLayer = MapView.Active.Map.GetLayersAsFlattenedList().OfType<ParcelLayer>().FirstOrDefault();
//if there is no fabric in the map then bail
if (myParcelFabricLayer == null)
return "There is no fabric in the map.";

bool bSuccess = await myParcelFabricLayer.SetActiveRecordAsync(sExistingRecord);
if (!bSuccess)
return "No record called " + sExistingRecord + " was found.";
}
catch (Exception ex)
{
return ex.Message;
}
return "";
});
if (!string.IsNullOrEmpty(errorMessage))
MessageBox.Show(errorMessage, "Set Active Record.");

创建新记录

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
string errorMessage = await QueuedTask.Run(async () =>
{
Dictionary<string, object> RecordAttributes = new Dictionary<string, object>();
string sNewRecord = "MyRecordName";
try
{
var myParcelFabricLayer = MapView.Active.Map.GetLayersAsFlattenedList().OfType<ParcelLayer>().FirstOrDefault();
//if there is no fabric in the map then bail
if (myParcelFabricLayer == null)
return "There is no fabric in the map.";
var recordsLayer = await myParcelFabricLayer.GetRecordsLayerAsync();
var editOper = new EditOperation()
{
Name = "Create Parcel Fabric Record",
ProgressMessage = "Create Parcel Fabric Record...",
ShowModalMessageAfterFailure = true,
SelectNewFeatures = false,
SelectModifiedFeatures = false
};
RecordAttributes.Add("Name", sNewRecord);
var editRowToken = editOper.Create(recordsLayer.FirstOrDefault(), RecordAttributes);
if (!editOper.Execute())
return editOper.ErrorMessage;

var defOID = -1;
var lOid = editRowToken.ObjectID.HasValue ? editRowToken.ObjectID.Value : defOID;
await myParcelFabricLayer.SetActiveRecordAsync(lOid);
}
catch (Exception ex)
{
return ex.Message;
}
return "";
});
if (!string.IsNullOrEmpty(errorMessage))
MessageBox.Show(errorMessage, "Create New Record.");

将标准线要素复制到宗地类型

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
string errorMessage = await QueuedTask.Run( async () =>
{
// check for selected layer
if (MapView.Active.GetSelectedLayers().Count == 0)
return "Please select a target parcel polygon layer in the table of contents.";
//get the feature layer that's selected in the table of contents
var destPolygonL = MapView.Active.GetSelectedLayers().OfType<FeatureLayer>().FirstOrDefault();
try
{
var myParcelFabricLayer = MapView.Active.Map.GetLayersAsFlattenedList().OfType<ParcelLayer>().FirstOrDefault();
//if there is no fabric in the map then bail
if (myParcelFabricLayer == null)
return "There is no fabric in the map.";
var pRec = myParcelFabricLayer.GetActiveRecord();
if (pRec == null)
return "There is no Active Record. Please set the active record and try again.";
string ParcelTypeName = "";
IEnumerable<string> parcelTypeNames = await myParcelFabricLayer.GetParcelTypeNamesAsync();
foreach (string parcelTypeNm in parcelTypeNames)
{
var polygonLyrParcelTypeEnum = await myParcelFabricLayer.GetParcelPolygonLayerByTypeNameAsync(parcelTypeNm);
foreach (FeatureLayer lyr in polygonLyrParcelTypeEnum)
if (lyr == destPolygonL)
{
ParcelTypeName = parcelTypeNm;
break;
}
}
if (String.IsNullOrEmpty(ParcelTypeName))
return "Please select a target parcel polygon layer in the table of contents.";
var srcFeatLyr = MapView.Active.Map.GetLayersAsFlattenedList().OfType<FeatureLayer>().FirstOrDefault(l => l.Name.Contains("MySourceLines") && l.IsVisible);
if (srcFeatLyr == null)
return "Looking for a layer named 'MySourceLines' in the table of contents.";
//now get the line layer for this parcel type
var destLineLyrEnum = await myParcelFabricLayer.GetParcelLineLayerByTypeNameAsync(ParcelTypeName);
if (destLineLyrEnum.Count() == 0) //make sure there is one in the map
return ParcelTypeName + " not found.";
var destLineL = destLineLyrEnum.FirstOrDefault();
if (destLineL == null || destPolygonL == null)
return "";
var editOper = new EditOperation()
{
Name = "Copy Line Features To Parcel Type",
ProgressMessage = "Copy Line Features To Parcel Type...",
ShowModalMessageAfterFailure = true,
SelectNewFeatures = true,
SelectModifiedFeatures = false
};
var ids = new List<long>((srcFeatLyr as FeatureLayer).GetSelection().GetObjectIDs());
if (ids.Count == 0)
return "No selected lines were found. Please select line features and try again.";
editOper.CopyLineFeaturesToParcelType(srcFeatLyr, ids, destLineL, destPolygonL);
if (!editOper.Execute())
return editOper.ErrorMessage;
}
catch (Exception ex)
{
return ex.Message;
}
return "";
});
if (!string.IsNullOrEmpty(errorMessage))
MessageBox.Show(errorMessage, "Copy Line Features To Parcel Type.");

将宗地行复制到宗地类型

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
string errorMessage = await QueuedTask.Run( async () =>
{
// check for selected layer
if (MapView.Active.GetSelectedLayers().Count == 0)
return "Please select a source parcel polygon feature layer in the table of contents.";
try
{
var myParcelFabricLayer = MapView.Active.Map.GetLayersAsFlattenedList().OfType<ParcelLayer>().FirstOrDefault();
if (myParcelFabricLayer == null)
return "No parcel layer found in the map.";

//get the feature layer that's selected in the table of contents
var srcParcelFeatLyr = MapView.Active.GetSelectedLayers().OfType<FeatureLayer>().FirstOrDefault();
string sTargetParcelType = "Tax";
var destLineLEnum = await myParcelFabricLayer.GetParcelLineLayerByTypeNameAsync(sTargetParcelType);
if (destLineLEnum.Count() == 0)
return "";
var destLineL = destLineLEnum.FirstOrDefault();
var destPolygonLEnum = await myParcelFabricLayer.GetParcelPolygonLayerByTypeNameAsync(sTargetParcelType);
if (destPolygonLEnum.Count() == 0)
return "";
var destPolygonL = destPolygonLEnum.FirstOrDefault();
if (destLineL == null || destPolygonL == null)
return "";
var theActiveRecord = myParcelFabricLayer.GetActiveRecord();
if (theActiveRecord == null)
return "There is no Active Record. Please set the active record and try again.";
var editOper = new EditOperation()
{
Name = "Copy Lines To Parcel Type",
ProgressMessage = "Copy Lines To Parcel Type ...",
ShowModalMessageAfterFailure = true,
SelectNewFeatures = true,
SelectModifiedFeatures = false
};
var ids = new List<long>(srcParcelFeatLyr.GetSelection().GetObjectIDs());
if (ids.Count == 0)
return "No selected parcels found. Please select parcels and try again.";
//add the standard feature line layers source, and their feature ids to a new Dictionary
var sourceParcelFeatures = new Dictionary<MapMember, List<long>>();
sourceParcelFeatures.Add(srcParcelFeatLyr, ids);
editOper.CopyParcelLinesToParcelType(myParcelFabricLayer, SelectionSet.FromDictionary(sourceParcelFeatures), destLineL, destPolygonL, true, false, true);
if (!editOper.Execute())
return editOper.ErrorMessage;
}
catch (Exception ex)
{
return ex.Message;
}
return "";
});
if (!string.IsNullOrEmpty(errorMessage))
MessageBox.Show(errorMessage, "Copy Parcel Lines To Parcel Type.");

将要素分配给活动记录

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
string errorMessage = await QueuedTask.Run( () =>
{
//check for selected layer
if (MapView.Active.GetSelectedLayers().Count == 0)
return "Please select a source feature layer in the table of contents.";
//first get the feature layer that's selected in the table of contents
var srcFeatLyr = MapView.Active.GetSelectedLayers().OfType<FeatureLayer>().FirstOrDefault();
var myParcelFabricLayer = MapView.Active.Map.GetLayersAsFlattenedList().OfType<ParcelLayer>().FirstOrDefault();
if (myParcelFabricLayer == null)
return "No parcel layer found in the map.";
try
{
var theActiveRecord = myParcelFabricLayer.GetActiveRecord();
if (theActiveRecord == null)
return "There is no Active Record. Please set the active record and try again.";
var editOper = new EditOperation()
{
Name = "Assign Features to Record",
ProgressMessage = "Assign Features to Record...",
ShowModalMessageAfterFailure = true,
SelectNewFeatures = true,
SelectModifiedFeatures = false
};
//add parcel type layers and their feature ids to a new Dictionary
var ids = new List<long>(srcFeatLyr.GetSelection().GetObjectIDs());
var sourceFeatures = new Dictionary<MapMember, List<long>>();
sourceFeatures.Add(srcFeatLyr, ids);
editOper.AssignFeaturesToRecord(myParcelFabricLayer,
SelectionSet.FromDictionary(sourceFeatures), theActiveRecord);
if (!editOper.Execute())
return editOper.ErrorMessage;
}
catch (Exception ex)
{
return ex.Message;
}
return "";
});
if (!string.IsNullOrEmpty(errorMessage))
MessageBox.Show(errorMessage, "Assign Features To Record.");

创建宗地种子

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
try
{
var theActiveRecord = myParcelFabricLayer.GetActiveRecord();
if (theActiveRecord == null)
return "There is no Active Record. Please set the active record and try again.";

var guid = theActiveRecord.Guid;
var editOper = new EditOperation()
{
Name = "Create Parcel Seeds",
ProgressMessage = "Create Parcel Seeds...",
ShowModalMessageAfterFailure = true,
SelectNewFeatures = true,
SelectModifiedFeatures = false
};
editOper.CreateParcelSeedsByRecord(myParcelFabricLayer, guid, MapView.Active.Extent);
if (!editOper.Execute())
return editOper.ErrorMessage;
}
catch (Exception ex)
{
return ex.Message;
}
return "";

构建宗地

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
try
{
var myParcelFabricLayer = MapView.Active.Map.GetLayersAsFlattenedList().OfType<ParcelLayer>().FirstOrDefault();
if (myParcelFabricLayer == null)
return "Parcel layer not found in map.";

var theActiveRecord = myParcelFabricLayer.GetActiveRecord();
var guid = theActiveRecord.Guid;
var editOper = new EditOperation()
{
Name = "Build Parcels",
ProgressMessage = "Build Parcels...",
ShowModalMessageAfterFailure = true,
SelectNewFeatures = true,
SelectModifiedFeatures = true
};
editOper.BuildParcelsByRecord(myParcelFabricLayer, guid);
if (!editOper.Execute())
return editOper.ErrorMessage;
}
catch (Exception ex)
{
return ex.Message;
}
return "";

重复的包裹

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
var myParcelFabricLayer = MapView.Active.Map.GetLayersAsFlattenedList().OfType<ParcelLayer>().FirstOrDefault();
if (myParcelFabricLayer == null)
return "Parecl layer not found in the map.";
//get the source polygon layer from the parcel fabric layer type, in this case a layer called Lot
var srcFeatLyrEnum = await myParcelFabricLayer.GetParcelPolygonLayerByTypeNameAsync("Lot");
if (srcFeatLyrEnum.Count() == 0)
return "";
var sourcePolygonL = srcFeatLyrEnum.FirstOrDefault();
//get the target polygon layer from the parcel fabric layer type, in this case a layer called Tax
var targetFeatLyrEnum = await myParcelFabricLayer.GetParcelPolygonLayerByTypeNameAsync("Tax");
if (targetFeatLyrEnum.Count() == 0)
return "";
var targetFeatLyr = targetFeatLyrEnum.FirstOrDefault();
var ids = new List<long>(sourcePolygonL.GetSelection().GetObjectIDs());
if (ids.Count == 0)
return "No selected parcels found. Please select parcels and try again.";
//add polygon layers and the feature ids to be duplicated to a new Dictionary
var sourceFeatures = new Dictionary<MapMember, List<long>>();
sourceFeatures.Add(sourcePolygonL, ids);
try
{
var theActiveRecord = myParcelFabricLayer.GetActiveRecord();
if (theActiveRecord == null)
return "There is no Active Record. Please set the active record and try again.";
var editOper = new EditOperation()
{
Name = "Duplicate Parcels",
ProgressMessage = "Duplicate Parcels...",
ShowModalMessageAfterFailure = true,
SelectNewFeatures = true,
SelectModifiedFeatures = false
};
editOper.DuplicateParcels(myParcelFabricLayer,
SelectionSet.FromDictionary(sourceFeatures), theActiveRecord, targetFeatLyr);
if (!editOper.Execute())
return editOper.ErrorMessage;
}
catch (Exception ex)
{
return ex.Message;
}

设置历史宗地

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
string errorMessage = await QueuedTask.Run(async () =>
{
var myParcelFabricLayer = MapView.Active.Map.GetLayersAsFlattenedList().OfType<ParcelLayer>().FirstOrDefault();
if (myParcelFabricLayer == null)
return "Please add a parcel fabric to the map";
try
{
FeatureLayer destPolygonL = null;
//find the first layer that is a parcel type, is non-historic, and has a selection
bool bFound = false;
var ParcelTypesEnum = await myParcelFabricLayer.GetParcelTypeNamesAsync();
foreach (FeatureLayer mapFeatLyr in MapView.Active.Map.GetLayersAsFlattenedList().OfType<FeatureLayer>())
{
foreach (string ParcelType in ParcelTypesEnum)
{
var layerEnum = await myParcelFabricLayer.GetParcelPolygonLayerByTypeNameAsync(ParcelType);
foreach (FeatureLayer flyr in layerEnum)
{
if (flyr == mapFeatLyr)
{
bFound = mapFeatLyr.SelectionCount > 0;
destPolygonL = mapFeatLyr;
break;
}
}
if (bFound) break;
}
if (bFound) break;
}
if (!bFound)
return "Please select parcels to set as historic.";

var theActiveRecord = myParcelFabricLayer.GetActiveRecord();
if (theActiveRecord == null)
return "There is no Active Record. Please set the active record and try again.";

var ids = new List<long>(destPolygonL.GetSelection().GetObjectIDs());
//can do multi layer selection but using single per code above
var sourceFeatures = new Dictionary<MapMember, List<long>>();
sourceFeatures.Add(destPolygonL, ids);
var editOper = new EditOperation()
{
Name = "Set Parcels Historic",
ProgressMessage = "Set Parcels Historic...",
ShowModalMessageAfterFailure = true,
SelectNewFeatures = true,
SelectModifiedFeatures = false
};
editOper.SetParcelHistoryRetired(myParcelFabricLayer,
SelectionSet.FromDictionary(sourceFeatures), theActiveRecord);
if (!editOper.Execute())
return editOper.ErrorMessage;
}
catch (Exception ex)
{
return ex.Message;
}
return "";
});
if (!string.IsNullOrEmpty(errorMessage))
MessageBox.Show(errorMessage, "Set Parcels Historic.");

将包裹收缩为种子

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
string errorMessage = await QueuedTask.Run(async () =>
{
var myParcelFabricLayer = MapView.Active.Map.GetLayersAsFlattenedList().OfType<ParcelLayer>().FirstOrDefault();
if (myParcelFabricLayer == null)
return "Please add a parcel fabric to the map";
try
{
FeatureLayer parcelPolygonLyr = null;
//find the first layer that is a polygon parcel type, is non-historic, and has a selection
bool bFound = false;
var ParcelTypesEnum = await myParcelFabricLayer.GetParcelTypeNamesAsync();
foreach (FeatureLayer mapFeatLyr in MapView.Active.Map.GetLayersAsFlattenedList().OfType<FeatureLayer>())
{
foreach (string ParcelType in ParcelTypesEnum)
{
var layerEnum = await myParcelFabricLayer.GetParcelPolygonLayerByTypeNameAsync(ParcelType);
foreach (FeatureLayer flyr in layerEnum)
{
if (flyr == mapFeatLyr)
{
bFound = mapFeatLyr.SelectionCount > 0;
parcelPolygonLyr = mapFeatLyr;
break;
}
}
if (bFound) break;
}
if (bFound) break;
}
if (!bFound)
return "Please select parcels to shrink to seeds.";
var editOper = new EditOperation()
{
Name = "Shrink Parcels To Seeds",
ProgressMessage = "Shrink Parcels To Seeds...",
ShowModalMessageAfterFailure = true,
SelectNewFeatures = true,
SelectModifiedFeatures = false
};
var ids = new List<long>(parcelPolygonLyr.GetSelection().GetObjectIDs());
var sourceParcelFeatures = new Dictionary<MapMember, List<long>>();
sourceParcelFeatures.Add(parcelPolygonLyr, ids);
editOper.ShrinkParcelsToSeeds(myParcelFabricLayer,SelectionSet.FromDictionary(sourceParcelFeatures));
if (!editOper.Execute())
return editOper.ErrorMessage;
}
catch (Exception ex)
{
return ex.Message;
}
return "";
});
if (!string.IsNullOrEmpty(errorMessage))
MessageBox.Show(errorMessage, "Shrink Parcels To Seeds.");

更改宗地类型

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
//add polygon layers and the feature ids to change the type on to a new Dictionary
var ids = new List<long>(sourcePolygonL.GetSelection().GetObjectIDs());
var sourceFeatures = new Dictionary<MapMember, List<long>>();
sourceFeatures.Add(sourcePolygonL, ids);
try
{
var editOper = new EditOperation()
{
Name = "Change Parcel Type",
ProgressMessage = "Change Parcel Type...",
ShowModalMessageAfterFailure = true,
SelectNewFeatures = true,
SelectModifiedFeatures = false
};
editOper.ChangeParcelType(myParcelFabricLayer, SelectionSet.FromDictionary(sourceFeatures), targetFeatLyr);
if (!editOper.Execute())
return editOper.ErrorMessage;
}
catch (Exception ex)
{
return ex.Message;
}
return "";

获取宗地要素

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
string sReportResult = "Polygon Information --" + Environment.NewLine;
string sParcelTypeName = "tax";
string errorMessage = await QueuedTask.Run(async () =>
{
var myParcelFabricLayer =
MapView.Active.Map.GetLayersAsFlattenedList().OfType<ParcelLayer>().FirstOrDefault();
//if there is no fabric in the map then bail
if (myParcelFabricLayer == null)
return "There is no fabric layer in the map.";

//first get the parcel type feature layer
var featSrcLyr = myParcelFabricLayer.GetParcelPolygonLayerByTypeNameAsync(sParcelTypeName).Result.FirstOrDefault();

if (featSrcLyr.SelectionCount == 0)
return "There is no selection on the " + sParcelTypeName + " layer.";

sReportResult += " Parcel Type: " + sParcelTypeName + Environment.NewLine;
sReportResult += " Poygons: " + featSrcLyr.SelectionCount + Environment.NewLine + Environment.NewLine;

try
{
// ------- get the selected parcels ---------
var ids = new List<long>((featSrcLyr as FeatureLayer).GetSelection().GetObjectIDs());
var sourceParcels = new Dictionary<MapMember, List<long>>();
sourceParcels.Add(featSrcLyr, ids);
//---------------------------------------------
ParcelFeatures parcFeatures =
await myParcelFabricLayer.GetParcelFeaturesAsync(SelectionSet.FromDictionary(sourceParcels));
//since we know that we want to report on Tax lines only, and for this functionality
// we can use any of the Tax line layer instances (if there happens to be more than one)
// we can get the first instance as follows
FeatureLayer myLineFeatureLyr =
myParcelFabricLayer.GetParcelLineLayerByTypeNameAsync(sParcelTypeName).Result.FirstOrDefault();
if (myLineFeatureLyr == null)
return sParcelTypeName + " line layer not found";

FeatureLayer myPointFeatureLyr =
myParcelFabricLayer.GetPointsLayerAsync().Result.FirstOrDefault();
if (myPointFeatureLyr == null)
return "fabric point layer not found";

var LineInfo = parcFeatures.Lines; //then get the line information from the parcel features object
//... and then do some work for each of the lines
int iRadiusAttributeCnt = 0;
int iDistanceAttributeCnt = 0;
sReportResult += "Line Information --";
foreach (KeyValuePair<string, List<long>> kvp in LineInfo)
{
if (kvp.Key.ToLower() != sParcelTypeName)
continue; // ignore any other lines from different parcel types

foreach (long oid in kvp.Value)
{
var insp = myLineFeatureLyr.Inspect(oid);
var dRadius = insp["RADIUS"];
var dDistance = insp["DISTANCE"];

if (dRadius != DBNull.Value)
iRadiusAttributeCnt++;
if (dDistance != DBNull.Value)
iDistanceAttributeCnt++;
//Polyline poly = (Polyline)insp["SHAPE"];
}
sReportResult += Environment.NewLine + " Distance attributes: " + iDistanceAttributeCnt.ToString();
sReportResult += Environment.NewLine + " Radius attributes: " + iRadiusAttributeCnt.ToString();
}

var PointInfo = parcFeatures.Points; //get the point information from the parcel features object
//... and then do some work for each of the points
sReportResult += Environment.NewLine + Environment.NewLine + "Point Information --";
int iFixedPointCnt = 0;
int iNonFixedPointCnt = 0;
foreach (long oid in PointInfo)
{
var insp = myPointFeatureLyr.Inspect(oid);
var isFixed = insp["ISFIXED"];
if (isFixed == DBNull.Value || (int)isFixed == 0)
iNonFixedPointCnt++;
else
iFixedPointCnt++;
// var pt = insp["SHAPE"];

}
sReportResult += Environment.NewLine + " Fixed Points: " + iFixedPointCnt.ToString();
sReportResult += Environment.NewLine + " Non-Fixed Points: " + iNonFixedPointCnt.ToString();
}
catch (Exception ex)
{
return ex.Message;
}
return "";
});
if (!string.IsNullOrEmpty(errorMessage))
MessageBox.Show(errorMessage, "Get Parcel Features");
else
MessageBox.Show(sReportResult, "Get Parcel Features");

从宗地图层获取宗地结构数据集控制器

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
string errorMessage = await QueuedTask.Run(() =>
{
try
{
var myParcelFabricLayer = MapView.Active.Map.GetLayersAsFlattenedList().OfType<ParcelLayer>().FirstOrDefault();
//if there is no fabric in the map then bail
if (myParcelFabricLayer == null)
return "There is no fabric in the map.";
var myParcelFabricDataset = myParcelFabricLayer.GetParcelFabric();
}
catch (Exception ex)
{
return ex.Message;
}
return "";
});
if (!string.IsNullOrEmpty(errorMessage))
MessageBox.Show(errorMessage, "Get Parcel Fabric Dataset from layer.");

获取宗地结构数据集的宗地拓扑

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
string errorMessage = await QueuedTask.Run(() =>
{
try
{
var myParcelFabricLayer = MapView.Active.Map.GetLayersAsFlattenedList().OfType<ParcelLayer>().FirstOrDefault();
//if there is no fabric in the map then bail
if (myParcelFabricLayer == null)
return "There is no fabric in the map.";
var myParcelFabricDataset = myParcelFabricLayer.GetParcelFabric();
var myTopology = myParcelFabricDataset.GetParcelTopology();
}
catch (Exception ex)
{
return ex.Message;
}
return "";
});
if (!string.IsNullOrEmpty(errorMessage))
MessageBox.Show(errorMessage, "Get Parcel Fabric Topology.");

从宗地结构数据集中获取点、连接和记录要素类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
string errorMessage = await QueuedTask.Run(() =>
{
try
{
var myParcelFabricLayer = MapView.Active.Map.GetLayersAsFlattenedList().OfType<ParcelLayer>().FirstOrDefault();
//if there is no fabric in the map then bail
if (myParcelFabricLayer == null)
return "There is no fabric in the map.";
var myParcelFabricDataset = myParcelFabricLayer.GetParcelFabric();
FeatureClass myPointsFC = myParcelFabricDataset.GetSystemTable(SystemTableType.Points) as FeatureClass;
FeatureClass myCoonectionsFC = myParcelFabricDataset.GetSystemTable(SystemTableType.Connections) as FeatureClass;
FeatureClass myRecordsFC = myParcelFabricDataset.GetSystemTable(SystemTableType.Records) as FeatureClass;
}
catch (Exception ex)
{
return ex.Message;
}
return "";
});
if (!string.IsNullOrEmpty(errorMessage))
MessageBox.Show(errorMessage, "Get point, connection, and record feature classes.");

从宗地结构数据集获取宗地类型要素类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
string errorMessage = await QueuedTask.Run(() =>
{
try
{
var myParcelFabricLayer = MapView.Active.Map.GetLayersAsFlattenedList().OfType<ParcelLayer>().FirstOrDefault();
//if there is no fabric in the map then bail
if (myParcelFabricLayer == null)
return "There is no fabric in the map.";
string myParcelTypeName = "Tax";
var myParcelFabricDataset = myParcelFabricLayer.GetParcelFabric();
var typeInfo = myParcelFabricDataset.GetParcelTypeInfo();
FeatureClass lineFCType = null;
FeatureClass polyFCType = null;
foreach (var info in typeInfo)
{
if (info.Name.ToLower() == myParcelTypeName.ToLower())
{
lineFCType = info.LineFeatureTable as FeatureClass;
polyFCType = info.PolygonFeatureTable as FeatureClass;
break;
}
}
}
catch (Exception ex)
{
return ex.Message;
}
return "";
});
if (!string.IsNullOrEmpty(errorMessage))
MessageBox.Show(errorMessage, "Get Parcel Type feature classes.");

从要素图层获取宗地类型名称

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
private async Task<string> GetParcelTypeNameFromFeatureLayer(ParcelLayer myParcelFabricLayer, FeatureLayer featLayer, GeometryType geomType)
{
if (featLayer == null) //nothing to do, return empty string
return String.Empty;
IEnumerable<string> parcelTypeNames = await myParcelFabricLayer.GetParcelTypeNamesAsync();
foreach (string parcelTypeName in parcelTypeNames)
{
if (geomType == GeometryType.Polygon)
{
var polygonLyrParcelTypeEnum = await myParcelFabricLayer.GetParcelPolygonLayerByTypeNameAsync(parcelTypeName);
foreach (FeatureLayer lyr in polygonLyrParcelTypeEnum)
if (lyr == featLayer)
return parcelTypeName;

polygonLyrParcelTypeEnum = await myParcelFabricLayer.GetHistoricParcelPolygonLayerByTypeNameAsync(parcelTypeName);
foreach (FeatureLayer lyr in polygonLyrParcelTypeEnum)
if (lyr == featLayer)
return parcelTypeName;
}
if (geomType == GeometryType.Polyline)
{
var lineLyrParcelTypeEnum = await myParcelFabricLayer.GetParcelLineLayerByTypeNameAsync(parcelTypeName);
foreach (FeatureLayer lyr in lineLyrParcelTypeEnum)
if (lyr == featLayer)
return parcelTypeName;

lineLyrParcelTypeEnum = await myParcelFabricLayer.GetHistoricParcelLineLayerByTypeNameAsync(parcelTypeName);
foreach (FeatureLayer lyr in lineLyrParcelTypeEnum)
if (lyr == featLayer)
return parcelTypeName;
}
}
return String.Empty;
}

从表中获取宗地结构

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
public static ParcelFabric GetParcelFabricFromTable(Table table)
{
ParcelFabric myParcelFabricDataset = null;
if (table.IsControllerDatasetSupported())
{
// Tables can belong to multiple controller datasets, but at most one of them will be a parcel fabric

IReadOnlyList<Dataset> controllerDatasets = table.GetControllerDatasets();
foreach (Dataset controllerDataset in controllerDatasets)
{
if (controllerDataset is ParcelFabric)
{
myParcelFabricDataset = controllerDataset as ParcelFabric;
}
else
{
controllerDataset.Dispose();
}
}
}
return myParcelFabricDataset;
}

光栅

在文件夹中打开栅格数据集

1
2
3
4
5
6
// Create a FileSystemConnectionPath using the folder path.
FileSystemConnectionPath connectionPath = new FileSystemConnectionPath(new System.Uri(@"C:\Temp"), FileSystemDatastoreType.Raster);
// Create a new FileSystemDatastore using the FileSystemConnectionPath.
FileSystemDatastore dataStore = new FileSystemDatastore(connectionPath);
// Open the raster dataset.
RasterDataset fileRasterDataset = dataStore.OpenDataset<RasterDataset>("Sample.tif");

在地理数据库中打开栅格数据集

1
2
3
4
5
6
// Create a FileGeodatabaseConnectionPath using the path to the gdb. Note: This can be a path to a .sde file.
FileGeodatabaseConnectionPath geodatabaseConnectionPath = new FileGeodatabaseConnectionPath(new Uri(@"C:\Temp\rasters.gdb"));
// Create a new Geodatabase object using the FileGeodatabaseConnectionPath.
Geodatabase geodatabase = new Geodatabase(geodatabaseConnectionPath);
// Open the raster dataset.
RasterDataset gdbRasterDataset = geodatabase.OpenDataset<RasterDataset>("sample");

从栅格数据集获取栅格数据集定义

1
2
3
4
5
6
7
await QueuedTask.Run(() =>
{
RasterDatasetDefinition rasterDatasetDefinition = rasterDataset.GetDefinition();

// access the dataset definition properties
rasterDatasetDefinition.GetBandCount();
});

访问栅格数据集中的波段

1
2
3
4
5
6
7
8
9
10
11
var count = rasterDataset.GetBandCount();
RasterBand rasterBandByName = rasterDataset.GetBandByName(sBandName);
var index = rasterDataset.GetBandIndex(sBandName);

// Get a RasterBand from the raster dataset
RasterBand rasterBand = rasterDataset.GetBand(0);

// Get the RasterBandDefinition from the raster band.
RasterBandDefinition rasterBandDefinition = rasterBand.GetDefinition();
// Get the name of the raster band from the raster band.
string bandName = rasterBandDefinition.GetName();

访问栅格属性表中的行

1
2
3
4
5
6
7
8
9
10
11
12
13
var raster = MapView.Active.Map.GetLayersAsFlattenedList().OfType<RasterLayer>().FirstOrDefault();
if (raster != null)
{
await QueuedTask.Run(() =>
{
var rasterTbl = raster.GetRaster().GetAttributeTable();
var cursor = rasterTbl.Search();
while (cursor.MoveNext())
{
var row = cursor.Current;
}
});
}

创建栅格光标以循环访问栅格数据

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
await QueuedTask.Run(() =>
{
// Create a full raster from the raster dataset.
ArcGIS.Core.Data.Raster.Raster raster = rasterDataset.CreateFullRaster();

// Calculate size of pixel blocks to process. Use 1000 or height/width of the raster, whichever is smaller.
var height = raster.GetHeight();
var width = raster.GetWidth();
int pixelBlockHeight = height > 1000 ? 1000 : height;
int pixelBlockWidth = width > 1000 ? 1000 : width;

// Create the raster cursor using the height and width calculated.
RasterCursor rasterCursor = raster.CreateCursor(pixelBlockWidth, pixelBlockHeight);

// Use a do-while loop to iterate through the pixel blocks of the raster using the raster cursor.
do
{
// Get the current pixel block from the cursor.
using (PixelBlock currentPixelBlock = rasterCursor.Current)
{
// Do something with the pixel block...
}

// Once you are done, move to the next pixel block.
}
while (rasterCursor.MoveNext());
});

使用像素块在栅格数据集中读取和写入像素

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
await QueuedTask.Run(() =>
{
// Create a full raster from the raster dataset.
ArcGIS.Core.Data.Raster.Raster raster = rasterDataset.CreateFullRaster();

// Calculate size of pixel block to create. Use 128 or height/width of the raster, whichever is smaller.
var height = raster.GetHeight();
var width = raster.GetWidth();
int pixelBlockHeight = height > 128 ? 128 : height;
int pixelBlockWidth = width > 128 ? 128 : width;

// Create a new (blank) pixel block.
PixelBlock currentPixelBlock = raster.CreatePixelBlock(pixelBlockWidth, pixelBlockHeight);

// Read pixel values from the raster dataset into the pixel block starting from the given top left corner.
raster.Read(0, 0, currentPixelBlock);

// Do something with the pixel block...

// Write the pixel block to the raster dataset starting from the given top left corner.
raster.Write(0, 0, currentPixelBlock);
});

使用像素块处理像素

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
await QueuedTask.Run(() =>
{
// Read pixel values from the raster dataset into the pixel block starting from the given top left corner.
raster.Read(0, 0, currentPixelBlock);

// For each plane (band) in the pixel block
for (int plane = 0; plane < currentPixelBlock.GetPlaneCount(); plane++)
{
// Get a copy of the array of pixels from the pixel block corresponding to the current plane.
Array sourcePixels = currentPixelBlock.GetPixelData(plane, true);
// Get the height and width of the pixel block.
int pBHeight = currentPixelBlock.GetHeight();
int pBWidth = currentPixelBlock.GetWidth();

// Iterate through the pixels in the array.
for (int i = 0; i < pBHeight; i++)
{
for (int j = 0; j < pBWidth; j++)
{
// Get the NoData mask value to see if the pixel is a valid pixel.
if (Convert.ToByte(currentPixelBlock.GetNoDataMaskValue(plane, j, i)) == 1)
{
// Get the pixel value from the array and process it (add 5 to the value).
// Note: This is assuming the pixel type is Unisigned 8bit.
int pixelValue = Convert.ToInt16(sourcePixels.GetValue(j, i)) + 5;
// Make sure the pixel value does not go above the range of the pixel type.
pixelValue = pixelValue > 254 ? 254 : pixelValue;
// Set the new pixel value to the array.
// Note: This is assuming the pixel type is Unisigned 8bit.
sourcePixels.SetValue(Convert.ToByte(pixelValue), j, i);
}
}
}
// Set the modified array of pixels back to the pixel block.
currentPixelBlock.SetPixelData(plane, sourcePixels);
}
// Write the pixel block to the raster dataset starting from the given top left corner.
raster.Write(0, 0, currentPixelBlock);
});

计算栅格统计数据

1
2
3
4
5
6
7
8
9
10
11
12
//If a raster dataset has statistics, you can create a raster layer and get these statistics by accessing the colorizer.
await QueuedTask.Run(() =>
{
//Accessing the raster layer
var lyr = MapView.Active.Map.GetLayersAsFlattenedList().OfType<BasicRasterLayer>().FirstOrDefault();
//Getting the colorizer
var colorizer = lyr.GetColorizer() as CIMRasterStretchColorizer;
//Accessing the statistics
var stats = colorizer.StretchStats;
var max = stats.max;
var min = stats.min;
});

场景图层

创建场景图层

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
var sceneLayerUrl = @"https://myportal.com/server/rest/services/Hosted/SceneLayerServiceName/SceneServer";
//portal items also ok as long as the portal is the current active portal...
//var sceneLayerUrl = @"https://myportal.com/home/item.html?id=123456789abcdef1234567890abcdef0";

await QueuedTask.Run(() =>
{
//Create with initial visibility set to false. Add to current scene
var createparams = new LayerCreationParams(new Uri(sceneLayerUrl, UriKind.Absolute))
{
IsVisible = false
};

//cast to specific type of scene layer being created - in this case FeatureSceneLayer
var sceneLayer = LayerFactory.Instance.CreateLayer<Layer>(
createparams, MapView.Active.Map) as FeatureSceneLayer;
//or...specify the cast directly
var sceneLayer2 = LayerFactory.Instance.CreateLayer<FeatureSceneLayer>(
createparams, MapView.Active.Map);
//ditto for BuildingSceneLayer, PointCloudSceneLayer, IntegratedMeshSceneLayer
//...
});

建筑领域场景图层

获取建筑规程场景图层规程

1
2
var bsl_discipline = MapView.Active.Map.GetLayersAsFlattenedList().OfType<BuildingDisciplineSceneLayer>().FirstOrDefault(l => l.Name == "Architectural");
var disciplineName = bsl_discipline.GetDiscipline();

枚举建筑物场景图层中的领域图层

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
public void QueryBuildingSceneLayer()
{
var bldgLayer = MapView.Active.Map.GetLayersAsFlattenedList().OfType<BuildingSceneLayer>().First();
var disciplines = new Dictionary<string, BuildingDisciplineSceneLayer>();
//A Building layer has two children - Overview and FullModel
//Overview is a FeatureSceneLayer
//Full Model is a BuildingDisciplineSceneLayer that contains the disciplines

var fullModel = bldgLayer.FindLayers("Full Model").First()
as BuildingDisciplineSceneLayer;
CollectDisciplineLayers(fullModel, disciplines);

}

internal void CollectDisciplineLayers(BuildingDisciplineSceneLayer disciplineLayer,
Dictionary<string, BuildingDisciplineSceneLayer> disciplines)
{
//collect information on the disciplines
var name = disciplineLayer.Name;
//At 2.x - var layerType =
// ((ISceneLayerInfo)disciplineLayer).SceneServiceLayerType.ToString();

var discipline = disciplineLayer.GetDiscipline();
//etc
//TODO - use collected information

disciplines.Add(discipline, disciplineLayer);

//Discipline layers are composite layers too
foreach (var childDiscipline in disciplineLayer.Layers
.OfType<BuildingDisciplineSceneLayer>())
{
//Discipline layers can also contain FeatureSceneLayers that render the
//individual full model contents
var content_names = string.Join(", ", childDiscipline.Layers
.OfType<FeatureSceneLayer>().Select(fl => fl.Name));
CollectDisciplineLayers(childDiscipline, disciplines);
}
}

建筑物场景图层

建筑物场景图层的名称

1
2
3
var bsl = MapView.Active.Map.GetLayersAsFlattenedList()
.OfType<BuildingSceneLayer>().FirstOrDefault();
var scenelayerName = bsl.Name;

查询建筑物场景图层以获取可用的类型和值

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
//Must be called on the MCT
//Retrieve the complete set of types and values for the building scene
//var bsl = ...;
//At 2.x - var dict = bsl.QueryAvailableFieldsAndValues();
var dict = bsl.GetAvailableFieldsAndValues();

//get a list of existing disciplines
var disciplines = dict.SingleOrDefault(
kvp => kvp.Key == "Discipline").Value ?? new List<string>();

//get a list of existing categories
var categories = dict.SingleOrDefault(
kvp => kvp.Key == "Category").Value ?? new List<string>();

//get a list of existing floors or "levels"
var floors = dict.SingleOrDefault(
kvp => kvp.Key == "BldgLevel").Value ?? new List<string>();

创建默认筛选器并获取筛选器计数

1
2
3
4
5
6
7
8
9
10
//Must be called on the MCT
//Creates a default filter on the building scene
//var bsl = ...;
var filter1 = bsl.CreateDefaultFilter();
var values = filter1.FilterBlockDefinitions[0].SelectedValues;
//values will be a single value for the type
//"CreatedPhase", value "New Construction"

//There will be at least one filter after "CreateDefaultFilter()" call
var filtersCount = bsl.GetFilters().Count;

获取包含线框块的所有过滤器

1
2
3
4
5
6
7
8
9
10
//var bsl = ...;
//Note: wire_frame_filters can be null in this example
var wire_frame_filters = bsl.GetFilters().Where(
f => f.FilterBlockDefinitions.Any(
fb => fb.FilterBlockMode == Object3DRenderingMode.Wireframe));
//substitute Object3DRenderingMode.None to get blocks with a solid mode (default)
//and...
//fb.FilterBlockMode == Object3DRenderingMode.Wireframe &&
//fb.FilterBlockMode == Object3DRenderingMode.None
//for blocks with both

设置和清除建筑物场景图层的活动过滤器

1
2
3
4
5
6
7
8
9
//Must be called on the MCT
//Note: Use HasFilter to check if a given filter id exists in the layer
//var bsl = ...;
if (bsl.HasFilter(filter1.ID))
bsl.SetActiveFilter(filter1.ID);
var activeFilter = bsl.GetActiveFilter();

//Clear the active filter
bsl.ClearActiveFilter();

获取建筑物场景图层过滤器 ID 和过滤器

1
2
3
4
string filterID1 = filter1.ID;
var filter = bsl.GetFilter(filterID1);
//or via Linq
//var filter = bsl.GetFilters().FirstOrDefault(f => f.ID == filterID1);

修改建筑物场景图层过滤器名称和描述

1
2
3
4
5
6
7
8
//Must be called on the MCT
//var bsl = ...;
//var filter1 = bsl.GetFilter(filterID1);

filter1.Name = "Updated Filter Name";
filter1.Description = "Updated Filter description";
//At 2.x - bsl.SetFilter(filter1);
bsl.UpdateFilter(filter);

使用建筑物标高和类别创建过滤器

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
//Must be called on the MCT

//refer to "Query Building Scene Layer for available Types and Values"
//...
//var bsl = ...;
//At 2.x
//var dict = bsl.QueryAvailableFieldsAndValues();

//var dict = bsl.GetAvailableFieldsAndValues();
//var categories = dict.SingleOrDefault(kvp => kvp.Key == "Category").Value;
//var floors = dict.SingleOrDefault(kvp => kvp.Key == "BldgLevel").Value;

//Make a new filter definition
var fd = new FilterDefinition()
{
Name = "Floor and Category Filter",
Description = "Example filter",
};
//Set up the values for the filter
var filtervals = new Dictionary<string, List<string>>();
filtervals.Add("BldgLevel", new List<string>() { floors[0] });
var category_vals = categories.Where(v => v == "Walls" || v == "Stairs").ToList() ?? new List<string>();
if (category_vals.Count() > 0)
{
filtervals.Add("Category", category_vals);
}
//Create a solid block (other option is "Wireframe")
var fdef = new FilterBlockDefinition()
{
FilterBlockMode = Object3DRenderingMode.None,
Title = "Solid Filter",
SelectedValues = filtervals//Floor and Category
};
//Apply the block
fd.FilterBlockDefinitions = new List<FilterBlockDefinition>() { fdef };
//Add the filter definition to the layer
//At 2.x - bsl.SetFilter(fd);
bsl.UpdateFilter(fd);
//Set it active. The ID is auto-generated
bsl.SetActiveFilter(fd.ID);

修改建筑物场景图层过滤器块

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
//Must be called on the MCT
//Assuming retrieve filter ok
//var bsl = ...;
//var filter1 = bsl.GetFilter(...);

var filterBlock = new FilterBlockDefinition();
filterBlock.FilterBlockMode = Object3DRenderingMode.Wireframe;

var selectedValues = new Dictionary<string, List<string>>();
//We assume QueryAvailableFieldsAndValues() contains "Walls" and "Doors"
//For 'Category'
selectedValues["Category"] = new List<string>() { "Walls", "Doors" };
filterBlock.SelectedValues = selectedValues;

//Overwrite
filter1.FilterBlockDefinitions = new List<FilterBlockDefinition>() { filterBlock };
//At 2.x - bsl.SetFilter(filter1);
bsl.UpdateFilter(filter1);

移除建筑物场景图层过滤器

1
2
3
4
5
6
7
//var bsl = ...;
//Note: Use HasFilter to check if a given filter id exists in the layer
//Must be called on the MCT
if (bsl.HasFilter(filter1.ID))
bsl.RemoveFilter(filter1.ID);
//Or remove all filters
bsl.RemoveAllFilters();

要素场景图层编辑

确定要素场景图层是否支持编辑

1
2
3
4
5
6
7
var featSceneLayer = MapView.Active.Map.GetLayersAsFlattenedList()
.OfType<FeatureSceneLayer>().FirstOrDefault();
if (!featSceneLayer.HasAssociatedFeatureService ||
!featSceneLayer.IsEditable)
return;//not supported

//TODO continue editing here...

在要素场景图层中创建新点要素

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
//must support editing!
//var featSceneLayer = ... ;
if (!featSceneLayer.HasAssociatedFeatureService ||
!featSceneLayer.IsEditable)
return;
//Check geometry type...must be point in this example
if (featSceneLayer.ShapeType != esriGeometryType.esriGeometryPoint)
return;

var editOp = new EditOperation()
{
Name = "Create new 3d point feature",
SelectNewFeatures = true
};

var attributes = new Dictionary<string, object>();
//mapPoint contains the new 3d point location
attributes.Add("SHAPE", mapPoint);
attributes.Add("TreeID", "1");
editOp.Create(featSceneLayer, attributes);
editOp.ExecuteAsync();//fyi, no await

删除要素场景图层中的所有选定要素

1
2
3
4
5
6
7
8
9
10
11
12
13
//must support editing!
//var featSceneLayer = .... ;
if (!featSceneLayer.HasAssociatedFeatureService ||
!featSceneLayer.IsEditable)
return;

var delOp = new EditOperation()
{
Name = "Delete selected features"
};
//Assuming we have a selection on the layer...
delOp.Delete(featSceneLayer, featSceneLayer.GetSelection().GetObjectIDs());
await delOp.ExecuteAsync();//await if needed but not required

编辑要素场景图层的属性

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
//must support editing!
var featSceneLayer = MapView.Active.Map.GetLayersAsFlattenedList()
.OfType<FeatureSceneLayer>().FirstOrDefault();
if (!featSceneLayer.HasAssociatedFeatureService ||
!featSceneLayer.IsEditable)
return;

var ok = await QueuedTask.Run(() =>
{
var editOp = new EditOperation()
{
Name = "Edit FeatureSceneLayer Attributes",
SelectModifiedFeatures = true
};
//make an inspector
var inspector = new Inspector();
//get the attributes for the specified oid
inspector.Load(featSceneLayer, oid);
inspector["PermitNotes"] = "test";//modify
editOp.Modify(inspector);
return editOp.Execute();//synchronous flavor
});

要素场景图层

要素场景图层的名称

1
2
3
var featSceneLayer = MapView.Active.Map.GetLayersAsFlattenedList()
.OfType<FeatureSceneLayer>().FirstOrDefault();
var scenelayerName = featSceneLayer?.Name;

获取数据源类型

1
2
3
4
5
6
7
8
9
10
11
//Must be called on the MCT
var dataSourceType = featSceneLayer?.GetDataSourceType() ??
SceneLayerDataSourceType.Unknown;
if (dataSourceType == SceneLayerDataSourceType.SLPK)
{
//Uses SLPK - only cached attributes
}
else if (dataSourceType == SceneLayerDataSourceType.Service)
{
//Hosted service - can have live attributes - check HasAssociatedFeatureService
}

获取关联的要素类

1
2
3
4
5
6
7
8
9
//var featSceneLayer = ....;
if (featSceneLayer.HasAssociatedFeatureService)
{
//Must be called on the MCT
using (var fc = featSceneLayer.GetFeatureClass())
{
//TODO query underlying feature class
}
}

获取字段定义

1
2
3
4
5
6
7
8
9
//var featSceneLayer = ....;
await QueuedTask.Run(() =>
{
//Get only the readonly fields
var readOnlyFields = featSceneLayer.GetFieldDescriptions()
.Where(fdesc => fdesc.IsReadOnly);
//etc

});

设置定义查询

1
2
3
//Must be called on the MCT
//var featSceneLayer = ...;
featSceneLayer.SetDefinitionQuery("Name = 'Ponderosa Pine'");

通过地图视图选择要素

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
//assume the geometry used in SelectFeaturesEx() is coming from a 
//map tool...
//
//SketchType = SketchGeometryType.Rectangle;
//SketchOutputMode = SketchOutputMode.Screen;

await QueuedTask.Run(() =>
{
var result = MapView.Active.SelectFeaturesEx(geometry);
//Get scene layers with selections
//At 2.x - var scene_layers = result.Where(kvp => kvp.Key is FeatureSceneLayer);
var scene_layers = result.ToDictionary<FeatureSceneLayer>();
foreach (var kvp in scene_layers)
{
var scene_layer = kvp.Key as FeatureSceneLayer;
var sel_oids = kvp.Value;
//If there are attributes then get them
if (scene_layer.HasAssociatedFeatureService)
{
var insp = new Inspector();
foreach (var oid in sel_oids)
{
insp.Load(scene_layer, oid);
//TODO something with retrieved attributes
}
}
}
});

具有关联的要素服务

1
2
3
4
5
6
7
var featSceneLayer = MapView.Active.Map.GetLayersAsFlattenedList()
.OfType<FeatureSceneLayer>().First();
if (featSceneLayer.HasAssociatedFeatureService)
{
//Can Select and Search...possibly edit

}

搜索要素场景图层上的行

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
//var featSceneLayer = ...;
if (!featSceneLayer.HasAssociatedFeatureService)
return;//Search and Select not supported

//Multipatch (Object3D) or point?
//var is3dObject = ((ISceneLayerInfo)featSceneLayer).SceneServiceLayerType
// == esriSceneServiceLayerType.Object3D;
var is3dObject = featSceneLayer.FeatureSceneLayerType == FeatureSceneLayerType.Object3D;
await QueuedTask.Run(() =>
{
var queryFilter = new QueryFilter
{
WhereClause = "Name = 'Ponderosa Pine'",
SubFields = "*"
};

int rowCount = 0;
//or select... var select = featSceneLayer.Select(queryFilter)
using (RowCursor rowCursor = featSceneLayer.Search(queryFilter))
{
while (rowCursor.MoveNext())
{
using (var feature = rowCursor.Current as Feature)
{
var oid = feature.GetObjectID();
var shape = feature.GetShape();
var attrib = feature["Name"];
if (is3dObject)
{
//shape is a multipatch
}
else
{
//shape is a point
}
rowCount += 1;
}

}
}

});

隐藏所选要素和显示隐藏要素

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
//var featSceneLayer = ...;
if (featSceneLayer.HasAssociatedFeatureService)
return;//Search and Select not supported

await QueuedTask.Run(() =>
{
QueryFilter qf = new QueryFilter()
{
ObjectIDs = new List<long>() { 6069, 6070, 6071 },
SubFields = "*"
};
featSceneLayer.Select(qf, SelectionCombinationMethod.New);

featSceneLayer.HideSelectedFeatures();
var selectionCount = featSceneLayer.SelectionCount;

featSceneLayer.ShowHiddenFeatures();
selectionCount = featSceneLayer.SelectionCount;

});

使用 MapView Select SelectFeaturesEx 或 GetFeaturesEx

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
//var featSceneLayer = ...;
var sname = featSceneLayer.Name;

await QueuedTask.Run(() =>
{
//Select all features within the current map view
var sz = MapView.Active.GetViewSize();

var c_ll = new Coordinate2D(0, 0);
var c_ur = new Coordinate2D(sz.Width, sz.Height);
//Use screen coordinates for 3D selection on MapView
var env = EnvelopeBuilderEx.CreateEnvelope(c_ll, c_ur);

//HasAssociatedFeatureService does not matter for SelectFeaturesEx
//or GetFeaturesEx
var result = MapView.Active.SelectFeaturesEx(env);
//var result = MapView.Active.GetFeaturesEx(env);

//The list of object ids from SelectFeaturesEx
//At 2.x - var oids1 = result.Where(kvp => kvp.Key.Name == sname).First().Value;
var oids1 = result.ToDictionary().Where(kvp => kvp.Key.Name == sname).First().Value;
//TODO - use the object ids

MapView.Active.Map.ClearSelection();
});

对空间查询使用选择或搜索

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
//var featSceneLayer = ...;
//var sname = featSceneLayer.Name;
await QueuedTask.Run(() =>
{
if (!featSceneLayer.HasAssociatedFeatureService)
return;//no search or select

//Select all features within the current map view
var sz = MapView.Active.GetViewSize();
var map_pt1 = MapView.Active.ClientToMap(new System.Windows.Point(0, sz.Height));
var map_pt2 = MapView.Active.ClientToMap(new System.Windows.Point(sz.Width, 0));

//Convert to an envelope
var temp_env = EnvelopeBuilderEx.CreateEnvelope(map_pt1, map_pt2, MapView.Active.Map.SpatialReference);

//Project if needed to the layer spatial ref
SpatialReference sr = null;
using (var fc = featSceneLayer.GetFeatureClass())
using (var fdef = fc.GetDefinition())
sr = fdef.GetSpatialReference();

var env = GeometryEngine.Instance.Project(temp_env, sr) as Envelope;

//Set up a query filter
var sf = new SpatialQueryFilter()
{
FilterGeometry = env,
SpatialRelationship = SpatialRelationship.Intersects,
SubFields = "*"
};

//Select against the feature service
var select = featSceneLayer.Select(sf);
if (select.GetCount() > 0)
{
//enumerate over the selected features
using (var rc = select.Search())
{
while (rc.MoveNext())
{
using (var feature = rc.Current as Feature)
{
var oid = feature.GetObjectID();
//etc.
}
}
}
}

MapView.Active.Map.ClearSelection();

});

点云场景图层

点云场景图层的名称

1
2
3
var pcsl = MapView.Active.Map.GetLayersAsFlattenedList()
.OfType<PointCloudSceneLayer>().FirstOrDefault();
var scenelayerName = pcsl?.Name;

获取点云场景图层的数据源类型

1
2
3
4
5
6
7
8
9
10
11
12
13
//var pcsl = ...;
//At 2.x - ISceneLayerInfo slInfo = pcsl as ISceneLayerInfo;
// SceneLayerDataSourceType dataSourceType = slInfo.GetDataSourceType();

SceneLayerDataSourceType dataSourceType = pcsl.GetDataSourceType();
if (dataSourceType == SceneLayerDataSourceType.Service)
{
//TODO...
}
else if (dataSourceType == SceneLayerDataSourceType.SLPK)
{

}

查询点云场景图层中的所有类代码和标签

1
2
3
4
5
6
7
//Must be called on the MCT
//var pcsl = ...;
//At 2.x - Dictionary<int, string> classCodesAndLabels =
// pcsl.QueryAvailableClassCodesAndLabels();

Dictionary<int, string> classCodesAndLabels =
pcsl.GetAvailableClassCodesAndLabels();

为点云场景图层设置过滤器

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
//Must be called on the MCT
//var pcsl = ...;
//Retrieve the available classification codes
//At 2.x - var dict = pcsl.QueryAvailableClassCodesAndLabels();
var dict = pcsl.GetAvailableClassCodesAndLabels();

//Filter out low noise and unclassified (7 and 1 respectively)
//consult https://pro.arcgis.com/en/pro-app/help/data/las-dataset/storing-lidar-data.htm
var filterDef = new PointCloudFilterDefinition()
{
ClassCodes = dict.Keys.Where(c => c != 7 && c != 1).ToList(),
ReturnValues = new List<PointCloudReturnType> {
PointCloudReturnType.FirstOfMany }
};
//apply the filter
pcsl.SetFilters(filterDef.ToCIM());

更新 PointCloudSceneLayer 的类标志

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
//Must be called on the MCT
//var pcsl = ...;
var filters = pcsl.GetFilters();
PointCloudFilterDefinition fdef = null;
if (filters.Count() == 0)
{
fdef = new PointCloudFilterDefinition()
{
//7 is "edge of flight line" - exclude
ClassFlags = new List<ClassFlag> {
new ClassFlag(7, ClassFlagOption.Exclude) }
};
}
else
{
fdef = PointCloudFilterDefinition.FromCIM(filters);
//keep any include or ignore class flags
var keep = fdef.ClassFlags.Where(
cf => cf.ClassFlagOption != ClassFlagOption.Exclude).ToList();
//7 is "edge of flight line" - exclude
keep.Add(new ClassFlag(7, ClassFlagOption.Exclude));
fdef.ClassFlags = keep;
}
//apply
pcsl.SetFilters(fdef.ToCIM());

获取 PointCloudSceneLayer 的过滤器

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
//Must be called on the MCT
//var pcsl = ...;
IReadOnlyList<CIMPointCloudFilter> updatedFilter = pcsl.GetFilters();
foreach (var filter in updatedFilter)
{
//There is either 0 or 1 of each
if (filter is CIMPointCloudReturnFilter returnFilter)
{
PointCloudFilterDefinition pcfl = PointCloudFilterDefinition.FromCIM(updatedFilter);
List<PointCloudReturnType> updatedReturnValues = pcfl.ReturnValues;

}
if (filter is CIMPointCloudValueFilter classCodesFilter)
{
// do something
}

if (filter is CIMPointCloudBitFieldFilter classFlagsFilter)
{
// do something
}
}

清除点云场景图层中的过滤器

1
2
3
//Must be called on the MCT
//var pcsl = ...;
pcsl.ClearFilters();

获取点云场景图层渲染器和渲染器类型

1
2
3
4
5
//Must be called on the MCT
//var pcsl = ...;
CIMPointCloudRenderer cimGetPCLRenderer = pcsl.GetRenderer();
//Can be one of Unknown, Stretch, ClassBreaks, UniqueValue, RGB
PointCloudRendererType pclRendererType = pcsl.RendererType;

查询点云场景图层渲染器字段

1
2
3
4
5
6
7
//Must be called on the MCT
//var pcsl = ...;
//At 2.x - IReadOnlyList<string> flds = pcsl.QueryAvailablePointCloudRendererFields(
// PointCloudRendererType.UniqueValueRenderer);
IReadOnlyList<string> flds = pcsl.GetAvailablePointCloudRendererFields(
PointCloudRendererType.UniqueValueRenderer);
var fldCount = flds.Count;

创建和设置拉伸渲染器

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
//Must be called on the MCT
//var pcsl = ...;

//At 2.x - var fields = pcsl.QueryAvailablePointCloudRendererFields(
// PointCloudRendererType.StretchRenderer);

var fields = pcsl.GetAvailablePointCloudRendererFields(
PointCloudRendererType.StretchRenderer);
var stretchDef = new PointCloudRendererDefinition(
PointCloudRendererType.StretchRenderer)
{
//Will be either ELEVATION or INTENSITY
Field = fields[0]
};
//Create the CIM Renderer
var stretchRenderer = pcsl.CreateRenderer(stretchDef)
as CIMPointCloudStretchRenderer;
//Apply a color ramp
var style = Project.Current.GetItems<StyleProjectItem>()
.First(s => s.Name == "ArcGIS Colors");
var colorRamp = style.SearchColorRamps("").First();
stretchRenderer.ColorRamp = colorRamp.ColorRamp;
//Apply modulation
stretchRenderer.ColorModulation = new CIMColorModulationInfo()
{
MinValue = 0,
MaxValue = 100
};
//apply the renderer
pcsl.SetRenderer(stretchRenderer);

创建和设置分类间隔渲染器

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
//Must be called on the MCT
//var pcsl = ...;

//At 2.x - var fields = pcsl.QueryAvailablePointCloudRendererFields(
// PointCloudRendererType.ClassBreaksRenderer);

var fields = pcsl.GetAvailablePointCloudRendererFields(
PointCloudRendererType.ClassBreaksRenderer);
var classBreakDef = new PointCloudRendererDefinition(
PointCloudRendererType.ClassBreaksRenderer)
{
//ELEVATION or INTENSITY
Field = fields[0]
};
//create the renderer
var cbr = pcsl.CreateRenderer(classBreakDef)
as CIMPointCloudClassBreaksRenderer;
//Set up a color scheme to use
var style = Project.Current.GetItems<StyleProjectItem>()
.First(s => s.Name == "ArcGIS Colors");
var rampStyle = style.LookupItem(
StyleItemType.ColorRamp, "Spectrum By Wavelength-Full Bright_Multi-hue_2")
as ColorRampStyleItem;
var colorScheme = rampStyle.ColorRamp;
//Set up 6 manual class breaks
var breaks = 6;
var colors = ColorFactory.Instance.GenerateColorsFromColorRamp(
colorScheme, breaks);
var classBreaks = new List<CIMColorClassBreak>();
var min = cbr.Breaks[0].UpperBound;
var max = cbr.Breaks[cbr.Breaks.Count() - 1].UpperBound;
var step = (max - min) / (double)breaks;

//add in the class breaks
double upper = min;
for (int b = 1; b <= breaks; b++)
{
double lower = upper;
upper = b == breaks ? max : min + (b * step);
var cb = new CIMColorClassBreak()
{
UpperBound = upper,
Label = string.Format("{0:#0.0#} - {1:#0.0#}", lower, upper),
Color = colors[b - 1]
};
classBreaks.Add(cb);
}
cbr.Breaks = classBreaks.ToArray();
pcsl.SetRenderer(cbr);

点云场景图层扩展属性

编辑颜色调制

1
2
3
4
5
6
7
8
9
10
11
12
13
14
//Must be called on the MCT
//var pcsl = ...;
var def = pcsl.GetDefinition() as CIMPointCloudLayer;
//Get the ColorModulation off the renderer
var modulation = def.Renderer.ColorModulation;
if (modulation == null)
modulation = new CIMColorModulationInfo();
//Set the minimum and maximum intensity as needed
modulation.MinValue = 0;
modulation.MaxValue = 100.0;
//apply back
def.Renderer.ColorModulation = modulation;
//Commit changes back to the CIM
pcsl.SetDefinition(def);

编辑渲染器以使用固定大小

1
2
3
4
5
6
7
8
9
10
11
12
13
14
//Must be called on the MCT
//var pcsl = ...;
var def = pcsl.GetDefinition() as CIMPointCloudLayer;

//Set the point shape and sizing on the renderer
def.Renderer.PointShape = PointCloudShapeType.DiskShaded;
var pointSize = new CIMPointCloudFixedSizeAlgorithm()
{
UseRealWorldSymbolSizes = false,
Size = 8
};
def.Renderer.PointSizeAlgorithm = pointSize;
//Commit changes back to the CIM
pcsl.SetDefinition(def);

编辑渲染器以缩放大小

1
2
3
4
5
6
7
8
9
10
11
12
13
14
//Must be called on the MCT
//var pcsl = ...;
var def = pcsl.GetDefinition() as CIMPointCloudLayer;

//Set the point shape and sizing on the renderer
def.Renderer.PointShape = PointCloudShapeType.DiskFlat;//default
var scaleSize = new CIMPointCloudSplatAlgorithm()
{
MinSize = 8,
ScaleFactor = 1.0 //100%
};
def.Renderer.PointSizeAlgorithm = scaleSize;
//Commit changes back to the CIM
pcsl.SetDefinition(def);

编辑密度设置

1
2
3
4
5
6
7
8
9
10
11
12
//Must be called on the MCT
//var pcsl = ...;
var def = pcsl.GetDefinition() as CIMPointCloudLayer;
//PointsBudget - corresponds to Display Limit on the UI
// - the absolute maximum # of points to display
def.PointsBudget = 1000000;

//PointsPerInch - corresponds to Density Min --- Max on the UI
// - the max number of points per display inch to renderer
def.PointsPerInch = 15;
//Commit changes back to the CIM
pcsl.SetDefinition(def);

流图层

创建流图层

使用 URI 创建流图层

1
2
3
4
5
6
7
8
9
10
11
12
//Must be on the QueuedTask
var url = "https://geoeventsample1.esri.com:6443/arcgis/rest/services/AirportTraffics/StreamServer";
var createParam = new FeatureLayerCreationParams(new Uri(url))
{
IsVisible = false //turned off by default
};
var streamLayer = LayerFactory.Instance.CreateLayer<StreamLayer>(createParam, map);

//or use "original" create layer (will be visible by default)
Uri uri = new Uri(url);
streamLayer = LayerFactory.Instance.CreateLayer(uri, map) as StreamLayer;
streamLayer.SetVisibility(false);//turn off

使用定义查询创建流图层

1
2
3
4
5
6
7
8
9
10
11
12
13
14
//Must be on the QueuedTask
var url = "https://geoeventsample1.esri.com:6443/arcgis/rest/services/AirportTraffics/StreamServer";
var lyrCreateParam = new FeatureLayerCreationParams(new Uri(url))
{
IsVisible = true,
//At 2.x - DefinitionFilter = new CIMDefinitionFilter()
//{
// DefinitionExpression = "RWY = '29L'",
// Name = "Runway"
//}
DefinitionQuery = new DefinitionQuery(whereClause: "RWY = '29L'", name: "Runway")
};

var streamLayer = LayerFactory.Instance.CreateLayer<StreamLayer>(lyrCreateParam, map);

使用简单渲染器创建流图层

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
var url = @"https://geoeventsample1.esri.com:6443/arcgis/rest/services/LABus/StreamServer";
var uri = new Uri(url, UriKind.Absolute);
//Must be on QueuedTask!
var createParams = new FeatureLayerCreationParams(uri)
{
RendererDefinition = new SimpleRendererDefinition()
{
SymbolTemplate = SymbolFactory.Instance.ConstructPointSymbol(
ColorFactory.Instance.BlueRGB,
12,
SimpleMarkerStyle.Pushpin).MakeSymbolReference()
}
};
var streamLayer = LayerFactory.Instance.CreateLayer<StreamLayer>(
createParams, map);

为最新观测值设置唯一值渲染器

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
var url = @"https://geoeventsample1.esri.com:6443/arcgis/rest/services/AirportTraffics/StreamServer";
var uri = new Uri(url, UriKind.Absolute);
//Must be on QueuedTask!

var createParams = new FeatureLayerCreationParams(uri)
{
IsVisible = false
};
var streamLayer = LayerFactory.Instance.CreateLayer<StreamLayer>(
createParams, map);
//Define the unique values by hand
var uvr = new CIMUniqueValueRenderer()
{
Fields = new string[] { "ACTYPE" },
UseDefaultSymbol = true,
DefaultLabel = "Others",
DefaultSymbol = SymbolFactory.Instance.ConstructPointSymbol(
CIMColor.CreateRGBColor(185, 185, 185), 8, SimpleMarkerStyle.Hexagon).MakeSymbolReference()
};

var classes = new List<CIMUniqueValueClass>();
//add in classes - one for ACTYPE of 727, one for DC 9
classes.Add(
new CIMUniqueValueClass() {
Values = new CIMUniqueValue[] {
new CIMUniqueValue() { FieldValues = new string[] { "B727" } } },
Visible = true,
Label = "Boeing 727",
Symbol = SymbolFactory.Instance.ConstructPointSymbol(
ColorFactory.Instance.RedRGB, 10, SimpleMarkerStyle.Hexagon).MakeSymbolReference()
});
classes.Add(
new CIMUniqueValueClass()
{
Values = new CIMUniqueValue[] {
new CIMUniqueValue() { FieldValues = new string[] { "DC9" } } },
Visible = true,
Label = "DC 9",
Symbol = SymbolFactory.Instance.ConstructPointSymbol(
ColorFactory.Instance.GreenRGB, 10, SimpleMarkerStyle.Hexagon).MakeSymbolReference()
});
//add the classes to a group
var groups = new List<CIMUniqueValueGroup>()
{
new CIMUniqueValueGroup() {
Classes = classes.ToArray()
}
};
//add the groups to the renderer
uvr.Groups = groups.ToArray();
//Apply the renderer (for current observations)
streamLayer.SetRenderer(uvr);
streamLayer.SetVisibility(true);//turn on the layer

流图层设置和属性

查找所有可识别轨迹的流图层

1
2
var trackAwareLayers = MapView.Active.Map.GetLayersAsFlattenedList()
.OfType<StreamLayer>().Where(sl => sl.IsTrackAware)?.ToList();

确定流图层类型

1
2
3
4
5
6
7
8
9
//spatial or non-spatial?
if (streamLayer.TrackType == TrackType.AttributeOnly)
{
//this is a non-spatial stream layer
}
else
{
//this must be a spatial stream layer
}

检查流图层连接状态

1
2
3
if (!streamLayer.IsStreamingConnectionOpen)
//Must be on QueuedTask!
streamLayer.StartStreaming();

开始和停止流式传输

1
2
3
4
5
//Must be on QueuedTask!
//Start...
streamLayer.StartStreaming();
//Stop...
streamLayer.StopStreaming();

删除所有当前和以前的观察结果

1
2
3
4
//Must be on QueuedTask!
//Must be called on the feature class
using (var rfc = streamLayer.GetFeatureClass())
rfc.Truncate();

获取跟踪 ID 字段

1
2
3
4
5
if (streamLayer.IsTrackAware)
{
var trackField = streamLayer.TrackIdFieldName;
//TODO use the field name
}

获取曲目类型

1
2
3
4
5
6
7
8
9
var trackType = streamLayer.TrackType;
switch(trackType)
{
//TODO deal with tracktype
case TrackType.None:
case TrackType.AttributeOnly:
case TrackType.Spatial:
break;
}

设置要存储在内存中的先前观测值的最大计数

1
2
3
4
5
6
7
8
9
10
//Must be on QueuedTask
//Set Expiration Method and Max Expiration Count
if (streamLayer.GetExpirationMethod() != FeatureExpirationMethod.MaximumFeatureCount)
streamLayer.SetExpirationMethod(FeatureExpirationMethod.MaximumFeatureCount);
streamLayer.SetExpirationMaxCount(15);
//FYI
if (streamLayer.IsTrackAware)
{
//MaxCount is per track! otherwise for the entire layer
}

设置要存储在内存中的先前观测值的最长期限

1
2
3
4
5
6
7
8
9
10
11
12
//Must be on QueuedTask
//Set Expiration Method and Max Expiration Age
if (streamLayer.GetExpirationMethod() != FeatureExpirationMethod.MaximumFeatureAge)
streamLayer.SetExpirationMethod(FeatureExpirationMethod.MaximumFeatureAge);
//set to 12 hours (max is 24 hours)
streamLayer.SetExpirationMaxAge(new TimeSpan(12,0,0));

//FYI
if (streamLayer.IsTrackAware)
{
//MaxAge is per track! otherwise for the entire layer
}

通过 CIM 设置各种流图层属性

1
2
3
4
5
6
7
8
9
10
11
12
13
//The layer must be track aware and spatial
if (streamLayer.TrackType != TrackType.Spatial)
return;
//Must be on QueuedTask
//get the CIM Definition
var def = streamLayer.GetDefinition() as CIMFeatureLayer;
//set the number of previous observations,
def.PreviousObservationsCount = (int)streamLayer.GetExpirationMaxCount() - 1;
//set show previous observations and track lines to true
def.ShowPreviousObservations = true;
def.ShowTracks = true;
//commit the changes
streamLayer.SetDefinition(def);

渲染

定义唯一值呈现器定义

1
2
3
4
5
6
7
8
9
10
11
var uvrDef = new UniqueValueRendererDefinition()
{
ValueFields = new List<string> { "ACTYPE" },
SymbolTemplate = SymbolFactory.Instance.ConstructPointSymbol(
ColorFactory.Instance.RedRGB, 10, SimpleMarkerStyle.Hexagon)
.MakeSymbolReference(),
ValuesLimit = 5
};
//Note: CreateRenderer can only create value classes based on
//the current events it has received
streamLayer.SetRenderer(streamLayer.CreateRenderer(uvrDef));

为最新观测值设置唯一值渲染器

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
//Define the classes by hand to avoid using CreateRenderer(...)
CIMUniqueValueClass uvcB727 = new CIMUniqueValueClass()
{
Values = new CIMUniqueValue[] { new CIMUniqueValue() { FieldValues = new string[] { "B727" } } },
Visible = true,
Label = "Boeing 727",
Symbol = SymbolFactory.Instance.ConstructPointSymbol(CIMColor.CreateRGBColor(255, 0, 0), 8, SimpleMarkerStyle.Hexagon).MakeSymbolReference()
};

CIMUniqueValueClass uvcD9 = new CIMUniqueValueClass()
{
Values = new CIMUniqueValue[] { new CIMUniqueValue() { FieldValues = new string[] { "DC9" } } },
Visible = true,
Label = "DC 9",
Symbol = SymbolFactory.Instance.ConstructPointSymbol(CIMColor.CreateRGBColor(0, 255, 0), 8, SimpleMarkerStyle.Hexagon).MakeSymbolReference()
};
//Assign the classes to a group
CIMUniqueValueGroup uvGrp = new CIMUniqueValueGroup()
{
Classes = new CIMUniqueValueClass[] { uvcB727, uvcD9 }
};
//assign the group to the renderer
var UVrndr = new CIMUniqueValueRenderer()
{
Fields = new string[] { "ACTYPE" },
Groups = new CIMUniqueValueGroup[] { uvGrp },
UseDefaultSymbol = true,
DefaultLabel = "Others",
DefaultSymbol = SymbolFactory.Instance.ConstructPointSymbol(
CIMColor.CreateRGBColor(185, 185, 185), 8, SimpleMarkerStyle.Hexagon).MakeSymbolReference()
};
//set the renderer. Depending on the current events received, the
//layer may or may not have events for each of the specified
//unique value classes
streamLayer.SetRenderer(UVrndr);

为先前的观测值设置唯一值渲染器

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
//The layer must be track aware and spatial
if (streamLayer.TrackType != TrackType.Spatial)
return;
//Must be on QueuedTask!
//Define unique value classes same as we do for current observations
//or use "CreateRenderer(...)" to assign them automatically
CIMUniqueValueClass uvcB727Prev = new CIMUniqueValueClass()
{
Values = new CIMUniqueValue[] { new CIMUniqueValue() {
FieldValues = new string[] { "B727" } } },
Visible = true,
Label = "Boeing 727",
Symbol = SymbolFactory.Instance.ConstructPointSymbol(
CIMColor.CreateRGBColor(255, 0, 0), 4, SimpleMarkerStyle.Hexagon)
.MakeSymbolReference()
};

CIMUniqueValueClass uvcD9Prev = new CIMUniqueValueClass()
{
Values = new CIMUniqueValue[] { new CIMUniqueValue() {
FieldValues = new string[] { "DC9" } } },
Visible = true,
Label = "DC 9",
Symbol = SymbolFactory.Instance.ConstructPointSymbol(
CIMColor.CreateRGBColor(0, 255, 0), 4, SimpleMarkerStyle.Hexagon)
.MakeSymbolReference()
};

CIMUniqueValueGroup uvGrpPrev = new CIMUniqueValueGroup()
{
Classes = new CIMUniqueValueClass[] { uvcB727Prev, uvcD9Prev }
};

var UVrndrPrev = new CIMUniqueValueRenderer()
{
Fields = new string[] { "ACTYPE" },
Groups = new CIMUniqueValueGroup[] { uvGrpPrev },
UseDefaultSymbol = true,
DefaultLabel = "Others",
DefaultSymbol = SymbolFactory.Instance.ConstructPointSymbol(
CIMColor.CreateRGBColor(185, 185, 185), 4, SimpleMarkerStyle.Hexagon)
.MakeSymbolReference()
};

streamLayer.SetRenderer(UVrndr, FeatureRendererTarget.PreviousObservations);

设置简单的渲染器以绘制轨迹线

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
//The layer must be track aware and spatial
if (streamLayer.TrackType != TrackType.Spatial)
return;
//Must be on QueuedTask!
//Note: only a simple renderer with solid line symbol is supported for track
//line renderer
var trackRenderer = new SimpleRendererDefinition()
{
SymbolTemplate = SymbolFactory.Instance.ConstructLineSymbol(
ColorFactory.Instance.BlueRGB, 2, SimpleLineStyle.Solid)
.MakeSymbolReference()
};
streamLayer.SetRenderer(
streamLayer.CreateRenderer(trackRenderer),
FeatureRendererTarget.TrackLines);

检查先前的观测值和轨道线可见性

1
2
3
4
5
6
7
8
9
//The layer must be track aware and spatial for these settings
//to have an effect
if (streamLayer.TrackType != TrackType.Spatial)
return;
//Must be on QueuedTask
if (!streamLayer.AreTrackLinesVisible)
streamLayer.SetTrackLinesVisibility(true);
if (!streamLayer.ArePreviousObservationsVisible)
streamLayer.SetPreviousObservationsVisibility(true);

使轨迹线和先前的观测点可见

1
2
3
4
5
6
7
8
9
10
11
12
13
14
//The layer must be track aware and spatial for these settings
//to have an effect
if (streamLayer.TrackType != TrackType.Spatial)
return;

//Must be on QueuedTask

//Note: Setting PreviousObservationsCount larger than the
//"SetExpirationMaxCount()" has no effect
streamLayer.SetPreviousObservationsCount(6);
if (!streamLayer.AreTrackLinesVisible)
streamLayer.SetTrackLinesVisibility(true);
if (!streamLayer.ArePreviousObservationsVisible)
streamLayer.SetPreviousObservationsVisibility(true);

检索当前观测渲染器

1
2
//Must be on QueuedTask!
var renderer = streamLayer.GetRenderer();

检索上一个观测渲染器

1
2
3
4
5
6
//The layer must be track aware and spatial
if (streamLayer.TrackType != TrackType.Spatial)
return;
//Must be on QueuedTask!
var prev_renderer = streamLayer.GetRenderer(
FeatureRendererTarget.PreviousObservations);

检索轨迹线渲染器

1
2
3
4
5
6
//The layer must be track aware and spatial
if (streamLayer.TrackType != TrackType.Spatial)
return;
//Must be on QueuedTask!
var track_renderer = streamLayer.GetRenderer(
FeatureRendererTarget.TrackLines);

订阅和搜索

搜索和订阅流数据

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
await QueuedTask.Run(async () =>
{
//query filter can be null to search and retrieve all rows
//true means recycling cursor
using (var rc = streamLayer.SearchAndSubscribe(qfilter, true))
{
//waiting for new features to be streamed
//default is no cancellation
while (await rc.WaitForRowsAsync())
{
while (rc.MoveNext())
{
using (var row = rc.Current)
{
//determine the origin of the row event
switch (row.GetRowSource())
{
case RealtimeRowSource.PreExisting:
//pre-existing row at the time of subscribe
continue;
case RealtimeRowSource.EventInsert:
//row was inserted after subscribe
continue;
case RealtimeRowSource.EventDelete:
//row was deleted after subscribe
continue;
}
}
}
}
}//row cursor is disposed. row cursor is unsubscribed

//....or....
//Use the feature class instead of the layer
using (var rfc = streamLayer.GetFeatureClass())
{
//non-recycling cursor - 2nd param "false"
using (var rc = rfc.SearchAndSubscribe(qfilter, false))
{
//waiting for new features to be streamed
//default is no cancellation
while (await rc.WaitForRowsAsync())
{
//etc
}
}
}
});

搜索和订阅取消

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
await QueuedTask.Run(async () =>
{
//Recycling cursor - 2nd param "true"
//or streamLayer.Subscribe(qfilter, true) to just subscribe
using (var rc = streamLayer.SearchAndSubscribe(qfilter, true))
{
//auto-cancel after 20 seconds
var cancel = new CancellationTokenSource(new TimeSpan(0, 0, 20));
//catch TaskCanceledException
try
{
while (await rc.WaitForRowsAsync(cancel.Token))
{
//check for row events
while (rc.MoveNext())
{
using (var row = rc.Current)
{
//etc
}
}
}
}
catch (TaskCanceledException tce)
{
//Handle cancellation as needed
}
cancel.Dispose();
}
});

显式取消等待行异步

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
//somewhere in our code we create a CancellationTokenSource
var cancel = new CancellationTokenSource();
//...

//call cancel on the CancellationTokenSource anywhere in
//the add-in, assuming the CancellationTokenSource is in scope
if (SomeConditionForCancel)
cancel.Cancel();//<-- will cancel the token

//Within QueuedTask we are subscribed! streamLayer.Subscribe() or SearchAndSubscribe()
try
{
//TaskCanceledException will be thrown when the token is cancelled
while (await rc.WaitForRowsAsync(cancel.Token))
{
//check for row events
while (rc.MoveNext())
{
using (var row = rc.Current)
{
//etc
}
}
}
}
catch (TaskCanceledException tce)
{
//Handle cancellation as needed
}
cancel.Dispose();

实时要素类

从实时数据存储连接到实时要素类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
var url = "https://geoeventsample1.esri.com:6443/arcgis/rest/services/AirportTraffics/StreamServer";

await QueuedTask.Run(() =>
{
var realtimeServiceConProp = new RealtimeServiceConnectionProperties(
new Uri(url),
RealtimeDatastoreType.StreamService
);
using (var realtimeDatastore = new RealtimeDatastore(realtimeServiceConProp))
{
//A Realtime data store only contains **one** Realtime feature class (or table)
var name = realtimeDatastore.GetTableNames().First();
using (var realtimeFeatureClass = realtimeDatastore.OpenTable(name) as RealtimeFeatureClass)
{
//feature class, by default, is not streaming (opposite of the stream layer)
realtimeFeatureClass.StartStreaming();
//TODO use the feature class
//...
}
}

});

检查实时要素类是否可识别轨迹

1
2
3
4
5
6
7
8
using (var rfc = streamLayer.GetFeatureClass())
using (var rfc_def = rfc.GetDefinition())
{
if (rfc_def.HasTrackIDField())
{
//Track aware
}
}

从实时要素类获取追踪 ID 字段

1
2
3
4
5
6
7
8
9
10
//Must be on QueuedTask
using (var rfc = streamLayer.GetFeatureClass())
using (var rfc_def = rfc.GetDefinition())
{
if (rfc_def.HasTrackIDField())
{
var fld_name = rfc_def.GetTrackIDField();

}
}

订阅流数据

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
//Note: with feature class we can also use a System Task to subscribe and
//process rows
await QueuedTask.Run(async () =>
{
// or var rfc = realtimeDatastore.OpenTable(name) as RealtimeFeatureClass
using (var rfc = streamLayer.GetFeatureClass())
{
//non-recycling cursor - 2nd param "false"
//subscribe, pre-existing rows are not searched
using (var rc = rfc.Subscribe(qfilter, false))
{
SpatialQueryFilter spatialFilter = new SpatialQueryFilter();
//waiting for new features to be streamed
//default is no cancellation
while (await rc.WaitForRowsAsync())
{
while (rc.MoveNext())
{
using (var row = rc.Current)
{
switch (row.GetRowSource())
{
case RealtimeRowSource.EventInsert:
//getting geometry from new events as they arrive
Polygon poly = ((RealtimeFeature)row).GetShape() as Polygon;

//using the geometry to select features from another feature layer
spatialFilter.FilterGeometry = poly;//project poly if needed...
countyFeatureLayer.Select(spatialFilter);
continue;
default:
continue;
}
}
}
}
}//row cursor is disposed. row cursor is unsubscribed
}
});

搜索现有数据并订阅流数据

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
//Note we can use System Task with the Realtime feature class
//for subscribe
await System.Threading.Tasks.Task.Run(async () =>
// or use ... QueuedTask.Run()
{
using (var rfc = streamLayer.GetFeatureClass())
{
//non-recycling cursor - 2nd param "false"
using (var rc = rfc.SearchAndSubscribe(qfilter, false))
{
//waiting for new features to be streamed
//default is no cancellation
while (await rc.WaitForRowsAsync())
{
//pre-existing rows will be retrieved that were searched
while (rc.MoveNext())
{
using (var row = rc.Current)
{
var row_source = row.GetRowSource();
switch (row_source)
{
case RealtimeRowSource.EventDelete:
//TODO - handle deletes
break;
case RealtimeRowSource.EventInsert:
//TODO handle inserts
break;
case RealtimeRowSource.PreExisting:
//TODO handle pre-existing rows
break;
}
}
}
}
}//row cursor is disposed. row cursor is unsubscribed
}
});

搜索和订阅取消

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
await System.Threading.Tasks.Task.Run(async () =>
// or use ... QueuedTask.Run()
{
using (var rfc = streamLayer.GetFeatureClass())
{
//Recycling cursor - 2nd param "true"
using (var rc = rfc.SearchAndSubscribe(qfilter, true))
{
//auto-cancel after 20 seconds
var cancel = new CancellationTokenSource(new TimeSpan(0, 0, 20));
//catch TaskCanceledException
try
{
while (await rc.WaitForRowsAsync(cancel.Token))
{
//check for row events
while (rc.MoveNext())
{
using (var record = rc.Current)
{
//etc
}
}
}
}
catch(TaskCanceledException tce)
{
//Handle cancellation as needed
}
cancel.Dispose();
}
}
});

任务

检索项目中的所有任务项

1
2
3
4
5
IEnumerable<TaskProjectItem> taskItems = Project.Current.GetItems<TaskProjectItem>();
foreach (var item in taskItems)
{
// do something
}

打开任务文件 - .esriTasks 文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// Open a task file
try
{
// TODO - substitute your own .esriTasks file to be opened
string taskFile = @"c:\Tasks\Get Started.esriTasks";
//At 2.x -
//System.Guid guid = await TaskAssistantModule.OpenTaskAsync(taskFile);
var guid = await TaskAssistantFactory.Instance.OpenTaskFileAsync(taskFile);

// TODO - retain the guid returned for use with CloseTaskItemAsync
}
catch (OpenTaskException e)
{
// exception thrown if task file doesn't exist or has incorrect format
ArcGIS.Desktop.Framework.Dialogs.MessageBox.Show(e.Message);
}

打开项目任务项

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
// get the first project task item
var taskItem = Project.Current.GetItems<TaskProjectItem>().FirstOrDefault();
// if there isn't a project task item, return
if (taskItem == null)
return;

try
{
// Open it
//At 2.x -
//System.Guid guid = await TaskAssistantModule.OpenTaskItemAsync(taskItem.TaskItemGuid);
var guid = await TaskAssistantFactory.Instance.OpenTaskItemAsync(taskItem.TaskItemGuid);

// TODO - retain the guid returned for use with CloseTaskItemAsync
}
catch (OpenTaskException e)
{
ArcGIS.Desktop.Framework.Dialogs.MessageBox.Show(e.Message);
}

关闭任务项

1
2
3
4
5
6
7
8
9
10
11
12
13
14
// find the first project task item which is open
var taskItem = Project.Current.GetItems<TaskProjectItem>().FirstOrDefault(t => t.IsOpen == true);
// if there isn't a project task item, return
if (taskItem == null)
return;

if (taskItem.IsOpen)
{
// close it
// NOTE : The task item will also be removed from the project
//At 2.x -
//TaskAssistantModule.CloseTaskAsync(taskItem.TaskItemGuid);
TaskAssistantFactory.Instance.CloseTaskItemAsync(taskItem.TaskItemGuid);
}

导出任务项

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
// get the first project task item
var taskItem = Project.Current.GetItems<TaskProjectItem>().FirstOrDefault();
// if there isn't a project task item, return
if (taskItem == null)
return;

try
{
// export the task item to the c:\Temp folder
string exportFolder = @"c:\temp";
//At 2.x -
//string fileName = await TaskAssistantModule.ExportTaskAsync(taskItem.TaskItemGuid, exportFolder);
string fileName = await TaskAssistantFactory.Instance.ExportTaskItemAsync(taskItem.TaskItemGuid, exportFolder);
ArcGIS.Desktop.Framework.Dialogs.MessageBox.Show("Task saved to " + fileName);
}
catch (ExportTaskException e)
{
ArcGIS.Desktop.Framework.Dialogs.MessageBox.Show("Error saving task " + e.Message);
}

获取任务信息 - 从任务项目项

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
var taskItem = Project.Current.GetItems<TaskProjectItem>().FirstOrDefault();
// if there isn't a project task item, return
if (taskItem == null)
return;

string message = await QueuedTask.Run(async () =>
{
bool isOpen = taskItem.IsOpen;
Guid taskGuid = taskItem.TaskItemGuid;

string msg = "";
try
{
TaskItemInfo taskItemInfo = await taskItem.GetTaskItemInfoAsync();

msg = "Name : " + taskItemInfo.Name;
msg += "\r\n" + "Description : " + taskItemInfo.Description;
msg += "\r\n" + "Guid : " + taskItemInfo.Guid.ToString("B");
msg += "\r\n" + "Task Count : " + taskItemInfo.GetTasks().Count();

// iterate the tasks in the task item
IEnumerable<TaskInfo> taskInfos = taskItemInfo.GetTasks();
foreach (TaskInfo taskInfo in taskInfos)
{
string name = taskInfo.Name;
Guid guid = taskInfo.Guid;

// do something
}
}
catch (OpenTaskException e)
{
// exception thrown if task file doesn't exist or has incorrect format
msg = e.Message;
}
catch (TaskFileVersionException e)
{
// exception thrown if task file does not support returning task information
msg = e.Message;
}
return msg;
});

ArcGIS.Desktop.Framework.Dialogs.MessageBox.Show(message, "Task Information");

获取任务信息 - 从 .esriTasks 文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
// TODO - substitute your own .esriTasks file
string taskFile = @"c:\Tasks\Get Started.esriTasks";

string message = await QueuedTask.Run(async () =>
{
string msg = "";
try
{
// retrieve the task item information
//At 2.x -
//TaskItemInfo taskItemInfo = await TaskAssistantModule.GetTaskItemInfoAsync(taskFile);
TaskItemInfo taskItemInfo = await TaskAssistantFactory.Instance.GetTaskItemInfoAsync(taskFile);

msg = "Name : " + taskItemInfo.Name;
msg += "\r\n" + "Description : " + taskItemInfo.Description;
msg += "\r\n" + "Guid : " + taskItemInfo.Guid.ToString("B");
msg += "\r\n" + "Task Count : " + taskItemInfo.GetTasks().Count();

}
catch (OpenTaskException e)
{
// exception thrown if task file doesn't exist or has incorrect format
msg = e.Message;
}
catch (TaskFileVersionException e)
{
// exception thrown if task file does not support returning task information
msg = e.Message;
}
return msg;
});

ArcGIS.Desktop.Framework.Dialogs.MessageBox.Show(message, "Task Information");

在任务文件中打开特定任务 - .esriTasks 文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
// TODO - substitute your own .esriTasks file to be opened
string taskFile = @"c:\Tasks\Get Started.esriTasks";

await QueuedTask.Run(async () =>
{
try
{
// retrieve the task item information
//At 2.x -
//TaskItemInfo taskItemInfo = await TaskAssistantModule.GetTaskItemInfoAsync(taskFile);
var taskItemInfo = await TaskAssistantFactory.Instance.GetTaskItemInfoAsync(taskFile);

// find the first task
TaskInfo taskInfo = taskItemInfo.GetTasks().FirstOrDefault();

Guid guid = Guid.Empty;
if (taskInfo != null)
{
// if a task exists, open it
//At 2.x -
//guid = await TaskAssistantModule.OpenTaskAsync(taskFile, taskInfo.Guid);
guid = await TaskAssistantFactory.Instance.OpenTaskFileAsync(taskFile, taskInfo.Guid);
}
else
{
// else just open the task item
//At 2.x -
//guid = await TaskAssistantModule.OpenTaskAsync(taskFile);
guid = await TaskAssistantFactory.Instance.OpenTaskFileAsync(taskFile);
}

// TODO - retain the guid returned for use with CloseTaskItemAsync
}
catch (OpenTaskException e)
{
// exception thrown if task file doesn't exist or has incorrect format
ArcGIS.Desktop.Framework.Dialogs.MessageBox.Show(e.Message);
}
catch (TaskFileVersionException e)
{
// exception thrown if task file does not support returning task information
ArcGIS.Desktop.Framework.Dialogs.MessageBox.Show(e.Message);
}

});

订阅任务事件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
public void TaskEvents()
{
TaskStartedEvent.Subscribe(OnTaskStarted);
TaskEndedEvent.Subscribe(OnTaskCompletedOrCancelled);
}

private void OnTaskStarted(TaskStartedEventArgs args)
{
string userName = args.UserID; // ArcGIS Online signed in userName. If not signed in to ArcGIS Online then returns the name of the user logged in to the Windows OS.
string projectName = args.ProjectName;

Guid taskItemGuid = args.TaskItemGuid;
string taskItemName = args.TaskItemName;
string taskItemVersion = args.TaskItemVersion;

Guid taskGuid = args.TaskGuid;
string taskName = args.TaskName;

DateTime startTime = args.StartTime;
}

private void OnTaskCompletedOrCancelled(TaskEndedEventArgs args)
{
string userName = args.UserID; // ArcGIS Online signed in userName. If not signed in to ArcGIS Online then returns the name of the user logged in to the Windows OS.
string projectName = args.ProjectName;

Guid taskItemGuid = args.TaskItemGuid;
string taskItemName = args.TaskItemName;
string taskItemVersion = args.TaskItemVersion;

Guid taskGuid = args.TaskGuid;
string taskName = args.TaskName;

DateTime startTime = args.StartTime;
DateTime endTime = args.EndTime;
double duration = args.Duration;

bool completed = args.Completed; // completed or cancelled
}

工作流管理器

如何获取管理器对象

1
2
3
4
5
// WorkflowModule.GetManager returns a manager of the type specified
// keyword is currently just an empty string
var wfCon = await WorkflowModule.ConnectAsync();
var jobManager = wfCon.GetManager<JobsManager>();
var configManager = wfCon.GetManager<ConfigurationManager>();

如何获取群组

1
2
3
4
// GetAllGroups returns a list of Workflow Manager groups
var wfCon = await WorkflowModule.ConnectAsync();
var configManager = wfCon.GetManager<ConfigurationManager>();
var allGroups = configManager.GetAllGroups();

如何获取用户

1
2
3
4
// GetAllUsers returns a list of Workflow Manager users
var wfCon = await WorkflowModule.ConnectAsync();
var configManager = wfCon.GetManager<ConfigurationManager>();
var allUsers = configManager.GetAllUsers();

如何获取作业类型

1
2
3
4
// GetVisibleJobTypes returns a list of job types
var wfCon = await WorkflowModule.ConnectAsync();
var configManager = wfCon.GetManager<ConfigurationManager>();
var jobTypes = configManager.GetVisibleJobTypes();

如何创建作业

1
2
3
4
5
// CreateJob returns an ID of a new job
// it is a passed a valid job type ID as an integer
var wfCon = await WorkflowModule.ConnectAsync();
var jobManager = wfCon.GetManager<JobsManager>();
var jobID = jobManager.CreateNewJob(jobTypeID);

如何找到工作

1
2
3
4
5
// GetJob returns an existing job
// it is passed a valid job ID as an integer
var wfCon = await WorkflowModule.ConnectAsync();
var jobManager = wfCon.GetManager<JobsManager>();
var job = jobManager.GetJob(jobID);

如何获取与地图关联的作业

1
2
3
4
5
6
7
8
9
// Get a job associated with the map
var wfCon = await WorkflowModule.ConnectAsync();
var jobManager = wfCon.GetManager<JobsManager>();
var job = jobManager.GetJob(map);
if (job != null)
{
// Job found, do something with the job
var jobId = job.ID;
}

如何关闭作业

1
2
3
4
5
// CloseJobs returns a list of closed job IDs
// it is passed a list of job IDs to close
var wfCon = await WorkflowModule.ConnectAsync();
var jobManager = wfCon.GetManager<JobsManager>();
var jobIDs = jobManager.CloseJobs(jobIdsToClose);

如何访问和更改工作信息

1
2
3
4
5
6
// You can change many of the exposed properties of a job and then save them
var wfCon = await WorkflowModule.ConnectAsync();
var jobManager = wfCon.GetManager<JobsManager>();
var job = jobManager.GetJob(jobID);
job.Description = "This is a test";
job.Save();

如何在作业上执行步骤

1
2
3
4
5
6
7
8
9
// Gets the current step
// checks to see if it can execute it
// proceeds to do so if it can
var wfCon = await WorkflowModule.ConnectAsync();
var jobManager = wfCon.GetManager<JobsManager>();
var job = jobManager.GetJob(jobID);
string stepID = job.GetCurrentSteps().First();
if (job.CanExecuteStep(stepID).Item1)
job.ExecuteStep(stepID);

如何执行查询

1
2
3
4
5
// ExecuteQuery returns a query result
// Its passed either an ID or a name
var wfCon = await WorkflowModule.ConnectAsync();
var jobManager = wfCon.GetManager<JobsManager>();
var queryResultReturn = jobManager.ExecuteQuery("All Jobs");

);