This code is looping over polygons geometries vertices in order to create a list of deltas (distance) between vertices coordinates to compact the geometry before sending it into the web.
Geometry output is expected to be on this format: [[x0, y0, (x0-x1), (y0-y1), (x1-x2), (y1-y2)]]
The output is a JSON object containing a list of features attributes and geometry deltas like this one:
{
features: [
{
attributes : {"CD_MUNCP" : 00000, "NOM_MUNCP": "Name1"},
geometry : [[5767767, -834778, -10, 199, 99, 332, 9, -9], [5787767, -837709, 123, 33, -31, 121, 0, 12330]]
}
]
}
I am using IEnumerable<>
to create the geometry deltas because I thought it would be faster, but it appears this is not really compatible with JSON serialization (it takes very long to serialize) so I transform them using .ToList()
.
The most important thing with the code is the performance. It seems the bottleneck is the JSON serialization that takes more than 50% of the processing time.
Is there some optimizations or workarounds I can do to improve the performance?
using System;
using System.Collections.Generic;
using fastJSON;
using ESRI.ArcGIS.ADF;
using ESRI.ArcGIS.Geodatabase;
using ESRI.ArcGIS.Geometry;
using ESRI.ArcGIS.esriSystem;
namespace DesktopConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
var watch = System.Diagnostics.Stopwatch.StartNew();
Result result = new Result
{
features = CreateResultFeatures().ToList()
};
string output = JSON.ToJSON(result);
watch.Stop();
Console.WriteLine(watch.ElapsedMilliseconds);
Console.ReadLine();
}
public class Result
{
public IEnumerable<ResultFeature> features { get; set; }
}
public class ResultFeature
{
public Dictionary<string, dynamic> attributes { get; set; }
public IEnumerable<IEnumerable<int>> geometry { get; set; }
}
public static IEnumerable<ResultFeature> CreateResultFeatures()
{
IWorkspace gdbWorkspace = FileGdbWorkspaceFromPath(@"\\vnageop1\geod\Maxime\test.gdb");
IFeatureWorkspace featureWorkspace = (IFeatureWorkspace)gdbWorkspace;
IFeatureClass featureClass = featureWorkspace.OpenFeatureClass(@"GEO09E04_MUNCP_GEN");
IQueryFilter queryFilter = new QueryFilterClass();
queryFilter.SubFields = "CD_MUNCP, NOM_MUNCP, SHAPE";
int cd_muncp_idx = featureClass.FindField("CD_MUNCP");
int nom_muncp_idx = featureClass.FindField("NOM_MUNCP");
using (ComReleaser comReleaser = new ComReleaser())
{
IFeatureCursor cursor = featureClass.Search(queryFilter, false);
comReleaser.ManageLifetime(cursor);
IFeature feature = null;
while ((feature = cursor.NextFeature()) != null)
{
ResultFeature resultFeature = new ResultFeature
{
attributes = new Dictionary<string,dynamic>
{
{ "CD_MUNCP", Convert.ToString(feature.Value[cd_muncp_idx]) },
{ "NOM_MUNCP", Convert.ToString(feature.Value[nom_muncp_idx]) }
},
geometry = PolygonToDeltas(feature.Shape as IPolygon4).ToList()
};
yield return resultFeature;
}
}
}
public static IEnumerable<IEnumerable<int>> PolygonToDeltas(IPolygon4 polygon)
{
IGeometryBag exteriorRingGeometryBag = polygon.ExteriorRingBag;
IGeometryCollection exteriorRingGeometryCollection = exteriorRingGeometryBag as IGeometryCollection;
for (int i = 0; i < exteriorRingGeometryCollection.GeometryCount; i++)
{
IGeometry exteriorRingGeometry = exteriorRingGeometryCollection.get_Geometry(i);
IPointCollection exteriorRingPointCollection = exteriorRingGeometry as IPointCollection;
yield return CreateDeltas(exteriorRingPointCollection);
IGeometryBag interiorRingGeometryBag = polygon.get_InteriorRingBag(exteriorRingGeometry as IRing);
IGeometryCollection interiorRingGeometryCollection = interiorRingGeometryBag as IGeometryCollection;
for (int k = 0; k < interiorRingGeometryCollection.GeometryCount; k++)
{
IGeometry interiorRingGeometry = interiorRingGeometryCollection.get_Geometry(k);
IPointCollection interiorRingPointCollection = interiorRingGeometry as IPointCollection;
yield return CreateDeltas(exteriorRingPointCollection);
}
}
}
private static IEnumerable<int> CreateDeltas(IPointCollection pointCollection)
{
int previous_x = (int)pointCollection.get_Point(0).X;
int previous_y = (int)pointCollection.get_Point(0).Y;
yield return previous_x;
yield return previous_y;
for (int i = 1; i < pointCollection.PointCount; i++)
{
int current_x = (int)pointCollection.get_Point(i).X;
int current_y = (int)pointCollection.get_Point(i).Y;
yield return previous_x - current_x;
yield return previous_y - current_y;
previous_x = current_x;
previous_y = current_y;
}
}
}
}
dynamic
. It doesn't look like it's necessary. Try to replace it with a strong type and see how it performs then. \$\endgroup\$