PageRenderTime 37ms CodeModel.GetById 10ms RepoModel.GetById 1ms app.codeStats 0ms

/GPX.FireMap.Workflow/GPX.FireMap.Workflow/CalculateNearestFeature.cs

https://bitbucket.org/shope/dfu
C# | 316 lines | 202 code | 75 blank | 39 comment | 19 complexity | a1c63f7ec260999c7cac09e852319ba1 MD5 | raw file
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Text;
  5. using System.Activities;
  6. using System.ComponentModel;
  7. using GPX.Firemap.Workflow.Activities;
  8. using Geocortex.Logging;
  9. using Geocortex.Workflow.Activities;
  10. using ESRI.ArcGIS.Client.Tasks;
  11. using ESRI.ArcGIS.Client;
  12. using System.Net;
  13. using System.IO;
  14. using ESRI.ArcGIS.Client.Geometry;
  15. using Newtonsoft.Json.Linq;
  16. namespace GPX.Firemap.Workflow.Activities.Server
  17. {
  18. [Description("Calculates the nearest feature to a coordinate")]
  19. [WorkflowDesigner(
  20. DisplayName = "Calculate nearest feature",
  21. ToolboxCategory = "Firemap Server Activities")]
  22. public sealed class CalculateNearestFeature : CodeActivity
  23. {
  24. [CategoryAttribute("In Arguments")]
  25. [Description(@"Nearest Feature Definitions")]
  26. [DisplayName("Nearest Feature Definitions")]
  27. public InArgument<string> NearestFeatureDefinitions { get; set; }
  28. [CategoryAttribute("In Arguments")]
  29. [Description(@"Intersect Feature Definitions")]
  30. [DisplayName("Intersect Feature Definitions")]
  31. public InArgument<string> IntersectFeatureDefinitions { get; set; }
  32. [CategoryAttribute("In Arguments")]
  33. [Description(@"Projection Definitions")]
  34. [DisplayName("Projection Definitions")]
  35. public InArgument<string> ProjectionDefinitions { get; set; }
  36. [CategoryAttribute("In Arguments")]
  37. [Description(@"Location")]
  38. [DisplayName("Location")]
  39. public InArgument<MapPoint> Location { get; set; }
  40. [CategoryAttribute("In Arguments")]
  41. [Description(@"Root Service URL")]
  42. [DisplayName("Root Service URL")]
  43. public InArgument<string> RootServiceURL { get; set; }
  44. [CategoryAttribute("In Arguments")]
  45. [Description(@"Nearest Feature Service URL")]
  46. [DisplayName("Nearest Feature Service URL")]
  47. public InArgument<string> NearestFeatureServiceURL { get; set; }
  48. [CategoryAttribute("In Arguments")]
  49. [Description(@"Geometry Service URL")]
  50. [DisplayName("Geometry Service URL")]
  51. public InArgument<string> GeometryServiceURL { get; set; }
  52. [CategoryAttribute("Out Arguments")]
  53. [Description(@"Nearest Features")]
  54. [DisplayName("Nearest Features")]
  55. public OutArgument<string[]> NearestFeatures { get; set; }
  56. /// <summary>
  57. /// When implemented in a derived class, performs the execution of the activity.
  58. /// </summary>
  59. /// <param name="context">The execution context under which the activity executes.</param>
  60. protected override void Execute(CodeActivityContext context)
  61. {
  62. try
  63. {
  64. Logger.SystemInfo(this.DisplayName + " beginning activity execute ");
  65. List<string> nearestResults = new List<string>();
  66. // Obtain and validate the runtime values
  67. string rootServiceUrl = context.GetValue(this.RootServiceURL);
  68. if (string.IsNullOrEmpty(rootServiceUrl))
  69. Logger.SystemError("The root service url is not defined");
  70. string nearestFeatureServiceUrl = context.GetValue(this.NearestFeatureServiceURL);
  71. if (string.IsNullOrEmpty(nearestFeatureServiceUrl))
  72. Logger.SystemError("The nearest feature service url is not defined");
  73. string geometryServiceUrl = context.GetValue(this.GeometryServiceURL);
  74. if (string.IsNullOrEmpty(geometryServiceUrl))
  75. Logger.SystemError("The geometry service url is not defined");
  76. MapPoint location = context.GetValue(this.Location);
  77. if (location==null)
  78. Logger.SystemError("The input location is not defined");
  79. SpatialReference sr = location.SpatialReference;
  80. if (sr == null)
  81. Logger.SystemError("The location input location does not have a spatial reference");
  82. string nfdsAsJson = context.GetValue(this.NearestFeatureDefinitions);
  83. string ifdsAsJson = context.GetValue(this.IntersectFeatureDefinitions);
  84. string pdsAsJson = context.GetValue(this.ProjectionDefinitions);
  85. if (!string.IsNullOrEmpty(nfdsAsJson))
  86. {
  87. List<NearestFeatureDefinition> nfds = Newtonsoft.Json.JsonConvert.DeserializeObject<List<NearestFeatureDefinition>>(nfdsAsJson);
  88. //process the nearest
  89. ProcessNearestFeatureRequests(nearestResults, location, nfds, rootServiceUrl, nearestFeatureServiceUrl);
  90. }
  91. if (!string.IsNullOrEmpty(ifdsAsJson))
  92. {
  93. List<IntersectFeatureDefinition> ifds = Newtonsoft.Json.JsonConvert.DeserializeObject<List<IntersectFeatureDefinition>>(ifdsAsJson);
  94. //process the interesting features
  95. ProcessIntersectingFeatureRequests(nearestResults, location, ifds, rootServiceUrl);
  96. }
  97. if (!string.IsNullOrEmpty(pdsAsJson))
  98. {
  99. List<ProjectionDefinition> pds = Newtonsoft.Json.JsonConvert.DeserializeObject<List<ProjectionDefinition>>(pdsAsJson);
  100. ProcessProjectionRequests(nearestResults, location, pds, geometryServiceUrl);
  101. }
  102. context.SetValue(NearestFeatures, nearestResults.ToArray());
  103. Logger.SystemInfo(this.DisplayName + " ending activity execute ");
  104. }
  105. catch (Exception ex)
  106. {
  107. Logger.SystemError(ex.Message);
  108. }
  109. }
  110. /// <summary>
  111. /// Processes the projection requests.
  112. /// </summary>
  113. /// <param name="nearestResults">The nearest results.</param>
  114. /// <param name="location">The location.</param>
  115. /// <param name="pds">The PDS.</param>
  116. /// <param name="geometryServiceUrl">The geometry service URL.</param>
  117. private void ProcessProjectionRequests(List<string> nearestResults, MapPoint location, List<ProjectionDefinition> pds, string geometryServiceUrl)
  118. {
  119. try
  120. {
  121. foreach (ProjectionDefinition pd in pds)
  122. {
  123. //request the intersecting feature
  124. JObject projectedCoordinates;
  125. AGSServerSupport.CallArcGISServer(AGSServerSupport.CreateProjectGeometryRequest(location, location.SpatialReference.WKID.ToString(), pd.Wkid.ToString(), geometryServiceUrl), out projectedCoordinates);
  126. if (projectedCoordinates != null)
  127. {
  128. JArray coordinates = (JArray)projectedCoordinates["geometries"];
  129. foreach (var coordinate in coordinates)
  130. {
  131. double x = (double)coordinate["x"];
  132. double y = (double)coordinate["y"];
  133. StringBuilder resultBuilder = new StringBuilder();
  134. resultBuilder.Append(pd.DisplayName + " ");
  135. resultBuilder.Append("X:" + Math.Round(x, 2).ToString() + " ");
  136. resultBuilder.Append("Y:" + Math.Round(y, 2).ToString());
  137. nearestResults.Add(resultBuilder.ToString());
  138. }
  139. }
  140. }
  141. }
  142. catch (Exception ex)
  143. {
  144. Logger.SystemError(ex.Message);
  145. }
  146. }
  147. /// <summary>
  148. /// Processes the intersecting feature requests.
  149. /// </summary>
  150. /// <param name="nearestResults">The nearest results.</param>
  151. /// <param name="location">The location.</param>
  152. /// <param name="ifds">The intersecting feature definitions.</param>
  153. /// <param name="rootUrl">The root URL.</param>
  154. private void ProcessIntersectingFeatureRequests(List<string> nearestResults, MapPoint location, List<IntersectFeatureDefinition> ifds, string rootUrl)
  155. {
  156. try
  157. {
  158. foreach (IntersectFeatureDefinition ifd in ifds)
  159. {
  160. string lyrId = ifd.LyrId.ToString();
  161. //request the intersecting feature
  162. JObject IntersectingFeature;
  163. AGSServerSupport.CallArcGISServer(AGSServerSupport.CreateQueryRequest(location, rootUrl, ifd, lyrId), out IntersectingFeature);
  164. if (IntersectingFeature != null)
  165. {
  166. JArray features = (JArray)IntersectingFeature["features"];
  167. foreach (var feature in features)
  168. {
  169. JObject attributes = (JObject)feature["attributes"];
  170. string attribute = (string)attributes[ifd.Fields];
  171. StringBuilder resultBuilder = new StringBuilder();
  172. resultBuilder.Append(ifd.Name + " ");
  173. if (!string.IsNullOrEmpty(attribute))
  174. resultBuilder.Append(attribute + " ");
  175. nearestResults.Add(resultBuilder.ToString());
  176. }
  177. }
  178. }
  179. }
  180. catch (Exception ex)
  181. {
  182. Logger.SystemError(ex.Message);
  183. }
  184. }
  185. /// <summary>
  186. /// Processes the nearest feature requests.
  187. /// </summary>
  188. /// <param name="nearestResults">The nearest results.</param>
  189. /// <param name="location">The location.</param>
  190. /// <param name="nfds">The nearest feature definitions.</param>
  191. /// <param name="rootUrl">The root URL.</param>
  192. /// <param name="nearestFeatureUrl">The nearest feature URL.</param>
  193. private void ProcessNearestFeatureRequests(List<string> nearestResults, MapPoint location, List<NearestFeatureDefinition> nfds, string rootUrl, string nearestFeatureUrl)
  194. {
  195. try
  196. {
  197. foreach (NearestFeatureDefinition nfd in nfds)
  198. {
  199. string lyrId = nfd.LyrId.ToString();
  200. //request the nearest feature id
  201. JObject NearestFeatureId;
  202. AGSServerSupport.CallArcGISServer(AGSServerSupport.CreateNearestFeatureIdRequest(location, lyrId, nearestFeatureUrl), out NearestFeatureId);
  203. //double? distance;
  204. //NearestFeatureId.TryGetAsDouble("Distance", out distance);
  205. //long? id;
  206. //NearestFeatureId.TryGetAsLong("NearestFeatureId", out id);
  207. double distance = (double)NearestFeatureId["Distance"];
  208. int id = (int)NearestFeatureId["NearestFeatureId"];
  209. //send second request for feature itself
  210. JObject response;
  211. string finalUrl = string.Format(rootUrl + "{0}/{1}?f=json", lyrId, id.ToString());
  212. AGSServerSupport.CallArcGISServer(finalUrl, out response);
  213. //validate the response - because the Nearest Feature REST endpoint works directly on the feature class it will not honour any
  214. //definition queries set on the layer in the map service therefore check to see whethe the response inclues an error;
  215. JObject error = (JObject)response["error"];
  216. if (error != null)
  217. {
  218. Logger.SystemInfo("The following request " + finalUrl + "returned an error");
  219. response = null;
  220. }
  221. if (response != null)
  222. {
  223. JObject feature = (JObject)response["feature"];
  224. JObject attributes = (JObject)feature["attributes"];
  225. string attribute = (string)attributes[nfd.Fields];
  226. StringBuilder sb = new StringBuilder();
  227. sb.Append(nfd.Name + " ");
  228. if (!string.IsNullOrEmpty(attribute))
  229. sb.Append(attribute + " ");
  230. sb.Append("Distance: " + distance.ToString());
  231. nearestResults.Add(sb.ToString());
  232. }
  233. }
  234. }
  235. catch (Exception ex)
  236. {
  237. Logger.SystemError(ex.Message);
  238. }
  239. }
  240. }
  241. }