Select to view content in your preferred language

Trying to do a MakeFeaturelayer followed by a Clip

742
6
06-02-2022 09:08 AM
MarioLandry2
Occasional Contributor

I've built a method that does create a FeatureLayer (temp_layer).  And once that FeatureLayer is created, it is used in a clip operation.

But the clipping part does not work because it cannot recognize the featurelayer (temp_layer).

It's probably linked to the async process.

Anybody has a suggestion about that problem?

Here's the piece a code that does what I've said:

/// <summary>
/// Execute the MakeFeatureLayer Tool in the ArcMap Toolbox.
/// Followed by a clip on that featurelayer.
/// </summary>
/// <returns></returns>
/// <remarks></remarks>
public static async Task<bool> ExecuteMakeFeatureLayerAndClipAsync(string _inputFeatures,
string _outputLayer,
string _clipFClassPath,
string _whereClause = "",
string _workSpace = "",
string _field_Info = "")
{
var environments = Geoprocessing.MakeEnvironmentArray(overwriteoutput: true);

List<object> arguments = new()
{
_inputFeatures,
"temp_layer",
_whereClause,
_workSpace,
_field_Info
};

IGPResult result = await Geoprocessing.ExecuteToolAsync("management.MakeFeatureLayer", Geoprocessing.MakeValueArray(arguments.ToArray()), environments, null, null, GPExecuteToolFlags.None);
if (result.IsFailed)
{
Geoprocessing.ShowMessageBox(result.Messages, "GP Messages", GPMessageBoxStyle.Error);
}

arguments = new()
{
"temp_layer",
_clipFClassPath,
_outputLayer,
""
};

result = await Geoprocessing.ExecuteToolAsync("analysis.Clip", Geoprocessing.MakeValueArray(arguments.ToArray()), environments, null, null, GPExecuteToolFlags.None);
if (result.IsFailed)
{
Geoprocessing.ShowMessageBox(result.Messages, "GP Messages", GPMessageBoxStyle.Error);
}

return !result.IsFailed;
}

0 Kudos
6 Replies
KenBuja
MVP Esteemed Contributor

What I've done when using the result of one GeoProcessing tool in another tool is to get the FeatureClass of the result as an input to the second tool. This is using a geodatabase where everything will be stored. Here's an example:

 

IGPResult result = await Geoprocessing.ExecuteToolAsync("management.MakeFeatureLayer", Geoprocessing.MakeValueArray(arguments.ToArray()), environments, null, null, GPExecuteToolFlags.None);
if (result.IsFailed)
{
  Geoprocessing.ShowMessageBox(result.Messages, "GP Messages", GPMessageBoxStyle.Error);
  return;  //Exit if the first step fails
}
using (FeatureClass tempFC = geodatabase.OpenDataset<FeatureClass>("temp_layer"))
{
  arguments = new()
  {
    tempFC,
    _clipFClassPath,
    _outputLayer,
    ""
  };

  result = await Geoprocessing.ExecuteToolAsync("analysis.Clip", Geoprocessing.MakeValueArray(arguments.ToArray()), environments, null, null, GPExecuteToolFlags.None);
  if (result.IsFailed)
  {
    Geoprocessing.ShowMessageBox(result.Messages, "GP Messages", GPMessageBoxStyle.Error);
  }

  return !result.IsFailed;
}

 

 

0 Kudos
MarioLandry2
Occasional Contributor

Interesting approach.

But it does not work because I'm using a FeatureLayer which resides in memory only.  It is not part of the FGDB. I'm using a feature layer because it should be faster than creating a feature class which will be staying on the FGDB.

The line 

using (FeatureClass tempFC = geodatabase.OpenDataset<FeatureClass>("temp_layer"))

returns an error saying the table cannot be found.

I used to do that operation with ArcObjects without any problems, but it does not seem to be the case under ArcGIS PRo SDK.

0 Kudos
KenBuja
MVP Esteemed Contributor

I have used a memory geodatabase to temporarily copy a feature class and work with it.

MemoryConnectionProperties memoryConnectionProperties = new MemoryConnectionProperties();
using (Geodatabase geodatabase = SchemaBuilder.CreateGeodatabase(memoryConnectionProperties))
{
  string path = geodatabase.GetPath().AbsolutePath;
  var copyResult = await Utilities.CopyFeatureClass(SelectedFCFeatureLayer.GetFeatureClass(), path, "VirtualInputLayer"); //this is a function to call the "conversion.FeatureClassToFeatureClass" tool

 

0 Kudos
MarioLandry2
Occasional Contributor

I tried your suggestion, but it did not work because of the line:

string path = geodatabase.GetPath().AbsolutePath;

 

The GetPath() method return null when the geodatabase is in memory.

So instead, I tried to do a selection followed by a CopyFeatures into memory (using @"memory\") and then the clip, just like this:

public static async Task<bool> ExecuteMakeFeatureLayerAndClipAsync(string _inputFeatures,
string _outputLayer,
string _clipFClassPath,
string _whereClause = "",
string _workSpace = "",
string _field_Info = "")
{
var environments = Geoprocessing.MakeEnvironmentArray(overwriteoutput: true);

await ExecuteSelectLayerByAttributeAsync(_inputFeatures, "NEW_SELECTION", _whereClause);

string path = @"memory\";
await ExecuteCopyFeaturesAsync(_inputFeatures, path + "temp_layer");

List<object> arguments = new()
{
path + "temp_layer",
_clipFClassPath,
_outputLayer,
""
};

IGPResult result = await Geoprocessing.ExecuteToolAsync("analysis.Clip", Geoprocessing.MakeValueArray(arguments.ToArray()), environments, null, null, GPExecuteToolFlags.None);
if (result.IsFailed)
{
Geoprocessing.ShowMessageBox(result.Messages, "GP Messages", GPMessageBoxStyle.Error);
}

return !result.IsFailed;
}

It worked, but the performance is not there when I compare it with the code in the old ArcObjects that uses a MakeFeatureLayer followed by a clip.

For the exact same layer containing a lot of records, it used to take 10 seconds using ArcObjects, and under ArcGIS Pro SDK it takes almost 5 minutes.

The problem right now is not being able to use the FeatureLayer created when using "management.MakeFeatureLayer"

 

0 Kudos
KenBuja
MVP Esteemed Contributor

That path variable was a result of testing I was doing with different geodatabases. My code was copying an existing FeatureClass into memory, then adding fields to it for some additional analysis. That was working fine in ArcObjects, but not in the Pro SDK. I can't seem to add the fields to a FC in a memory geodatabase, so I have to copy it the geodatabase where the original FC resides, which is much slower.

0 Kudos
MarioLandry2
Occasional Contributor

Well, thanks a lot for the solution you tried to provide.  I'll keep digging, and if I find something, I'll do a reply.

0 Kudos