このシリーズでは「ArcGIS Pro SDK for .NET を使用した機能開発」のシリーズ記事として、ArcGIS Proを拡張するためのアドイン開発時によく使う便利なクラスやメソッド、また、それらを用いた実践的な開発をご紹介します。本シリーズで実装するソースはすべて Github に格納してありますので、ぜひArcGIS Pro SDK for .NET(以下 Pro SDK)を使用する開発の参考にしてください。
第1弾と第2弾の記事では、マップとの対話的な操作によって選択したフィーチャの属性表示、フィーチャの強調表示、フィーチャへのズーム機能等の実装方法をご紹介しました。第3弾となる今回は、レイヤーのレンダラーを設定する方法をご紹介します。
・Pro SDK を使用してArcGIS Pro のアドイン開発を行っている方
・Pro SDK を使用したArcGIS Pro のアドイン開発をこれから行う、もしくは、検討している方
※「ArcGIS Pro SDK for .NET を使った独力での開発」でご紹介した Pro SDK のハンズオンで予習しておくと、本シリーズをよりスムーズに理解できると思います。
レンダラーを使用すると、特定のルールに基づいてレイヤーの表示方法を定義することができます。例えば、レイヤーが持つ文字や数値の属性情報をもとにしてフィーチャを色分け表示したり、またはシンボル サイズを変えたりして、その属性値を地図上に可視化することができます。
本記事ではレイヤーが持つ属性フィールドの一覧を表示し、選択したフィールドとレンダリング手法でレイヤーのレンダラーを設定する機能を実装します。
※本記事ではドッキング ウインドウの「レンダリング」タブの機能を実装します。「アノテーション操作」、「ジオメトリ変換」タブの機能は今後の連載でご紹介します。
本記事で使用する主な API カテゴリ
本記事では「プロジェクト アイテム」、「レイヤー」を中心に使用します。
※API カテゴリに関しては「ArcGIS Pro SDK for .NET を使った独力での開発」をご参照ください。
本記事で使用するソースは Github に格納しています。ソースに関して実装のポイントとなる部分を抜粋して解説しますので、ダウンロードをお願いします。
レイヤー コンボ ボックスの選択肢がアクティブなマップ ビューに含まれているレイヤーを動的に表示するように実装します。この処理は、第1回目のマップとの対話的な操作の記事で紹介した方法と同じであるため、本記事では割愛します。実装方法は、「ArcGIS Pro SDK for .NET を使用した機能開発~マップとの対話的な操作その1~」及び GitHub のソースコードを参考にしてください。
選択したレイヤーの属性フィールド名の一覧を取得してコンボ ボックスに表示します。
「レンダリング」タブ アイテムの「renderingField_comboBox」コンボ ボックスに移動し、コンボ ボックスの「Itemsource」と「SelectedItem」属性を「MainDockPaneViewModel.cs」の「Fields」と「SelectedField」プロパティにバインドさせます。
<ComboBox Grid.Column="1" ItemsSource="{Binding Fields}" SelectedItem="{Binding SelectedField}"/>
「MainDockPaneViewModel.cs」に「Fields」と「SelectedField」プロパティ(「2.1」でバインドさせたプロパティ)を作成します。各々の役割は以下の通りです。
private List<String> _fields = new List<String>(); public List<String> Fields { get { return _fields; } set { SetProperty(ref _fields, value, () => Fields); } } private string _selectedField; public string SelectedField { get { return _selectedField; } set { SetProperty(ref _selectedField, value, () => SelectedField); } }
「2.2」で作成した「Fields」プロパティに、選択したレイヤーに存在するフィールドのフィールド名を格納します。属性値に応じて色分けを行うため、レンダラーの設定に使用できる文字列型か数値型のフィールドを抽出して格納します。
private void GetFields() { // アクティブ(選択状態)なマップを取得する var mapView = MapView.Active; if (mapView == null || _selectedRenderingLayer == null) return; // レイヤーの属性テーブルにアクセスして、フィールド名を Fields 配列に格納する QueuedTask.Run(() => { // レイヤー名で検索してマップ上のレイヤーを取得する var featureLayer = MapView.Active.Map.FindLayers(_selectedRenderingLayer.Name).FirstOrDefault() as FeatureLayer; var flf = featureLayer.GetTable().GetDefinition().GetFields(); // 文字列型または数値型のフィールドのフィールド名を抽出する Fields = flf.Where(f => f.FieldType == FieldType.Integer | f.FieldType == FieldType.SmallInteger | f.FieldType == FieldType.String | f.FieldType == FieldType.Double).Select(f => f.Name).ToList(); }); }
レンダリングに使用する手法のリストをコンボ ボックスに表示します。レンダリング手法に関しては「4.レンダラーを設定」の手順で説明します。
「レンダリング」タブ アイテムの「renderingMethod_comboBox」コンボ ボックスに移動し、コンボ ボックスの「Itemsource」と「SelectedItem」属性を「MainDockPaneViewModel.cs」の「RenderingMethod」と「SelectedRendering」プロパティにバインドさせます。
<ComboBox Grid.Column="1" ItemsSource="{Binding RenderingMethods}" SelectedItem="{Binding SelectedRenderingMethod}"/>
「MainDockPaneViewModel.cs」に「RenderingMethods」と「SelectedRenderingMethod」プロパティ(「3.1」でバインドさせたプロパティ)を作成します。各々の役割は以下の通りです。
private ObservableCollection<string> _renderingMethods = new ObservableCollection<string> { "個別値レンダリング", "等級色レンダリング" }; public ObservableCollection<string> RenderingMethods { get { return _renderingMethods; } set { SetProperty(ref _renderingMethods, value, () => RenderingMethods); } } private string _selectedRenderingMethod; public string SelectedRenderingMethod { get { return _selectedRenderingMethod; } set { SetProperty(ref _selectedRenderingMethod, value, () => SelectedRenderingMethod); } }
「実行」ボタンを押した際に、選択したフィールドとレンダリング手法でレンダラーを作成しレイヤーに設定します。
「実行」ボタンの「Command」属性を「MainDockPaneViewModel.cs」の「SelectionTool」プロパティにバインドさせます。
<Button Grid.Column="0" Content="実行" Command="{Binding Path= ExecuteRendering}" Style="{DynamicResource Esri_Button}"></Button>
「実行」ボタンを押すと「ExecuteRenderingClick()」メソッドが実行されるように実装します。
protected MainDockPaneViewModel() { // 実行ボタンを押すと ExecuteRenderingClick() が実行される _executeRendering = new RelayCommand(() => ExecuteRenderingClick(), () => true); } private ICommand _executeRendering; public ICommand ExecuteRendering => _executeRendering; private void ExecuteRenderingClick() { }
ExecuteRenderingClick() メソッドに以下の構文を追加します。コンボ ボックスでレイヤー、フィールド、レンダリング手法が選択されているかをチェックします。
// コンボ ボックスでレイヤー、フィールド、レンダリング手法が選択されているかをチェックする if (_selectedRenderingLayer is null) { MessageBox.Show("レイヤーを選択してください。"); } else if (_selectedField is null) { MessageBox.Show("フィールドを選択してください。"); } else if (_selectedRenderingMethod is null) { MessageBox.Show("レンダリング手法を選択してください。"); } else { try { // レンダラー作成の処理を実装 } catch (Exception) { MessageBox.Show("レンダリングに失敗しました。"); } }
try ブロックの中にレンダラー作成の処理を実装します。
まず、MapView.Active.Map.FindLayers() メソッドを使用してコンボ ボックスで選択したレイヤー(FeatureLayer オブジェクト)を取得します。
// レイヤー名で検索してマップ上のレイヤーを取得する var lyr = MapView.Active.Map.FindLayers(_selectedRenderingLayer.Name).FirstOrDefault() as FeatureLayer;
カラーランプ(配色)を取得するには、最初に StyleProjectItem(スタイル プロジェクト アイテム)を取得して、取得した StyleProjectItem の SearchColorRamps メソッドを使用して指定した名前のカラーランプ アイテムを取得します。
今回は、ArcGIS Pro に標準で含まれている「ArcGIS カラー」スタイル プロジェクト アイテムの「フル スペクトル (明るい)」カラーランプを使用します。(ArcGIS Pro の表示言語が英語の場合は、「ArcGIS Colors」及び「Spectrum - Full Light」を指定します)。
// 「ArcGIS カラー」(ArcGIS Pro の表示言語が英語の場合は、「ArcGIS Colors」を指定)プロジェクト スタイル アイテムを取得 StyleProjectItem style = Project.Current.GetItems<StyleProjectItem>().FirstOrDefault(s => s.Name == "ArcGIS カラー"); // 名前で検索してカラーランプ アイテムを取得する(ArcGIS Pro の表示言語が英語の場合は、「Spectrum - Full Light」を指定) IList<ColorRampStyleItem> colorRampList = style.SearchColorRamps("フル スペクトル (明るい)");
選択したレンダリング手法(_selectedRenderingMethod)により、レンダラーを作成します。レンダリング手法で個別値レンダリングを選択している場合は、個別値レンダラーを作成します。個別値レンダラーは同じ属性値を持つフィーチャを同一シンボルで表示する手法です。
まず、UniqueValueRendererDefinition コンストラクタを使用して個別値レンダラーの定義を作成します。引数にはフィールド コンボ ボックスで指定した属性フィールド名と「4.4.2」で取得したカラーランプを指定します。
続いて、引数に個別値レンダラーの定義を指定して、「4.4.1」で取得したレイヤー(FeatureLayer オブジェクト)の CreateRenderer メソッドを実行することで個別値レンダラー(CIMUniqueValueRenderer)を作成できます。
最後に、レイヤーの SetRenderer メソッドを実行して、レイヤーにレンダラーを設定します。引数には作成した個別値レンダラーを指定します。
if (_selectedRenderingMethod == "個別値レンダリング") { // 個別値レンダラーの定義を作成する UniqueValueRendererDefinition uvrDef = new UniqueValueRendererDefinition() { ValueFields = new String[] { _selectedField }, // 分類に使用するフィールド ColorRamp = colorRampList[0].ColorRamp, // カラーランプ }; // 個別値レンダラーを作成する CIMUniqueValueRenderer cimRenderer = (CIMUniqueValueRenderer)lyr.CreateRenderer(uvrDef); // レンダラーをレイヤーに設定する lyr.SetRenderer(cimRenderer); }
レンダリング手法で等級色レンダリングを選択している場合は、等級色レンダラーを作成します。等級色レンダラーは属性値(数値)の範囲でフィーチャを分類し、範囲ごとに異なるシンボルで表示する手法です。
まず、GraduatedColorsRendererDefinition コンストラクタを使用して等級色レンダラーの定義を作成します。引数にはフィールド コンボ ボックスで指定した属性フィールド名、「4.4.2」で取得したカラーランプ、分類方法(今回は「自然分類」を使用)、分類数を指定します。
続いて、引数に等級色レンダラーの定義を指定して、「4.4.1」で取得したレイヤー(FeatureLayer オブジェクト)の CreateRenderer メソッドを実行することで等級色レンダラー(CIMClassBreaksRenderer)を作成できます。
最後に、レイヤーの SetRenderer メソッドを実行して、レイヤーにレンダラーを設定します。引数には作成した等級色レンダラーを指定します。
else // 等級色レンダリングの場合 { if (GetNumericField(lyr, _selectedField)) // 数値型のフィールドを選択している場合のみ実行する { // 等級色レンダラーの定義を作成する GraduatedColorsRendererDefinition gcDef = new GraduatedColorsRendererDefinition() { ClassificationField = _selectedField, // 分類に使用するフィールド ColorRamp = colorRampList[0].ColorRamp, // カラーランプ ClassificationMethod = ClassificationMethod.NaturalBreaks, // 分類方法(自然分類) BreakCount = 5, // 分類数(5段階で分類) }; // 等級色(クラス分類)レンダラーを作成する CIMClassBreaksRenderer cimClassBreakRenderer = (CIMClassBreaksRenderer)lyr.CreateRenderer(gcDef); // レンダラーをレイヤーに設定する lyr.SetRenderer(cimClassBreakRenderer); } }
※ 等級色レンダリングは数値型フィールドのみ使用できるので GetNumericField 関数を作成して属性フィールドの型を判別しています(実装方法は GitHub のコードをご参照ください)。
これで選択したフィールドに応じてレイヤーにレンダラーを設定する処理は完了です。
本記事ではレイヤーが持つ属性フィールドの一覧を表示し、選択したフィールドとレンダリング手法でレイヤーのレンダラーを設定する方法についてご紹介しました。今回は個別値と等級色のレンダラーを使用しましたが、それ以外にもストレッチ、比例シンボル、ドット密度、ヒートマップ等の様々なレンダラーが用意されていますので、ぜひご活用ください。
次回はアノテーションの操作についてご紹介する予定です。