• DayDreamInGIS 逆地理编码工具(根据经纬度获取位置描述)插件源码解析


    本工具调用高德地图逆地理编码api,根据高的地图逆地理编码api,实现根据经纬度获取位置描述。

    总体设计逻辑,窗体采用WPF,通过属性的方式传递交互对象,核心处理逻辑写到button的执行逻辑中。

    1.页面

    页面XAML:

    1. <Window x:Class="DayDreamInGISTool.GeoCoding.InverseGCWPF"
    2. xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    3. xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    4. xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    5. xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    6. mc:Ignorable="d" Title="逆地理编码" ResizeMode="NoResize" WindowStartupLocation="CenterScreen"
    7. Width="500" Height="480">
    8. <Grid Margin="5">
    9. <Grid.RowDefinitions>
    10. <RowDefinition Height="40">RowDefinition>
    11. <RowDefinition Height="40">RowDefinition>
    12. <RowDefinition Height="40">RowDefinition>
    13. <RowDefinition Height="40">RowDefinition>
    14. <RowDefinition Height="40">RowDefinition>
    15. <RowDefinition>RowDefinition>
    16. <RowDefinition>RowDefinition>
    17. <RowDefinition Height="40">RowDefinition>
    18. Grid.RowDefinitions>
    19. <Grid>
    20. <Grid.ColumnDefinitions>
    21. <ColumnDefinition Width="100">ColumnDefinition>
    22. <ColumnDefinition>ColumnDefinition>
    23. Grid.ColumnDefinitions>
    24. <Label Content="高德地图Token" VerticalAlignment="Center">Label>
    25. <TextBox Grid.Column="1" VerticalAlignment="Center" Name="txtGDToken" Height="22" Text="b1670be70e419c2a112957742e55a756">TextBox>
    26. Grid>
    27. <Grid Grid.Row="1">
    28. <Grid.ColumnDefinitions>
    29. <ColumnDefinition Width="100">ColumnDefinition>
    30. <ColumnDefinition>ColumnDefinition>
    31. Grid.ColumnDefinitions>
    32. <Label Content="图层" VerticalAlignment="Center" HorizontalAlignment="Right">Label>
    33. <ComboBox Grid.Column="1" Name="cmbLayer" VerticalAlignment="Center" Height="23" SelectionChanged="cmbLayer_SelectionChanged">ComboBox>
    34. Grid>
    35. <Grid Grid.Row="2">
    36. <Grid.ColumnDefinitions>
    37. <ColumnDefinition Width="100">ColumnDefinition>
    38. <ColumnDefinition>ColumnDefinition>
    39. Grid.ColumnDefinitions>
    40. <Label Content="经度" VerticalAlignment="Center" HorizontalAlignment="Right">Label>
    41. <ComboBox Grid.Column="1" Name="cmbLongtitude" VerticalAlignment="Center" Height="23">ComboBox>
    42. Grid>
    43. <Grid Grid.Row="3">
    44. <Grid.ColumnDefinitions>
    45. <ColumnDefinition Width="100">ColumnDefinition>
    46. <ColumnDefinition>ColumnDefinition>
    47. Grid.ColumnDefinitions>
    48. <Label Content="纬度" VerticalAlignment="Center" HorizontalAlignment="Right">Label>
    49. <ComboBox Grid.Column="1" VerticalAlignment="Center" Name="cmbLatitude" Height="23">ComboBox>
    50. Grid>
    51. <Grid Grid.Row="4">
    52. <Grid.ColumnDefinitions>
    53. <ColumnDefinition Width="100">ColumnDefinition>
    54. <ColumnDefinition>ColumnDefinition>
    55. Grid.ColumnDefinitions>
    56. <Label Content="位置" VerticalAlignment="Center" HorizontalAlignment="Right">Label>
    57. <ComboBox Grid.Column="1" VerticalAlignment="Center" Name="cmbLocation" Height="23">ComboBox>
    58. Grid>
    59. <Grid Grid.Row="5">
    60. <GroupBox Header="地址结构">
    61. <Grid Margin="45 5">
    62. <Grid.RowDefinitions>
    63. <RowDefinition>RowDefinition>
    64. <RowDefinition>RowDefinition>
    65. Grid.RowDefinitions>
    66. <Grid>
    67. <Grid.ColumnDefinitions>
    68. <ColumnDefinition>ColumnDefinition>
    69. <ColumnDefinition>ColumnDefinition>
    70. <ColumnDefinition>ColumnDefinition>
    71. <ColumnDefinition>ColumnDefinition>
    72. Grid.ColumnDefinitions>
    73. <CheckBox Grid.Column="0" Name="chkPro" IsChecked="False" VerticalAlignment="Center" Checked="chkPro_Checked">CheckBox>
    74. <CheckBox Grid.Column="1" Name="chkCity" IsChecked="False" VerticalAlignment="Center" Checked="chkCity_Checked">CheckBox>
    75. <CheckBox Grid.Column="2" Name="chkCounty" IsChecked="False" VerticalAlignment="Center" Checked="chkCounty_Checked">县/区CheckBox>
    76. <CheckBox Grid.Column="3" Name="chkTown" IsChecked="False" VerticalAlignment="Center" Checked="chkTown_Checked">街道/乡镇CheckBox>
    77. Grid>
    78. <Grid Grid.Row="1">
    79. <Label>示例Label>
    80. <TextBox Name="txtExample" VerticalAlignment="Center" HorizontalAlignment="Right" IsReadOnly="True">
    81. 北京市朝阳区望京街道方恒国际中心B座方恒国际
    82. TextBox>
    83. Grid>
    84. Grid>
    85. GroupBox>
    86. Grid>
    87. <Grid Grid.Row="6">
    88. <GroupBox Header="说明">
    89. <Grid Margin="8">
    90. <TextBlock TextWrapping="Wrap" LineHeight="20">
    91. <Run>本插件使用高德地图逆地理编码服务获取位置描述,经纬度需为wgs84或者cgcs2000的经纬度,如果token不能使用,请去高德图管网申请tokenRun>
    92. <LineBreak>LineBreak>
    93. <Hyperlink Click="Hyperlink_Click" NavigateUri="https://console.amap.com/dev/key/app"> https://console.amap.com/dev/key/appHyperlink>
    94. TextBlock>
    95. Grid>
    96. GroupBox>
    97. Grid>
    98. <Grid Grid.Row="7">
    99. <Grid.ColumnDefinitions>
    100. <ColumnDefinition>ColumnDefinition>
    101. <ColumnDefinition>ColumnDefinition>
    102. Grid.ColumnDefinitions>
    103. <Button Content="确定" Name="btnOK" Width="80" Height="30" VerticalAlignment="Center" HorizontalAlignment="Center" Click="btnOK_Click">Button>
    104. <Button Content="取消" Name="btnCancel" Width="80" Height="30" Grid.Column="1" VerticalAlignment="Center" HorizontalAlignment="Center" Click="btnCancel_Click">Button>
    105. Grid>
    106. Grid>
    107. Window>

    页面逻辑代码:

    1. using System;
    2. using System.Collections.Generic;
    3. using System.Linq;
    4. using System.Text;
    5. using System.Threading.Tasks;
    6. using System.Windows;
    7. using System.Windows.Controls;
    8. using System.Windows.Data;
    9. using System.Windows.Documents;
    10. using System.Windows.Input;
    11. using System.Windows.Media;
    12. using System.Windows.Media.Imaging;
    13. using System.Windows.Navigation;
    14. using System.Windows.Shapes;
    15. using ESRI.ArcGIS.Carto;
    16. using ESRI.ArcGIS.Geometry;
    17. using ESRI.ArcGIS.Geodatabase;
    18. using System.CodeDom;
    19. using System.Diagnostics;
    20. namespace DayDreamInGISTool.GeoCoding
    21. {
    22. ///
    23. /// InverseGCWPF.xaml 的交互逻辑
    24. ///
    25. public partial class InverseGCWPF : Window
    26. {
    27. private IFeatureLayer pftlyr = null;
    28. public IFeatureLayer Pftlyr
    29. {
    30. get { return pftlyr; }
    31. set { pftlyr = value; }
    32. }
    33. private string xfdnm;
    34. public string Xfdnm
    35. {
    36. get { return xfdnm; }
    37. set { xfdnm = value; }
    38. }
    39. private string yfdnm;
    40. public string Yfdnm
    41. {
    42. get { return yfdnm; }
    43. set { yfdnm = value; }
    44. }
    45. private string locationfdnm;
    46. public string Locationfdnm
    47. {
    48. get { return locationfdnm; }
    49. set { locationfdnm = value; }
    50. }
    51. private string gdtoken;
    52. public string Gdtoken
    53. {
    54. get { return gdtoken; }
    55. set { gdtoken = value; }
    56. }
    57. private IMap pMap = null;
    58. string toolname = "DDGInverGeocoding";
    59. string keyname = "gdtoken";
    60. string tokenInReg = "";
    61. public InverseGCWPF()
    62. {
    63. InitializeComponent();
    64. pMap = ArcMap.Document.FocusMap;
    65. GISCommonHelper.CartoLyrHelper.setFeatureLyrCombox(ref cmbLayer, pMap, esriGeometryType.esriGeometryAny);
    66. try
    67. {
    68. object tt = GISCommonHelper.esriSystemHelper.getValueFromReg2(toolname, keyname);
    69. if (tt == null)
    70. {
    71. }
    72. else
    73. {
    74. tokenInReg = tt.ToString();
    75. this.txtGDToken.Text = tt.ToString();
    76. }
    77. }
    78. catch (Exception)
    79. {
    80. throw;
    81. }
    82. setExample();
    83. }
    84. private bool isPro;
    85. public bool IsPro
    86. {
    87. get { return isPro; }
    88. set { isPro = value; }
    89. }
    90. private bool isCity;
    91. public bool IsCity
    92. {
    93. get { return isCity; }
    94. set { isCity = value; }
    95. }
    96. private bool isCounty;
    97. public bool IsCounty
    98. {
    99. get { return isCounty; }
    100. set { isCounty = value; }
    101. }
    102. private bool isTown;
    103. public bool IsTown
    104. {
    105. get { return isTown; }
    106. set { isTown = value; }
    107. }
    108. private void cmbLayer_SelectionChanged(object sender, SelectionChangedEventArgs e)
    109. {
    110. if (cmbLayer.SelectedIndex != -1)
    111. {
    112. pftlyr = cmbLayer.SelectedValue as IFeatureLayer;
    113. GISCommonHelper.CartoFieldHelper.setFieldCombox(ref cmbLongtitude, pftlyr.FeatureClass.Fields, false,
    114. esriFieldType.esriFieldTypeDouble, esriFieldType.esriFieldTypeSingle);
    115. GISCommonHelper.CartoFieldHelper.setFieldCombox(ref cmbLatitude, pftlyr.FeatureClass.Fields, false,
    116. esriFieldType.esriFieldTypeDouble, esriFieldType.esriFieldTypeSingle);
    117. GISCommonHelper.CartoFieldHelper.setFieldCombox(ref cmbLocation, pftlyr.FeatureClass.Fields,false,esriFieldType.esriFieldTypeString);
    118. GISCommonHelper.CartoFieldHelper.setDftField(ref cmbLongtitude, p =>
    119. {
    120. if (p.alias_name.Contains("经度") || p.name.Contains("经度") || p.alias_name.Contains("Lng")
    121. || p.name.Contains("Lng") || p.alias_name.Contains("Longtitude") || p.name.Contains("Longtitude")
    122. || p.name.ToLower()=="x" || p.alias_name.ToLower()=="x")
    123. {
    124. return true;
    125. }
    126. return false;
    127. });
    128. GISCommonHelper.CartoFieldHelper.setDftField(ref cmbLatitude, p =>
    129. {
    130. if (p.alias_name.Contains("纬度") || p.name.Contains("纬度") || p.alias_name.Contains("Lat")
    131. || p.name.Contains("Lat") || p.alias_name.Contains("Latitude") || p.name.Contains("Latitude")
    132. || p.name.ToLower()=="y" || p.alias_name.ToLower()=="y")
    133. {
    134. return true;
    135. }
    136. return false;
    137. });
    138. GISCommonHelper.CartoFieldHelper.setDftField(ref cmbLocation, p =>
    139. {
    140. if (p.alias_name.Contains("位置") || p.name=="位置" || p.name.ToLower().Contains("location"))
    141. {
    142. return true;
    143. }
    144. else
    145. {
    146. return false;
    147. }
    148. });
    149. }
    150. }
    151. private void btnCancel_Click(object sender, RoutedEventArgs e)
    152. {
    153. this.DialogResult = false;
    154. }
    155. // 北京市朝阳区望京街道方恒国际中心B座方恒国际
    156. string pro = "浙江省";
    157. string city = "杭州市";
    158. string county = "上城区";
    159. string town = "四季青街道";
    160. string building = "钱江新城";
    161. private void btnOK_Click(object sender, RoutedEventArgs e)
    162. {
    163. if (pftlyr == null)
    164. {
    165. MessageBox.Show("请选择图层");
    166. return;
    167. }
    168. if (cmbLatitude.SelectedIndex == -1)
    169. {
    170. MessageBox.Show("请配置纬度字段");
    171. return;
    172. }
    173. else
    174. {
    175. yfdnm = cmbLatitude.SelectedValue.ToString();
    176. }
    177. if (cmbLongtitude.SelectedIndex == -1)
    178. {
    179. MessageBox.Show("请配置经度字段");
    180. return;
    181. }
    182. else
    183. {
    184. xfdnm = cmbLongtitude.SelectedValue.ToString();
    185. }
    186. if (cmbLocation.SelectedIndex == -1)
    187. {
    188. MessageBox.Show("请配置位置字段");
    189. return;
    190. }
    191. else
    192. {
    193. locationfdnm = cmbLocation.SelectedValue.ToString();
    194. }
    195. if (string.IsNullOrEmpty(txtGDToken.Text))
    196. {
    197. MessageBox.Show("高德地图token不能为空");
    198. }
    199. else
    200. {
    201. gdtoken = txtGDToken.Text;
    202. if(gdtoken== tokenInReg)
    203. {
    204. }
    205. else
    206. {
    207. //写入注册表
    208. GISCommonHelper.esriSystemHelper.setValueToReg2(toolname, new KeyValuePair<string, object>(keyname, gdtoken));
    209. }
    210. }
    211. this.DialogResult = true;
    212. }
    213. private void Hyperlink_Click(object sender, RoutedEventArgs e)
    214. {
    215. System.Windows.Documents.Hyperlink link = sender as System.Windows.Documents.Hyperlink;
    216. Process.Start(new ProcessStartInfo(link.NavigateUri.AbsoluteUri));
    217. }
    218. private void setExample()
    219. {
    220. string res = "";
    221. if (isPro)
    222. {
    223. res += pro;
    224. }
    225. if (isCity)
    226. {
    227. res+= city;
    228. }
    229. if (isCounty)
    230. {
    231. res += county;
    232. }
    233. if(isTown)
    234. {
    235. res += town;
    236. }
    237. res += building;
    238. txtExample.Text = res;
    239. }
    240. private void chkPro_Checked(object sender, RoutedEventArgs e)
    241. {
    242. isPro = chkPro.IsChecked.Value;
    243. setExample();
    244. }
    245. private void chkCity_Checked(object sender, RoutedEventArgs e)
    246. {
    247. isCity= chkCity.IsChecked.Value;
    248. setExample();
    249. }
    250. private void chkCounty_Checked(object sender, RoutedEventArgs e)
    251. {
    252. isCounty= chkCounty.IsChecked.Value;
    253. setExample();
    254. }
    255. private void chkTown_Checked(object sender, RoutedEventArgs e)
    256. {
    257. isTown= chkTown.IsChecked.Value;
    258. setExample();
    259. }
    260. }
    261. }

    2.代码逻辑

    1. using System;
    2. using System.Collections.Generic;
    3. using System.Text;
    4. using System.IO;
    5. using ESRI.ArcGIS.Geodatabase;
    6. using ESRI.ArcGIS.Geometry;
    7. using ESRI.ArcGIS.Carto;
    8. using System.Windows;
    9. using GISCommonHelper;
    10. using DayDreamInGISTool.Assister;
    11. using Newtonsoft.Json.Linq;
    12. namespace DayDreamInGISTool.GeoCoding
    13. {
    14. ///
    15. /// 高德地图逆地理编码
    16. /// 地址结构点选 OO
    17. /// 处理消息/状态写入 OO
    18. /// 进度条 OO
    19. /// token限制 默认token限速
    20. ///
    21. public class btnInverseGeocoding : ESRI.ArcGIS.Desktop.AddIns.Button
    22. {
    23. public btnInverseGeocoding()
    24. {
    25. }
    26. ESRI.ArcGIS.esriSystem.ITrackCancel trackCancel = null;
    27. ESRI.ArcGIS.esriSystem.IStepProgressor stepProgressor = null;
    28. ESRI.ArcGIS.Framework.IProgressDialog2 progressDialog2 = null;
    29. InverseGCWPF iwp = null;
    30. string tsttoken = "";
    31. bool isTest = false;
    32. protected override void OnClick()
    33. {
    34. try
    35. {
    36. iwp = new InverseGCWPF();
    37. if (iwp.ShowDialog().Value)
    38. {
    39. if(iwp.Gdtoken== tsttoken)
    40. {
    41. MessageBox.Show("测试token,每次处理不超过30个要素");
    42. isTest = true;
    43. }
    44. trackCancel = new ESRI.ArcGIS.Display.CancelTrackerClass();
    45. ESRI.ArcGIS.Framework.IProgressDialogFactory progressDialogFactory = new ESRI.ArcGIS.Framework.ProgressDialogFactoryClass();
    46. stepProgressor = progressDialogFactory.Create(trackCancel, ArcMap.Application.hWnd);
    47. ESRI.ArcGIS.Framework.IProgressDialog2 progressDialog2 = (ESRI.ArcGIS.Framework.IProgressDialog2)stepProgressor; // Explict Cast
    48. progressDialog2.CancelEnabled = true;
    49. progressDialog2.Description = "逆地理编码中...";
    50. progressDialog2.Title = "逆地理编码";
    51. progressDialog2.Animation = ESRI.ArcGIS.Framework.esriProgressAnimationTypes.esriProgressGlobe;
    52. stepProgressor.Show();
    53. execute();
    54. //完成
    55. trackCancel = null;
    56. stepProgressor = null;
    57. progressDialog2.HideDialog();
    58. progressDialog2 = null;
    59. }
    60. }
    61. catch (Exception ex)
    62. {
    63. MessageBox.Show("发生未知异常:"+ex.Message);
    64. }
    65. }
    66. string statusFd = "status";
    67. string infoFd = "info";
    68. private void execute()
    69. {
    70. //创建可能的消息状态字段
    71. try
    72. {
    73. GISCommonHelper.FieldHelper.AddStringField(iwp.Pftlyr.FeatureClass, new KeyValuePair<string, int>(statusFd, 10),
    74. new KeyValuePair<string, int>(infoFd, 70));
    75. }
    76. catch (Exception)
    77. {
    78. MessageBox.Show("创建标识字段出错");
    79. }
    80. stepProgressor.MinRange = 0;
    81. int featurecount = iwp.Pftlyr.FeatureClass.FeatureCount(null);
    82. if (isTest)
    83. {
    84. stepProgressor.MaxRange = featurecount > 30 ? 30 : featurecount; //测试token,一次请求只能30
    85. }
    86. else
    87. {
    88. stepProgressor.MaxRange = featurecount;
    89. }
    90. stepProgressor.StepValue = 1;
    91. int n = 0;
    92. IFeatureCursor pftcursor = iwp.Pftlyr.FeatureClass.Search(null, false);
    93. IFeature pFeature= pftcursor.NextFeature();
    94. while(pFeature!=null )
    95. {
    96. if (isTest)
    97. {
    98. if (n > 30)
    99. {
    100. break;
    101. }
    102. }
    103. stepProgressor.Message = "正在处理要素,OId:" + pFeature.OID;
    104. System.Diagnostics.Debug.WriteLine("正在处理:"+pFeature.OID);
    105. double lng= (double)pFeature.getval(iwp.Xfdnm);
    106. double lat = (double)pFeature.getval(iwp.Yfdnm);
    107. RequestRes rr = getLocationStr(lng, lat);
    108. if(pFeature.Fields.FindField(statusFd)!=-1)
    109. pFeature.setval(statusFd, rr.status);
    110. if (rr.status == "0")
    111. {
    112. if(pFeature.Fields.FindField(infoFd)!=-1)
    113. pFeature.setval(infoFd, rr.info);
    114. }
    115. else if (rr.status == "1")
    116. {
    117. pFeature.setval(iwp.Locationfdnm, rr.address);
    118. }
    119. stepProgressor.Step();
    120. pFeature.Store();
    121. n++;
    122. pFeature = pftcursor.NextFeature();
    123. }
    124. }
    125. string bsurl = "https://restapi.amap.com/v3/geocode/regeo?parameters";
    126. private RequestRes getLocationStr(double lng,double lat)
    127. {
    128. RequestRes rr = new RequestRes();
    129. //https://restapi.amap.com/v3/geocode/regeo?output=xml&location=116.310003,39.991957&key=<用户的key>&radius=1000&extensions=all
    130. string location = "";
    131. string url = string.Format("https://restapi.amap.com/v3/geocode/regeo?location={0},{1}&key={2}&radius=1000&extensions=all",lng,lat,iwp.Gdtoken);
    132. string json = WebRequestAssist.GetRequestStr(url);
    133. var jRoot= JObject.Parse(json);
    134. int status= jRoot.Value<int>("status");
    135. rr.status = status.ToString();
    136. if (status == 1)
    137. {
    138. // 1 请求成功
    139. var regeocodeObj = jRoot.GetValue("regeocode") as JObject;
    140. string formatted_address = regeocodeObj.Value<string>("formatted_address");
    141. //北京市朝阳区望京街道方恒国际中心B座方恒国际
    142. //移除前缀
    143. var addressComponentObj = regeocodeObj.GetValue("addressComponent");
    144. string province = addressComponentObj.Value<string>("province");
    145. string district = addressComponentObj.Value<string>("district");
    146. string city = addressComponentObj.Value<string>("city");
    147. string township = addressComponentObj.Value<string>("township");
    148. rr.address = formatted_address;
    149. //return formatted_address;
    150. if (!iwp.IsPro)
    151. {
    152. formatted_address=formatted_address.Replace(province, "");
    153. }
    154. if(!iwp.IsCity)
    155. {
    156. if (!string.IsNullOrEmpty(city))
    157. {
    158. formatted_address = formatted_address.Replace(city, "");
    159. }
    160. }
    161. if (!iwp.IsCounty)
    162. {
    163. formatted_address = formatted_address.Replace(district,"");
    164. }
    165. if (!iwp.IsTown)
    166. {
    167. formatted_address = formatted_address.Replace(township, "");
    168. }
    169. rr.address = formatted_address;
    170. }
    171. else
    172. {
    173. //0 请求失败
    174. string info = jRoot.Value<string>("info"); //错误消息
    175. rr.info = info;
    176. }
    177. return rr;
    178. }
    179. protected override void OnUpdate()
    180. {
    181. }
    182. struct RequestRes
    183. {
    184. public string status { get; set; }
    185. public string info { get; set; }
    186. public string address { get; set; }
    187. }
    188. }
    189. }

    大体解析:(1)获取要素的经度、纬度字段值

    (2)调用高德地图逆地理编码API,获取位置描述

    (3)通过Newtonsoft.JSON解析返回的json对象,并按照要求,剔除省、市等前缀

    (4)将结果写入要素

  • 相关阅读:
    【初阶数据结构】堆排序和TopK问题
    java写一个用于生成雪花id的工具类
    学生党用什么蓝牙耳机好?学生党性价比高的蓝牙耳机推荐
    Android 面(被)试(锤)现场还原~
    JavaCV - 图像暗通道去雾
    深入浅出了解BeanFactory 和 ApplicationContext
    工具-Obsidian生产力工具,安装第三方插件(GitHub)教程,以安装Syntax Highlight(代码高亮)为例
    谈思生物直播—GENOVIS张洪妍抗体特异性酶切技术助力抗体药物结构表征
    计算机图形学之点和直线
    测开 - 进阶篇 - 细节狂魔
  • 原文地址:https://blog.csdn.net/u012839776/article/details/133935960