Sunday, 4 February 2018

.net - Writing In-memory IFeatureLayer to Shapefile using ArcObjects (Engine SDK)



I've been working on this for a little while now, and can not seem to get this thing working.


I've managed to export a geodatabase feature class and shapefile to a shapefile, but what I'm struggling with right now is writing an in-memory feature layer (one that is created based on a selection of features) to a shapefile/geodatabase.


If anyone can help me with a code snippet (doesn't matter the language), or some links to some dark corner of the ESRI docs, I would be much obliged.


UPDATE


I used the following code to create the IFeatureLayer:


IFeatureSelection featureSelection = (IFeatureSelection)layer;
if (featureSelection.SelectionSet.Count > 0)
{
IFeatureLayerDefinition2 featDef = (IFeatureLayerDefinition2)featureSelection;
IFeatureLayer fLayer = featDef.CreateSelectionLayer(

String.Format( CultureInfo.InvariantCulture,
"{0}_Selection", layer.Name ),
true, "", "" );

featureSelection.Clear();

if (fLayer != null)
{
_hook.FocusMap.AddLayer( fLayer );
_hook.ActiveView.Refresh();

}
}

This creates and adds a new layer to the TOC.


What I'm missing now is taking that Feature selection and saving this to a Shapefile (for now).


The code example I've been working with is from esri code snippets but I'm getting stuck on the following:


IDataset sourceDataset = (IDataset)_layer;

IWorkspace sourceWorkspace;
IPropertySet propertySet = sourceDataset.Workspace.ConnectionProperties;

sourceWorkspace = sourceDataset.Workspace.WorkspaceFactory.Open( propertySet, 0 );

if (sourceDataset.FullName != null)
{
// HERE - Invalid Cast Exception.
IWorkspaceName sourceWorkspaceName = (IWorkspaceName)sourceDataset.FullName;
}

The full exception is here:




Unable to cast COM object of type 'System.__ComObject' to interface type 'ESRI.ArcGIS.Geodatabase.IWorkspaceName'. This operation failed because the QueryInterface call on the COM component for the interface with IID '{FADD975C-E36F-11D1-AA81-00C04FA33A15}' failed due to the following error: No such interface supported (Exception from HRESULT: 0x80004002 (E_NOINTERFACE)).



I guess the exception is thrown because the FullName property though is not empty is not compatible because of the type of COM object it is wrapping.


Any thoughts?



Answer



Ok Folk, This took some time to get worked out, mainly because it is a part of the ArcObjects API that I haven't worked with often, or frustration clouding pragmatic thought, or an extremely large (misleading) API. I would like to thank Kirk Kuykendall for some additional resources and ideas on this and other sites.


Here is the solution. It has been lightly tested but its there for all.


public static bool ExportLayerToShapefile(
string shapePath,
string shapeName,

ILayer source,
out IEnumFieldError fieldErrors,
out IEnumInvalidObject invalidObjects)
{
IGeoFeatureLayer sourceFeatLayer = (IGeoFeatureLayer)source;
IFeatureLayer sfeatlayer = (IFeatureLayer)sourceFeatLayer;
IFeatureClass sfeatClass = sfeatlayer.FeatureClass;
IDataset sdataset = (IDataset)sfeatClass;
IDatasetName sdatasetName = (IDatasetName)sdataset.FullName;


ISelectionSet sSelectionSet = (
(ITable)source).Select( new QueryFilter(),
esriSelectionType.esriSelectionTypeHybrid,
esriSelectionOption.esriSelectionOptionNormal,
sdataset.Workspace );

IWorkspaceFactory factory;
factory = new ShapefileWorkspaceFactory();
IWorkspace targetWorkspace = factory.OpenFromFile( shapePath, 0 );
IDataset targetDataset = (IDataset)targetWorkspace;


IName targetWorkspaceName = targetDataset.FullName;
IWorkspaceName tWorkspaceName = (IWorkspaceName)targetWorkspaceName;

IFeatureClassName tFeatClassname = (IFeatureClassName)new FeatureClassName();
IDatasetName tDatasetName = (IDatasetName)tFeatClassname;
tDatasetName.Name = shapeName;
tDatasetName.WorkspaceName = tWorkspaceName;

IFieldChecker fieldChecker = new FieldChecker();

IFields sFields = sfeatClass.Fields;
IFields tFields = null;

fieldChecker.InputWorkspace = sdataset.Workspace;
fieldChecker.ValidateWorkspace = targetWorkspace;

fieldChecker.Validate( sFields, out fieldErrors, out tFields );
if (fieldErrors != null)
{
IFieldError fieldError = null;

while((fieldError = fieldErrors.Next()) != null)
{
Console.WriteLine(fieldError.FieldError + " : " + fieldError.FieldIndex);
}
Console.WriteLine( "[ExportDataViewModel.cs] Errors encountered during field validation" );
}

string shapefieldName = sfeatClass.ShapeFieldName;
int shapeFieldIndex = sfeatClass.FindField( shapefieldName );
IField shapefield = sFields.get_Field( shapeFieldIndex );

IGeometryDef geomDef = shapefield.GeometryDef;
IClone geomDefClone = (IClone)geomDef;
IClone targetGeomDefClone = geomDefClone.Clone();
IGeometryDef tGeomDef = (IGeometryDef)targetGeomDefClone;

IFeatureDataConverter2 featDataConverter = (IFeatureDataConverter2)new FeatureDataConverter();
invalidObjects = featDataConverter.ConvertFeatureClass(
sdatasetName,
null,
sSelectionSet,

null,
tFeatClassname,
tGeomDef,
tFields,
"",
1000, 0 );

string fullpath = System.IO.Path.Combine( shapePath, shapeName );
return System.IO.File.Exists( fullpath );
}

No comments:

Post a Comment

arcpy - Changing output name when exporting data driven pages to JPG?

Is there a way to save the output JPG, changing the output file name to the page name, instead of page number? I mean changing the script fo...