Select to view content in your preferred language

Local Geoprocessing without packages

7474
47
Jump to solution
11-09-2012 11:26 AM
Labels (1)
GeorgeFaraj
Frequent Contributor
I'm opening feature layers from map packages and now I need to run tools such as Union, Buffer, Intersect, etc. dynamically on those layers, then add the results as a new layer in the map. What is the best way to do this locally without using pre-modeled packages?
47 Replies
MatthewBrown1
Deactivated User
... the tool runs fine if I don't specify the Fields collection. But then the output doesn't contain the fields of the input features; it contains the fields of the schema set in the GPK; which is the problem I'm trying to resolve.!


I've hit this issue as well, and I got around it by using a bunch of conditional Add Field/Calculate Field/Delete Field tools to tidy things up. Hardly ideal!

I haven't tried this in the Runtime, but I will have a go later this week (time permitting) as I too am often frustrated by subtle changes in schema.
0 Kudos
GeorgeFaraj
Frequent Contributor
Let me know how that turns out please. Thanks!
0 Kudos
MichaelBranscomb
Esri Frequent Contributor
Hi,

Here's the code I'm using to persist from the input featureset to the output featureclass:

  /* 
             * Build the GP Parameters...
             */
            // We want to specify input attributes - create a new FeatureSet.
            FeatureSet featureSet = new FeatureSet();

            // Create the Fields and add one called "VALUE".
            featureSet.Fields = new List<Field> { new Field() { FieldName = "VALUE", Type = Field.FieldType.String, Alias = "VALUE" } };
            
            // Create the graphic to submit.
            Graphic g = new Graphic() { Geometry = _mercator.ToGeographic(e.MapPoint) };

            // Add the graphic to the FeatureSet
            featureSet.Features.Add(g);

            // Set the graphic's attribute
            featureSet.Features[0].Attributes["VALUE"] = "Hello";

            // Create a new list of GPParameters
            List<GPParameter> parameters = new List<GPParameter>();

            // Add a new GPFeatureRecordSetLayer to the parameter list, passing in the FeatureSet created above.
            parameters.Add(new GPFeatureRecordSetLayer("Input_Features",featureSet));

            // Handler for the completed event
            _gpTask.ExecuteCompleted += (s, e1) =>
            {
                //OutputCopyFeatures
                GPExecuteResults results = e1.Results;
                GPFeatureRecordSetLayer rs = results.OutParameters[0] as GPFeatureRecordSetLayer;
                // Check the attributes... output feature should have attribute Field "VALUE" with value "Hello".
            };

0 Kudos
GeorgeFaraj
Frequent Contributor
Hi Mike,

If you scroll up a little bit, you'll see that I'm using similar code. The only difference is that I'm getting my input features from the SelectedGraphics collection. And I will emphasize that these features have a different attribute schema than the one I used to save my GPK.

Thanks.
0 Kudos
MichaelBranscomb
Esri Frequent Contributor
Hi,

Apologies, for the delay in replying - to pursue this issue a little further I actually demo'd it at the recent Esri Dev Summit. You can download the code for all the demos from GitHub or ArcGIS.com:

https://github.com/Esri/tips-and-tricks-wpf
http://www.arcgis.com/home/item.html?id=3f69c79bbd7340b09fad396647a977a5

I've also attached the specific demo to this post.

Cheers

Mike
0 Kudos
GeorgeFaraj
Frequent Contributor
Thank you Mike, I will be trying this out today.
0 Kudos
GeorgeFaraj
Frequent Contributor
Hi Mike,

I was doing something similar to your sample app. But the difference is that I'm working with pre-existing graphics with pre-existing attributes, while you were creating a new graphic and adding a new field.

I got this to work well now, which is a big progress:

var featureSet = new FeatureSet();
var layer = GetSelectedInputLayer();

featureSet.Fields = new List<Field>((layer as FeatureLayer).LayerInfo.Fields);
foreach (var graphic in layer.SelectedGraphics)
{
 featureSet.Features.Add(graphic);
}
parameters.Add(new GPFeatureRecordSetLayer("InputFeatures", featureSet));
parameters.Add(new GPLinearUnit("Distance", esriUnits.esriMeters, Convert.ToDouble(distanceText.Text)));


The problem now is that this only works with Feature Layers that have a LayerInfo value. I want this to work with a regular GraphicsLayer too, and the list of fields is not known to me ahead of time.

I wrote the following helper methods that will return the list of Fields for any layer:

public static ICollection<Field> GetFields(Graphic graphic)
{
 var fields = new List<Field>();
 foreach (var attribute in graphic.Attributes.Keys)
 {
  fields.Add(new Field()
  {
   FieldName = attribute, Type = Field.FieldType.Unknown, Alias = attribute
  });
 }
 return fields;
}

public static ICollection<Field> GetFields(Layer layer)
{
 if (layer is FeatureLayer)
 {
  var featureLayer = layer as FeatureLayer;
  if (featureLayer.LayerInfo != null)
  {
   return featureLayer.LayerInfo.Fields;
  }
  else if (featureLayer.Graphics.Count > 0)
  {
   return GetFields(featureLayer.Graphics[0]);
  }
 }
 else if (layer is GraphicsLayer)
 {
  var graphicsLayer = layer as GraphicsLayer;
  if (graphicsLayer.Graphics.Count > 0)
  {
   return GetFields(graphicsLayer.Graphics[0]);
  }
 }

 return new List<Field>();
}



So basically I'm looping through the attributes of the first Graphic and retrieving the Fields this way. But when I pass this collection of fields to the geoprocessor, it fails. It's obvious that the fields are causing the failure because if I don't specify the Fields property of the FeatureSet, the geoprocessor succeeds.

Is there a more accurate way of getting a list of fields/attributes from non-feature layers like Graphics layers?

Thanks!
0 Kudos
GeorgeFaraj
Frequent Contributor
I finally got this working. I'll put the code here in case anyone else needs help with this. I needed to specify the correct field type, and especially I needed to correctly identify the OID field too. Thanks for everyone that helped.


  public static ICollection<Field> GetFields(Graphic graphic)   {    var fields = new List<Field>();    foreach (var attribute in graphic.Attributes)    {     var field = new Field()     {      FieldName = attribute.Key,      Alias = attribute.Key     };     if (attribute.Key.ToLower() == "shape")     {      field.Type = Field.FieldType.Geometry;     }     else if (attribute.Key.ToLower() == "fid")     {      field.Type = Field.FieldType.OID;     }     else if (attribute.Key.ToLower() == "objectid")     {      field.Type = Field.FieldType.OID;     }     else if (attribute.Value is int)     {      field.Type = Field.FieldType.Integer;     }     else if (attribute.Value is double)     {      field.Type = Field.FieldType.Double;     }     else if (attribute.Value is float)     {      field.Type = Field.FieldType.Single;     }     else if (attribute.Value is DateTime)     {      field.Type = Field.FieldType.Date;     }     else     {      field.Type = Field.FieldType.String;     }     fields.Add(field);    }    return fields;   }
0 Kudos