About the Create an NDVI custom raster function Sample
[C#]
NDVICustomFunction.cs
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Runtime.InteropServices; using ESRI.ArcGIS.DataSourcesRaster; using ESRI.ArcGIS.esriSystem; using ESRI.ArcGIS.Geodatabase; using ESRI.ArcGIS.Geometry; using ESRI.ArcGIS.ADF.CATIDs; namespace CustomFunction { [Guid("652642F3-9106-4EB3-9262-A4C39E03BC56")] [ClassInterface(ClassInterfaceType.None)] [ProgId("CustomFunction.NDVICustomFunction")] [ComVisible(true)] public class NDVICustomFunction : IRasterFunction, IPersistVariant, IDocumentVersionSupportGEN, IXMLSerialize, IXMLVersionSupport { #region Private Members UID myUID; // UID for the Function. IRasterInfo myRasterInfo; // Raster Info for the Function rstPixelType myPixeltype; // Pixel Type of the Function. string myName; // Name of the Function. string myDescription; // Description of the Function. bool myValidFlag; // Flag to specify validity of the Function. IRasterFunctionHelper myFunctionHelper; // Raster Function Helper object. rstPixelType myInpPixeltype; int myInpNumBands; string[] myBandIndices; #endregion public NDVICustomFunction() { myName = "NDVI Custom Function"; myPixeltype = rstPixelType.PT_FLOAT; myDescription = "Custom NDVI Function which calculates the NDVI without any scaling."; myValidFlag = true; myFunctionHelper = new RasterFunctionHelperClass(); myInpPixeltype = myPixeltype; myInpNumBands = 0; myBandIndices = null; myUID = new UIDClass(); myUID.Value = "{652642F3-9106-4EB3-9262-A4C39E03BC56}"; } #region IRasterFunction Members /// <summary> /// Name of the Raster Function. /// </summary> public string Name { get { return myName; } set { myName = value; } } /// <summary> /// Pixel Type of the Raster Function /// </summary> public rstPixelType PixelType { get { return myPixeltype; } set { myPixeltype = value; } } /// <summary> /// Output Raster Info for the Raster Function /// </summary> public IRasterInfo RasterInfo { get { return myRasterInfo; } } /// <summary> /// Description of the Raster Function /// </summary> public string Description { get { return myDescription; } set { myDescription = value; } } /// <summary> /// Initialize the Raster function using the argument object. This is one of the two /// main functions to implement for a custom Raster function. The raster object is /// dereferenced if required and given to the RasterFuntionHelper object to bind. /// </summary> /// <param name="pArguments">Arguments object used for initialization</param> public void Bind(object pArguments) { try { // Check if the Arguments object is of the correct type. INDVICustomFunctionArguments customFunctionArgs = null; if (pArguments is INDVICustomFunctionArguments) { customFunctionArgs = (INDVICustomFunctionArguments)pArguments; object inputRaster = customFunctionArgs.Raster; if (customFunctionArgs.Raster is IRasterFunctionVariable) { IRasterFunctionVariable rasterFunctionVariable = (IRasterFunctionVariable)customFunctionArgs.Raster; inputRaster = rasterFunctionVariable.Value; } // Call the Bind method of the Raster Function Helper object. myFunctionHelper.Bind(inputRaster); } else { // Throw an error if incorrect arguments object is passed. throw new System.Exception( "Incorrect arguments object. Expected: INDVICustomFunctionArguments"); } // Check to see if Band Indices exist. if (customFunctionArgs.BandIndices != null && customFunctionArgs.BandIndices != "") myBandIndices = customFunctionArgs.BandIndices.Split(' '); else { // If not, throw an error. throw new System.Exception( "Incorrect parameters specified. Expected: Valid band indices."); } // Create a new RasterInfo object and initialize from the FunctionHelper object. // A new RasterInfo Object is created because assigning myFunctionHelper.RasterInfo // directly creates a reference. myRasterInfo = new RasterInfoClass(); myRasterInfo.BandCount = myFunctionHelper.RasterInfo.BandCount; myRasterInfo.BlockHeight = myFunctionHelper.RasterInfo.BlockHeight; myRasterInfo.BlockWidth = myFunctionHelper.RasterInfo.BlockWidth; myRasterInfo.CellSize = myFunctionHelper.RasterInfo.CellSize; myRasterInfo.Extent = myFunctionHelper.RasterInfo.Extent; myRasterInfo.FirstPyramidLevel = myFunctionHelper.RasterInfo.FirstPyramidLevel; myRasterInfo.Format = myFunctionHelper.RasterInfo.Format; myRasterInfo.GeodataXform = myFunctionHelper.RasterInfo.GeodataXform; myRasterInfo.MaximumPyramidLevel = myFunctionHelper.RasterInfo.MaximumPyramidLevel; myRasterInfo.NativeExtent = myFunctionHelper.RasterInfo.NativeExtent; myRasterInfo.NativeSpatialReference = myFunctionHelper.RasterInfo.NativeSpatialReference; myRasterInfo.NoData = myFunctionHelper.RasterInfo.NoData; myRasterInfo.Origin = myFunctionHelper.RasterInfo.Origin; myRasterInfo.PixelType = rstPixelType.PT_FLOAT; // Output pixel type should be output of the NDVI. myRasterInfo.Resampling = myFunctionHelper.RasterInfo.Resampling; myRasterInfo.SupportBandSelection = myFunctionHelper.RasterInfo.SupportBandSelection; // Store required input properties. myInpPixeltype = myRasterInfo.PixelType; myInpNumBands = myRasterInfo.BandCount; // Set output pixel properties. myRasterInfo.BandCount = 1; myPixeltype = rstPixelType.PT_FLOAT; // Perform validation to see if the indices passed are valid. if (myInpNumBands < 2 || myBandIndices.Length < 2) { // If not, throw an error. throw new System.Exception( "Incorrect parameters specified. Expected: Valid band indices."); } for (int i = 0; i < myBandIndices.Length; ++i) { int currBand = Convert.ToInt16(myBandIndices[i]) - 1; if ((currBand < 0) || (currBand > myInpNumBands)) { // If not, throw an error. throw new System.Exception( "Incorrect parameters specified. Expected: Valid band indices."); } } } catch (Exception exc) { System.Exception myExc = new System.Exception( "Exception caught in Bind method: " + exc.Message, exc); throw myExc; } } /// <summary> /// Read pixels from the input Raster and fill the PixelBlock provided with processed pixels. /// </summary> /// <param name="pTlc">Point to start the reading from in the Raster</param> /// <param name="pRaster">Reference Raster for the PixelBlock</param> /// <param name="pPixelBlock">PixelBlock to be filled in</param> public void Read(IPnt pTlc, IRaster pRaster, IPixelBlock pPixelBlock) { try { // Create a new pixel block to read the input data into. // This is done because the pPixelBlock represents the output // pixel block which is different from the input. int pBHeight = pPixelBlock.Height; int pBWidth = pPixelBlock.Width; IPnt pBlockSize = new PntClass(); pBlockSize.X = pBWidth; pBlockSize.Y = pBHeight; IPixelBlock inputPixelBlock = new PixelBlockClass(); ((IPixelBlock4)inputPixelBlock).Create(myInpNumBands, pBWidth, pBHeight, myInpPixeltype); // Call Read method of the Raster Function Helper object to read the input pixels into // the inputPixelBlock. myFunctionHelper.Read(pTlc, null, pRaster, inputPixelBlock); System.Array inpPixelValues1; System.Array inpPixelValues2; System.Array outPixelValues; int index1 = Convert.ToInt16(myBandIndices[0]) - 1; ; // Get NIR band index specified by user. int index2 = Convert.ToInt16(myBandIndices[1]) - 1; ; // Get Red Band index specified by user. // Get the correct bands from the input. IPixelBlock3 ipPixelBlock = (IPixelBlock3)inputPixelBlock; inpPixelValues1 = (System.Array)(ipPixelBlock.get_PixelData(index1)); inpPixelValues2 = (System.Array)(ipPixelBlock.get_PixelData(index2)); outPixelValues = (System.Array)(((IPixelBlock3)pPixelBlock).get_PixelData(0)); int i = 0; int k = 0; double pixelValue = 0.0; double nirValue = 0.0; double irValue = 0.0; // Perform the NDVI computation and store the result in the output pixel block. for (i = 0; i < pBHeight; i++) { for (k = 0; k < pBWidth; k++) { nirValue = Convert.ToDouble(inpPixelValues1.GetValue(k, i)); irValue = Convert.ToDouble(inpPixelValues2.GetValue(k, i)); // Check if input is not NoData. if ((Convert.ToByte(ipPixelBlock.GetNoDataMaskVal(index1, k, i)) == 1) && Convert.ToByte(ipPixelBlock.GetNoDataMaskVal(index2, k, i)) == 1) { // NDVI[k] = (NIR[k]-Red[k])/(NIR[k]+Red[k]); if ((nirValue + irValue) != 0) // Check for division by 0. { pixelValue = (nirValue - irValue) / (nirValue + irValue); if (pixelValue < -1.0 || pixelValue > 1.0) pixelValue = 0.0; } else pixelValue = 0.0; } outPixelValues.SetValue((float)(pixelValue), k, i); } } // Set the output pixel values on the output pixel block. ((IPixelBlock3)pPixelBlock).set_PixelData(0, outPixelValues); // Copy over the NoData mask from the input and set it on the output. ((IPixelBlock3)pPixelBlock).set_NoDataMask(0, ((IPixelBlock3)inputPixelBlock).get_NoDataMask(0)); } catch (Exception exc) { System.Exception myExc = new System.Exception( "Exception caught in Read method: " + exc.Message, exc); throw myExc; } } /// <summary> /// Update the Raster Function /// </summary> public void Update() { try { } catch (Exception exc) { System.Exception myExc = new System.Exception( "Exception caught in Update method: ", exc); throw myExc; } } /// <summary> /// Property that specifies whether the Raster Function is still valid. /// </summary> public bool Valid { get { return myValidFlag; } } #endregion #region IPersistVariant Members /// <summary> /// UID to identify the function. /// </summary> public UID ID { get { return myUID; } } /// <summary> /// Load the properties of the function from the stream provided /// </summary> /// <param name="Stream">Stream that contains the serialized form of the function</param> public void Load(IVariantStream Stream) { if (Stream is IDocumentVersion) { IDocumentVersion docVersion = (IDocumentVersion)Stream; if (docVersion.DocumentVersion >= esriArcGISVersion.esriArcGISVersion10) { esriArcGISVersion streamVersion = (esriArcGISVersion)((int)Stream.Read()); if (streamVersion >= esriArcGISVersion.esriArcGISVersion10) { myName = (string)Stream.Read(); myDescription = (string)Stream.Read(); myPixeltype = (rstPixelType)((int)Stream.Read()); } } } } /// <summary> /// Save the properties of the function to the stream provided /// </summary> /// <param name="Stream">Stream to which to serialize the function into</param> public void Save(IVariantStream Stream) { if (Stream is IDocumentVersion) { IDocumentVersion docVersion = (IDocumentVersion)Stream; if (docVersion.DocumentVersion >= esriArcGISVersion.esriArcGISVersion10) { Stream.Write((int)esriArcGISVersion.esriArcGISVersion10); Stream.Write(myName); Stream.Write(myDescription); Stream.Write((int)myPixeltype); } } } #endregion #region IDocumentVersionSupportGEN Members /// <summary> /// Convert the instance into an object supported by the given version /// </summary> /// <param name="docVersion">Version to convert to</param> /// <returns>Object that supports given version</returns> public object ConvertToSupportedObject(esriArcGISVersion docVersion) { return null; } /// <summary> /// Check if the object is supported at the given version /// </summary> /// <param name="docVersion">Version to check against</param> /// <returns>True if the object is supported</returns> public bool IsSupportedAtVersion(esriArcGISVersion docVersion) { if (docVersion >= esriArcGISVersion.esriArcGISVersion10) return true; else return false; } #endregion #region IXMLSerialize Members /// <summary> /// Deserialize the Raster Function from the datastream provided /// </summary> /// <param name="data">Xml stream to deserialize the function from</param> public void Deserialize(IXMLSerializeData data) { myName = data.GetString(data.Find("Name")); myDescription = data.GetString(data.Find("Description")); myPixeltype = (rstPixelType)(data.GetInteger(data.Find("PixelType"))); } /// <summary> /// Serialize the Raster Function into the stream provided. /// </summary> /// <param name="data">Xml stream to serialize the function into</param> public void Serialize(IXMLSerializeData data) { data.TypeName = "NDVICustomFunction"; data.TypeNamespaceURI = @"http://www.esri.com/schemas/ArcGIS/10.1"; data.AddString("Name", myName); data.AddString("Description", myDescription); data.AddInteger("PixelType", (int)myPixeltype); } #endregion #region IXMLVersionSupport Members /// <summary> /// Returns the namespaces supported by the object /// </summary> public string MinNamespaceSupported { get { return @"http://www.esri.com/schemas/ArcGIS/10.1"; } } #endregion #region COM Registration Function(s) [ComRegisterFunction()] static void Reg(string regKey) { ESRI.ArcGIS.ADF.CATIDs.RasterFunctions.Register(regKey); } [ComUnregisterFunction()] static void Unreg(string regKey) { ESRI.ArcGIS.ADF.CATIDs.RasterFunctions.Unregister(regKey); } #endregion } [Guid("157ACDCC-9F2B-4CC4-BFFD-FEB933F3E788")] [InterfaceTypeAttribute(ComInterfaceType.InterfaceIsIUnknown)] public interface INDVICustomFunctionArguments : IRasterFunctionArguments, IPersistVariant, IDocumentVersionSupportGEN, IXMLSerialize, IXMLVersionSupport { #region INDVICustomFunctionArguments Members [DispId(0x50505001)] object Raster { get; set; } [DispId(0x50505002)] string BandIndices { get; set; } #endregion } [Guid("CB684500-0A15-46C5-B1C1-8062A1629F66")] [ClassInterface(ClassInterfaceType.None)] [ProgId("CustomFunction.NDVICustomFunctionArguments")] [ComVisible(true)] public class NDVICustomFunctionArguments : INDVICustomFunctionArguments { #region Private Members string myName; string myDescription; UID myUID; // UID for the NDVI Custom Function Arguments. IPropertySet myProperties; // Property set to store the properties of the arguments object. #endregion public NDVICustomFunctionArguments() { myName = "NDVI Custom Function Arguments"; myDescription = "Arguments object for the NDVI Custom Function"; // Set default values myProperties = new PropertySetClass(); myProperties.SetProperty("Raster", null); myProperties.SetProperty("BandIndices", "1 2"); // Default value for band indexes: first two bands of image. myUID = new UIDClass(); myUID.Value = "{CB684500-0A15-46C5-B1C1-8062A1629F66}"; } #region NDVICustomFunctionArguments Members /// <summary> /// Raster to apply the raster function to. /// </summary> public object Raster { get { return GetDereferencedValue("Raster"); } set { myProperties.SetProperty("Raster", value); } } /// <summary> /// Indices of the bands to use in the NDVI computation. /// </summary> public string BandIndices { get { return Convert.ToString(GetDereferencedValue("BandIndices")); } set { myProperties.SetProperty("BandIndices", value); } } /// <summary> /// Dereference and return the value of the property whose name is given if necessary. /// </summary> /// <param name="name">Name of the property to check.</param> /// <returns>Dereferenced value of the property corresponding to the name given.</returns> private object GetDereferencedValue(string name) { object value = myProperties.GetProperty(name); if (value != null && value is IRasterFunctionVariable && !(value is IRasterFunctionTemplate)) { IRasterFunctionVariable rFVar = (IRasterFunctionVariable)value; return rFVar.Value; } return value; } #endregion #region IRasterFunctionArguments Members /// <summary> /// A list of files associated with the raster /// </summary> public IStringArray FileList { get { object rasterObject = myProperties.GetProperty("Raster"); IRasterDataset rasterDataset = null; if (rasterObject is IRasterDataset) rasterDataset = (IRasterDataset)rasterObject; else if (rasterObject is IName) rasterDataset = (IRasterDataset)((IName)rasterObject).Open(); if (rasterDataset != null && rasterDataset is IRasterDatasetInfo) { IRasterDatasetInfo rasterDatasetInfo = (IRasterDatasetInfo)rasterDataset; return rasterDatasetInfo.FileList; } else return null; } } /// <summary> /// Get the value associated with the name provided. /// </summary> /// <param name="Name">Name of the property</param> /// <returns>Value of the property name provided</returns> public object GetValue(string Name) { return myProperties.GetProperty(Name); } /// <summary> /// A list of all the names in the property set. /// </summary> public IStringArray Names { get // Generate a list of names in the propertyset. { object names = null, values = null; myProperties.GetAllProperties(out names, out values); IStringArray myNames = new StrArray(); string[] nameArray = (string[])names; for (int i = 0; i < nameArray.GetLength(0); ++i) myNames.Add(nameArray[i]); return myNames; } } /// <summary> /// Set the given property name to the given value /// </summary> /// <param name="Name">Name of the property</param> /// <param name="Value">Value of the property</param> public void PutValue(string Name, object Value) { myProperties.SetProperty(Name, Value); } /// <summary> /// Remove the value of the property name provided /// </summary> /// <param name="Name">Name of the property to be removed</param> public void Remove(string Name) { myProperties.RemoveProperty(Name); } /// <summary> /// Clear the property set of all names and values. /// </summary> public void RemoveAll() { myProperties = null; myProperties = new PropertySetClass(); } /// <summary> /// A list of all the values in the property set /// </summary> public IVariantArray Values { get // Generate a list of values in the propertyset. { object names = null, values = null; myProperties.GetAllProperties(out names, out values); IVariantArray myValues = new VarArray(); object[] valArray = (object[])values; for (int i = 0; i < valArray.GetLength(0); ++i) myValues.Add(valArray[i]); return myValues; } } /// <summary> /// Resolve variables containing field names with the corresponding values. /// </summary> /// <param name="pRow">The row corresponding to the function raster dataset.</param> /// <param name="pPropertySet">Property Set to add the list of the names and the resolved values to.</param> public void Resolve(IRow pRow, IPropertySet pPropertySet) { ResolveRasterVal(pRow); } /// <summary> /// Update the variables containing field names to their updated values. /// </summary> /// <param name="pRow">The row corresponding to the function raster dataset.</param> /// <param name="pPropertySet">Property Set to add the list of the names and the updated values to.</param> /// <param name="pTemplateArguments">The arguements object containing the properties to update if</param> public void Update(IRow pRow, IPropertySet pPropertySet, IRasterFunctionArguments pTemplateArguments) { Resolve(pRow, pPropertySet); } /// <summary> /// Resolve the 'Raster' variable if it contains field names with the corresponding values. /// </summary> /// <param name="pRow">The row corresponding to the function raster dataset.</param> private void ResolveRasterVal(IRow pRow) { try { // Get the Raster property. object myRasterObject = myProperties.GetProperty("Raster"); // Check to see if it is a variable if (myRasterObject is IRasterFunctionVariable) { IRasterFunctionVariable rasterVar = ((IRasterFunctionVariable)myRasterObject); object rasterVal = FindPropertyInRow(rasterVar, pRow); if (rasterVal != null && rasterVal is string) { string datasetPath = (string)rasterVal; rasterVar.Value = OpenRasterDataset(datasetPath); } } } catch (Exception exc) { System.Exception myExc = new System.Exception( "Exception caught in ResolveRasterVal: " + exc.Message, exc); throw myExc; } } /// <summary> /// Check the Name and Alias properties of the given Raster Function Variable to see /// if they contain a field name and get the value of the corresponding field if needed. /// </summary> /// <param name="rasterFunctionVar">The Raster Function Variable to check.</param> /// <param name="pRow">The row corresponding to the function raster dataset.</param> /// <returns></returns> private object FindPropertyInRow(IRasterFunctionVariable rasterFunctionVar, IRow pRow) { string varName = ""; IStringArray varNames = new StrArrayClass(); varName = rasterFunctionVar.Name; // If the name of the variable contains '@Field' if (varName.Contains("@Field.")) varNames.Add(varName); // Add it to the list of names. // Check the aliases of the variable for (int i = 0; i < rasterFunctionVar.Aliases.Count; ++i) { // Check the list of aliases for the '@Field' string varName = rasterFunctionVar.Aliases.get_Element(i); if (varName.Contains("@Field.")) varNames.Add(varName); // and add any that are found to the list of names. } // Use the list of names and find the value by looking up the appropriate field. for (int i = 0; i < varNames.Count; ++i) { // Get the variable name containing the field string varName = varNames.get_Element(i); // Replace the '@Field' with nothing to get just the name of the field. string fieldName = varName.Replace("@Field.", ""); IFields rowFields = pRow.Fields; // Look up the index of the field name in the row. int fieldIndex = rowFields.FindField(fieldName); // If it is a valid index and the field type is string, return the value. if (fieldIndex != -1 && ((rowFields.get_Field(fieldIndex)).Type == esriFieldType.esriFieldTypeString)) return pRow.get_Value(fieldIndex); } // If no value has been returned yet, return null. return null; } /// <summary> /// Open the Raster Dataset given the path to the file. /// </summary> /// <param name="path">Path to the Raster Dataset file.</param> /// <returns>The opened Raster Dataset.</returns> private IRasterDataset OpenRasterDataset(string path) { try { string inputWorkspace = System.IO.Path.GetDirectoryName(path); string inputDatasetName = System.IO.Path.GetFileName(path); Type factoryType = Type.GetTypeFromProgID("esriDataSourcesRaster.RasterWorkspaceFactory"); IWorkspaceFactory workspaceFactory = (IWorkspaceFactory)Activator.CreateInstance(factoryType); IWorkspace workspace = workspaceFactory.OpenFromFile(inputWorkspace, 0); IRasterWorkspace rasterWorkspace = (IRasterWorkspace)workspace; IRasterDataset myRasterDataset = rasterWorkspace.OpenRasterDataset(inputDatasetName); return myRasterDataset; } catch (Exception exc) { throw exc; } } #endregion #region IPersistVariant Members /// <summary> /// UID to identify the object. /// </summary> public UID ID { get { return myUID; } } /// <summary> /// Load the properties of the argument object from the stream provided /// </summary> /// <param name="Stream">Stream that contains the serialized form of the argument object</param> public void Load(IVariantStream Stream) { if (Stream is IDocumentVersion) { IDocumentVersion docVersion = (IDocumentVersion)Stream; if (docVersion.DocumentVersion >= esriArcGISVersion.esriArcGISVersion10) { esriArcGISVersion streamVersion = (esriArcGISVersion)((int)Stream.Read()); if (streamVersion >= esriArcGISVersion.esriArcGISVersion10) { myName = (string)Stream.Read(); myDescription = (string)Stream.Read(); myProperties = (IPropertySet)Stream.Read(); } } } } /// <summary> /// Save the properties of the argument object to the stream provided /// </summary> /// <param name="Stream">Stream to which to serialize the argument object into</param> public void Save(IVariantStream Stream) { if (Stream is IDocumentVersion) { IDocumentVersion docVersion = (IDocumentVersion)Stream; if (docVersion.DocumentVersion >= esriArcGISVersion.esriArcGISVersion10) { object names = null, values = null; myProperties.GetAllProperties(out names, out values); string[] nameArray = (string[])names; object[] valArray = (object[])values; for (int i = 0; i < nameArray.GetLength(0); ++i) { if (valArray[i] is IDataset) { IName myDatasetName = ((IDataset)valArray[i]).FullName; myProperties.SetProperty(nameArray[i], myDatasetName); } } Stream.Write((int)esriArcGISVersion.esriArcGISVersion10); Stream.Write(myName); Stream.Write(myDescription); Stream.Write(myProperties); } } } #endregion #region IDocumentVersionSupportGEN Members /// <summary> /// Convert the instance into an object supported by the given version /// </summary> /// <param name="docVersion">Version to convert to</param> /// <returns>Object that supports given version</returns> public object ConvertToSupportedObject(esriArcGISVersion docVersion) { return null; } /// <summary> /// Check if the object is supported at the given version /// </summary> /// <param name="docVersion">Version to check against</param> /// <returns>True if the object is supported</returns> public bool IsSupportedAtVersion(esriArcGISVersion docVersion) { if (docVersion >= esriArcGISVersion.esriArcGISVersion10) return true; else return false; } #endregion #region IXMLSerialize Members /// <summary> /// Deserialize the argument object from the datastream provided /// </summary> /// <param name="data">Xml stream to deserialize the argument object from</param> public void Deserialize(IXMLSerializeData data) { int nameIndex = data.Find("Names"); int valIndex = data.Find("Values"); if (nameIndex != -1 && valIndex != -1) { IStringArray myNames = (IStringArray)data.GetVariant(nameIndex); IVariantArray myValues = (IVariantArray)data.GetVariant(valIndex); for (int i = 0; i < myNames.Count; ++i) { myProperties.SetProperty(myNames.get_Element(i), myValues.get_Element(i)); } } } /// <summary> /// Serialize the argument object into the stream provided. /// </summary> /// <param name="data">Xml stream to serialize the argument object into</param> public void Serialize(IXMLSerializeData data) { #region Prepare PropertySet object names = null, values = null; myProperties.GetAllProperties(out names, out values); IStringArray myNames = new StrArray(); string[] nameArray = (string[])names; IVariantArray myValues = new VarArray(); object[] valArray = (object[])values; for (int i = 0; i < nameArray.GetLength(0); ++i) { myNames.Add(nameArray[i]); if (valArray[i] is IDataset) { IName myDatasetName = ((IDataset)valArray[i]).FullName; myValues.Add(myDatasetName); } else myValues.Add(valArray[i]); } #endregion data.TypeName = "NDVICustomFunctionArguments"; data.TypeNamespaceURI = @"http://www.esri.com/schemas/ArcGIS/10.1"; data.AddObject("Names", myNames); data.AddObject("Values", myValues); } #endregion #region IXMLVersionSupport Members /// <summary> /// Returns the namespaces supported by the object /// </summary> public string MinNamespaceSupported { get { return @"http://www.esri.com/schemas/ArcGIS/10.1"; } } #endregion } }
[Visual Basic .NET]
NDVICustomFunction.vb
Imports System.Collections.Generic Imports System.Linq Imports System.Text Imports System.Runtime.InteropServices Imports ESRI.ArcGIS.DataSourcesRaster Imports ESRI.ArcGIS.esriSystem Imports ESRI.ArcGIS.Geodatabase Imports ESRI.ArcGIS.Geometry Imports ESRI.ArcGIS.ADF.CATIDs Namespace CustomFunction <Guid("652642F3-9106-4EB3-9262-A4C39E03BC56")> _ <ClassInterface(ClassInterfaceType.None)> _ <ProgId("CustomFunction.NDVICustomFunction")> _ <ComVisible(True)> _ Public Class NDVICustomFunction Implements IRasterFunction Implements IPersistVariant Implements IDocumentVersionSupportGEN Implements IXMLSerialize Implements IXMLVersionSupport #Region "Private Members" Private myUID As UID ' UID for the Function. Private myRasterInfo As IRasterInfo ' Raster Info for the Function Private myPixeltype As rstPixelType ' Pixel Type of the Function. Private myName As String ' Name of the Function. Private myDescription As String ' Description of the Function. Private myValidFlag As Boolean ' Flag to specify validity of the Function. Private myFunctionHelper As IRasterFunctionHelper ' Raster Function Helper object. Private myInpPixeltype As rstPixelType Private myInpNumBands As Integer Private myBandIndices As String() #End Region Public Sub New() myName = "NDVI Custom Function" myPixeltype = rstPixelType.PT_FLOAT myDescription = "Custom NDVI Function which calculates the NDVI without any scaling." myValidFlag = True myFunctionHelper = New RasterFunctionHelperClass() myInpPixeltype = myPixeltype myInpNumBands = 0 myBandIndices = Nothing myUID = New UIDClass() myUID.Value = "{652642F3-9106-4EB3-9262-A4C39E03BC56}" End Sub #Region "IRasterFunction Members" ''' <summary> ''' Name of the Raster Function. ''' </summary> Public Property Name() As String Implements IRasterFunction.Name Get Return myName End Get Set myName = value End Set End Property ''' <summary> ''' Pixel Type of the Raster Function ''' </summary> Public Property PixelType() As rstPixelType Implements IRasterFunction.PixelType Get Return myPixeltype End Get Set myPixeltype = value End Set End Property ''' <summary> ''' Output Raster Info for the Raster Function ''' </summary> Public ReadOnly Property RasterInfo() As IRasterInfo Implements IRasterFunction.RasterInfo Get Return myRasterInfo End Get End Property ''' <summary> ''' Description of the Raster Function ''' </summary> Public Property Description() As String Implements IRasterFunction.Description Get Return myDescription End Get Set myDescription = value End Set End Property ''' <summary> ''' Initialize the Raster function using the argument object. This is one of the two ''' main functions to implement for a custom Raster function. The raster object is ''' dereferenced if required and given to the RasterFuntionHelper object to bind. ''' </summary> ''' <param name="pArguments">Arguments object used for initialization</param> Public Sub Bind(pArguments As Object) Implements IRasterFunction.Bind Try ' Check if the Arguments object is of the correct type. Dim customFunctionArgs As INDVICustomFunctionArguments = Nothing If TypeOf pArguments Is INDVICustomFunctionArguments Then customFunctionArgs = DirectCast(pArguments, INDVICustomFunctionArguments) Dim inputRaster As Object = customFunctionArgs.Raster If TypeOf customFunctionArgs.Raster Is IRasterFunctionVariable Then Dim rasterFunctionVariable As IRasterFunctionVariable = DirectCast(customFunctionArgs.Raster, IRasterFunctionVariable) inputRaster = rasterFunctionVariable.Value End If ' Call the Bind method of the Raster Function Helper object. myFunctionHelper.Bind(inputRaster) Else ' Throw an error if incorrect arguments object is passed. Throw New System.Exception("Incorrect arguments object. Expected: INDVICustomFunctionArguments") End If ' Check to see if Band Indices exist. If customFunctionArgs.BandIndices IsNot Nothing AndAlso customFunctionArgs.BandIndices <> "" Then myBandIndices = customFunctionArgs.BandIndices.Split(" "C) Else ' If not, throw an error. Throw New System.Exception("Incorrect parameters specified. Expected: Valid band indices.") End If ' Create a new RasterInfo object and initialize from the FunctionHelper object. ' A new RasterInfo Object is created because assigning myFunctionHelper.RasterInfo ' directly creates a reference. myRasterInfo = New RasterInfoClass() myRasterInfo.BandCount = myFunctionHelper.RasterInfo.BandCount myRasterInfo.BlockHeight = myFunctionHelper.RasterInfo.BlockHeight myRasterInfo.BlockWidth = myFunctionHelper.RasterInfo.BlockWidth myRasterInfo.CellSize = myFunctionHelper.RasterInfo.CellSize myRasterInfo.Extent = myFunctionHelper.RasterInfo.Extent myRasterInfo.FirstPyramidLevel = myFunctionHelper.RasterInfo.FirstPyramidLevel myRasterInfo.Format = myFunctionHelper.RasterInfo.Format myRasterInfo.GeodataXform = myFunctionHelper.RasterInfo.GeodataXform myRasterInfo.MaximumPyramidLevel = myFunctionHelper.RasterInfo.MaximumPyramidLevel myRasterInfo.NativeExtent = myFunctionHelper.RasterInfo.NativeExtent myRasterInfo.NativeSpatialReference = myFunctionHelper.RasterInfo.NativeSpatialReference myRasterInfo.NoData = myFunctionHelper.RasterInfo.NoData myRasterInfo.Origin = myFunctionHelper.RasterInfo.Origin myRasterInfo.PixelType = rstPixelType.PT_FLOAT ' Output pixel type should be output of the NDVI. myRasterInfo.Resampling = myFunctionHelper.RasterInfo.Resampling myRasterInfo.SupportBandSelection = myFunctionHelper.RasterInfo.SupportBandSelection ' Store required input properties. myInpPixeltype = myRasterInfo.PixelType myInpNumBands = myRasterInfo.BandCount ' Set output pixel properties. myRasterInfo.BandCount = 1 myPixeltype = rstPixelType.PT_FLOAT ' Perform validation to see if the indices passed are valid. If myInpNumBands < 2 OrElse myBandIndices.Length < 2 Then ' If not, throw an error. Throw New System.Exception("Incorrect parameters specified. Expected: Valid band indices.") End If For i As Integer = 0 To myBandIndices.Length - 1 Dim currBand As Integer = Convert.ToInt16(myBandIndices(i)) - 1 If (currBand < 0) OrElse (currBand > myInpNumBands) Then ' If not, throw an error. Throw New System.Exception("Incorrect parameters specified. Expected: Valid band indices.") End If Next Catch exc As Exception Dim myExc As New System.Exception("Exception caught in Bind method: " & exc.Message, exc) Throw myExc End Try End Sub ''' <summary> ''' Read pixels from the input Raster and fill the PixelBlock provided with processed pixels. ''' </summary> ''' <param name="pTlc">Point to start the reading from in the Raster</param> ''' <param name="pRaster">Reference Raster for the PixelBlock</param> ''' <param name="pPixelBlock">PixelBlock to be filled in</param> Public Sub Read(pTlc As IPnt, pRaster As IRaster, pPixelBlock As IPixelBlock) Implements IRasterFunction.Read Try ' Create a new pixel block to read the input data into. ' This is done because the pPixelBlock represents the output ' pixel block which is different from the input. Dim pBHeight As Integer = pPixelBlock.Height Dim pBWidth As Integer = pPixelBlock.Width Dim pBlockSize As IPnt = New PntClass() pBlockSize.X = pBWidth pBlockSize.Y = pBHeight Dim inputPixelBlock As IPixelBlock = New PixelBlockClass() DirectCast(inputPixelBlock, IPixelBlock4).Create(myInpNumBands, pBWidth, pBHeight, myInpPixeltype) ' Call Read method of the Raster Function Helper object to read the input pixels into ' the inputPixelBlock. myFunctionHelper.Read(pTlc, Nothing, pRaster, inputPixelBlock) Dim inpPixelValues1 As System.Array Dim inpPixelValues2 As System.Array Dim outPixelValues As System.Array Dim index1 As Integer = Convert.ToInt16(myBandIndices(0)) - 1 ' Get NIR band index specified by user. Dim index2 As Integer = Convert.ToInt16(myBandIndices(1)) - 1 ' Get Red Band index specified by user. ' Get the correct bands from the input. Dim ipPixelBlock As IPixelBlock3 = DirectCast(inputPixelBlock, IPixelBlock3) inpPixelValues1 = DirectCast(ipPixelBlock.PixelData(index1), System.Array) inpPixelValues2 = DirectCast(ipPixelBlock.PixelData(index2), System.Array) outPixelValues = DirectCast(DirectCast(pPixelBlock, IPixelBlock3).PixelData(0), System.Array) Dim i As Integer = 0 Dim k As Integer = 0 Dim pixelValue As Double = 0.0 Dim nirValue As Double = 0.0 Dim irValue As Double = 0.0 ' Perform the NDVI computation and store the result in the output pixel block. For i = 0 To pBHeight - 1 For k = 0 To pBWidth - 1 nirValue = Convert.ToDouble(inpPixelValues1.GetValue(k, i)) irValue = Convert.ToDouble(inpPixelValues2.GetValue(k, i)) ' Check if input is not NoData. If (Convert.ToByte(ipPixelBlock.GetNoDataMaskVal(index1, k, i)) = 1) AndAlso Convert.ToByte(ipPixelBlock.GetNoDataMaskVal(index2, k, i)) = 1 Then ' NDVI[k] = (NIR[k]-Red[k])/(NIR[k]+Red[k]); If (nirValue + irValue) <> 0 Then ' Check for division by 0. pixelValue = (nirValue - irValue) / (nirValue + irValue) If pixelValue < -1.0 OrElse pixelValue > 1.0 Then pixelValue = 0.0 End If Else pixelValue = 0.0 End If End If outPixelValues.SetValue(CSng(pixelValue), k, i) Next Next ' Set the output pixel values on the output pixel block. DirectCast(pPixelBlock, IPixelBlock3).PixelData(0) = outPixelValues ' Copy over the NoData mask from the input and set it on the output. DirectCast(pPixelBlock, IPixelBlock3).NoDataMask(0) = DirectCast(inputPixelBlock, IPixelBlock3).NoDataMask(0) Catch exc As Exception Dim myExc As New System.Exception("Exception caught in Read method: " & exc.Message, exc) Throw myExc End Try End Sub ''' <summary> ''' Update the Raster Function ''' </summary> Public Sub Update() Implements IRasterFunction.Update Try Catch exc As Exception Dim myExc As New System.Exception("Exception caught in Update method: ", exc) Throw myExc End Try End Sub ''' <summary> ''' Property that specifies whether the Raster Function is still valid. ''' </summary> Public ReadOnly Property Valid() As Boolean Implements IRasterFunction.Valid Get Return myValidFlag End Get End Property #End Region #Region "IPersistVariant Members" ''' <summary> ''' UID to identify the function. ''' </summary> Public ReadOnly Property ID() As UID Implements IPersistVariant.ID Get Return myUID End Get End Property ''' <summary> ''' Load the properties of the function from the stream provided ''' </summary> ''' <param name="Stream">Stream that contains the serialized form of the function</param> Public Sub Load(Stream As IVariantStream) Implements IPersistVariant.Load If TypeOf Stream Is IDocumentVersion Then Dim docVersion As IDocumentVersion = DirectCast(Stream, IDocumentVersion) If docVersion.DocumentVersion >= esriArcGISVersion.esriArcGISVersion10 Then Dim streamVersion As esriArcGISVersion = CType(CInt(Stream.Read()), esriArcGISVersion) If streamVersion >= esriArcGISVersion.esriArcGISVersion10 Then myName = DirectCast(Stream.Read(), String) myDescription = DirectCast(Stream.Read(), String) myPixeltype = CType(CInt(Stream.Read()), rstPixelType) End If End If End If End Sub ''' <summary> ''' Save the properties of the function to the stream provided ''' </summary> ''' <param name="Stream">Stream to which to serialize the function into</param> Public Sub Save(Stream As IVariantStream) Implements IPersistVariant.Save If TypeOf Stream Is IDocumentVersion Then Dim docVersion As IDocumentVersion = DirectCast(Stream, IDocumentVersion) If docVersion.DocumentVersion >= esriArcGISVersion.esriArcGISVersion10 Then Stream.Write(CInt(esriArcGISVersion.esriArcGISVersion10)) Stream.Write(myName) Stream.Write(myDescription) Stream.Write(CInt(myPixeltype)) End If End If End Sub #End Region #Region "IDocumentVersionSupportGEN Members" ''' <summary> ''' Convert the instance into an object supported by the given version ''' </summary> ''' <param name="docVersion">Version to convert to</param> ''' <returns>Object that supports given version</returns> Public Function ConvertToSupportedObject(docVersion As esriArcGISVersion) As Object Implements IDocumentVersionSupportGEN.ConvertToSupportedObject Return Nothing End Function ''' <summary> ''' Check if the object is supported at the given version ''' </summary> ''' <param name="docVersion">Version to check against</param> ''' <returns>True if the object is supported</returns> Public Function IsSupportedAtVersion(docVersion As esriArcGISVersion) As Boolean Implements IDocumentVersionSupportGEN.IsSupportedAtVersion If docVersion >= esriArcGISVersion.esriArcGISVersion10 Then Return True Else Return False End If End Function #End Region #Region "IXMLSerialize Members" ''' <summary> ''' Deserialize the Raster Function from the datastream provided ''' </summary> ''' <param name="data">Xml stream to deserialize the function from</param> Public Sub Deserialize(data As IXMLSerializeData) Implements IXMLSerialize.Deserialize myName = data.GetString(data.Find("Name")) myDescription = data.GetString(data.Find("Description")) myPixeltype = CType(data.GetInteger(data.Find("PixelType")), rstPixelType) End Sub ''' <summary> ''' Serialize the Raster Function into the stream provided. ''' </summary> ''' <param name="data">Xml stream to serialize the function into</param> Public Sub Serialize(data As IXMLSerializeData) Implements IXMLSerialize.Serialize data.TypeName = "NDVICustomFunction" data.TypeNamespaceURI = "http://www.esri.com/schemas/ArcGIS/10.1" data.AddString("Name", myName) data.AddString("Description", myDescription) data.AddInteger("PixelType", CInt(myPixeltype)) End Sub #End Region #Region "IXMLVersionSupport Members" ''' <summary> ''' Returns the namespaces supported by the object ''' </summary> Public ReadOnly Property MinNamespaceSupported() As String Implements IXMLVersionSupport.MinNamespaceSupported Get Return "http://www.esri.com/schemas/ArcGIS/10.1" End Get End Property #End Region #Region "COM Registration Function(s)" <ComRegisterFunction> _ Private Shared Sub Reg(regKey As String) ESRI.ArcGIS.ADF.CATIDs.RasterFunctions.Register(regKey) End Sub <ComUnregisterFunction> _ Private Shared Sub Unreg(regKey As String) ESRI.ArcGIS.ADF.CATIDs.RasterFunctions.Unregister(regKey) End Sub #End Region End Class <Guid("157ACDCC-9F2B-4CC4-BFFD-FEB933F3E788")> _ <InterfaceTypeAttribute(ComInterfaceType.InterfaceIsIUnknown)> _ Public Interface INDVICustomFunctionArguments Inherits IRasterFunctionArguments Inherits IPersistVariant Inherits IDocumentVersionSupportGEN Inherits IXMLSerialize Inherits IXMLVersionSupport #Region "INDVICustomFunctionArguments Members" <DispId(&H50505001)> _ Property Raster() As Object <DispId(&H50505002)> _ Property BandIndices() As String #End Region End Interface <Guid("CB684500-0A15-46C5-B1C1-8062A1629F66")> _ <ClassInterface(ClassInterfaceType.None)> _ <ProgId("CustomFunction.NDVICustomFunctionArguments")> _ <ComVisible(True)> _ Public Class NDVICustomFunctionArguments Implements INDVICustomFunctionArguments #Region "Private Members" Private myName As String Private myDescription As String Private myUID As UID ' UID for the NDVI Custom Function Arguments. Private myProperties As IPropertySet ' Property set to store the properties of the arguments object. #End Region Public Sub New() myName = "NDVI Custom Function Arguments" myDescription = "Arguments object for the NDVI Custom Function" ' Set default values myProperties = New PropertySetClass() myProperties.SetProperty("Raster", Nothing) myProperties.SetProperty("BandIndices", "1 2") ' Default value for band indexes: first two bands of image. myUID = New UIDClass() myUID.Value = "{CB684500-0A15-46C5-B1C1-8062A1629F66}" End Sub #Region "NDVICustomFunctionArguments Members" ''' <summary> ''' Raster to apply the raster function to. ''' </summary> Public Property Raster() As Object Implements INDVICustomFunctionArguments.Raster Get Return GetDereferencedValue("Raster") End Get Set myProperties.SetProperty("Raster", value) End Set End Property ''' <summary> ''' Indices of the bands to use in the NDVI computation. ''' </summary> Public Property BandIndices() As String Implements INDVICustomFunctionArguments.BandIndices Get Return Convert.ToString(GetDereferencedValue("BandIndices")) End Get Set myProperties.SetProperty("BandIndices", value) End Set End Property ''' <summary> ''' Dereference and return the value of the property whose name is given if necessary. ''' </summary> ''' <param name="name">Name of the property to check.</param> ''' <returns>Dereferenced value of the property corresponding to the name given.</returns> Private Function GetDereferencedValue(name As String) As Object Dim value As Object = myProperties.GetProperty(name) If value IsNot Nothing AndAlso TypeOf value Is IRasterFunctionVariable AndAlso Not (TypeOf value Is IRasterFunctionTemplate) Then Dim rFVar As IRasterFunctionVariable = DirectCast(value, IRasterFunctionVariable) Return rFVar.Value End If Return value End Function #End Region #Region "IRasterFunctionArguments Members" ''' <summary> ''' A list of files associated with the raster ''' </summary> Public ReadOnly Property FileList() As IStringArray Implements IRasterFunctionArguments.FileList Get Dim rasterObject As Object = myProperties.GetProperty("Raster") Dim rasterDataset As IRasterDataset = Nothing If TypeOf rasterObject Is IRasterDataset Then rasterDataset = DirectCast(rasterObject, IRasterDataset) ElseIf TypeOf rasterObject Is IName Then rasterDataset = DirectCast(DirectCast(rasterObject, IName).Open(), IRasterDataset) End If If rasterDataset IsNot Nothing AndAlso TypeOf rasterDataset Is IRasterDatasetInfo Then Dim rasterDatasetInfo As IRasterDatasetInfo = DirectCast(rasterDataset, IRasterDatasetInfo) Return rasterDatasetInfo.FileList Else Return Nothing End If End Get End Property ''' <summary> ''' Get the value associated with the name provided. ''' </summary> ''' <param name="Name">Name of the property</param> ''' <returns>Value of the property name provided</returns> Public Function GetValue(Name As String) As Object Implements IRasterFunctionArguments.GetValue Return myProperties.GetProperty(Name) End Function ''' <summary> ''' A list of all the names in the property set. ''' </summary> Public ReadOnly Property Names() As IStringArray Implements IRasterFunctionArguments.Names Get ' Generate a list of names in the propertyset. Dim names__1 As Object = Nothing, values As Object = Nothing myProperties.GetAllProperties(names__1, values) Dim myNames As IStringArray = New StrArray() Dim nameArray As String() = DirectCast(names__1, String()) For i As Integer = 0 To nameArray.GetLength(0) - 1 myNames.Add(nameArray(i)) Next Return myNames End Get End Property ''' <summary> ''' Set the given property name to the given value ''' </summary> ''' <param name="Name">Name of the property</param> ''' <param name="Value">Value of the property</param> Public Sub PutValue(Name As String, Value As Object) Implements IRasterFunctionArguments.PutValue myProperties.SetProperty(Name, Value) End Sub ''' <summary> ''' Remove the value of the property name provided ''' </summary> ''' <param name="Name">Name of the property to be removed</param> Public Sub Remove(Name As String) Implements IRasterFunctionArguments.Remove myProperties.RemoveProperty(Name) End Sub ''' <summary> ''' Clear the property set of all names and values. ''' </summary> Public Sub RemoveAll() Implements IRasterFunctionArguments.RemoveAll myProperties = Nothing myProperties = New PropertySetClass() End Sub ''' <summary> ''' A list of all the values in the property set ''' </summary> Public ReadOnly Property Values() As IVariantArray Implements IRasterFunctionArguments.Values Get ' Generate a list of values in the propertyset. Dim names As Object = Nothing, values__1 As Object = Nothing myProperties.GetAllProperties(names, values__1) Dim myValues As IVariantArray = New VarArray() Dim valArray As Object() = DirectCast(values__1, Object()) For i As Integer = 0 To valArray.GetLength(0) - 1 myValues.Add(valArray(i)) Next Return myValues End Get End Property ''' <summary> ''' Resolve variables containing field names with the corresponding values. ''' </summary> ''' <param name="pRow">The row corresponding to the function raster dataset.</param> ''' <param name="pPropertySet">Property Set to add the list of the names and the resolved values to.</param> Public Sub Resolve(pRow As IRow, pPropertySet As IPropertySet) Implements IRasterFunctionArguments.Resolve ResolveRasterVal(pRow) End Sub ''' <summary> ''' Update the variables containing field names to their updated values. ''' </summary> ''' <param name="pRow">The row corresponding to the function raster dataset.</param> ''' <param name="pPropertySet">Property Set to add the list of the names and the updated values to.</param> ''' <param name="pTemplateArguments">The arguements object containing the properties to update if</param> Public Sub Update(pRow As IRow, pPropertySet As IPropertySet, pTemplateArguments As IRasterFunctionArguments) Implements IRasterFunctionArguments.Update Resolve(pRow, pPropertySet) End Sub ''' <summary> ''' Resolve the 'Raster' variable if it contains field names with the corresponding values. ''' </summary> ''' <param name="pRow">The row corresponding to the function raster dataset.</param> Private Sub ResolveRasterVal(pRow As IRow) Try ' Get the Raster property. Dim myRasterObject As Object = myProperties.GetProperty("Raster") ' Check to see if it is a variable If TypeOf myRasterObject Is IRasterFunctionVariable Then Dim rasterVar As IRasterFunctionVariable = DirectCast(myRasterObject, IRasterFunctionVariable) Dim rasterVal As Object = FindPropertyInRow(rasterVar, pRow) If rasterVal IsNot Nothing AndAlso TypeOf rasterVal Is String Then Dim datasetPath As String = DirectCast(rasterVal, String) rasterVar.Value = OpenRasterDataset(datasetPath) End If End If Catch exc As Exception Dim myExc As New System.Exception("Exception caught in ResolveRasterVal: " & exc.Message, exc) Throw myExc End Try End Sub ''' <summary> ''' Check the Name and Alias properties of the given Raster Function Variable to see ''' if they contain a field name and get the value of the corresponding field if needed. ''' </summary> ''' <param name="rasterFunctionVar">The Raster Function Variable to check.</param> ''' <param name="pRow">The row corresponding to the function raster dataset.</param> ''' <returns></returns> Private Function FindPropertyInRow(rasterFunctionVar As IRasterFunctionVariable, pRow As IRow) As Object Dim varName As String = "" Dim varNames As IStringArray = New StrArrayClass() varName = rasterFunctionVar.Name ' If the name of the variable contains '@Field' If varName.Contains("@Field.") Then varNames.Add(varName) End If ' Add it to the list of names. ' Check the aliases of the variable For i As Integer = 0 To rasterFunctionVar.Aliases.Count - 1 ' Check the list of aliases for the '@Field' string varName = rasterFunctionVar.Aliases.Element(i) If varName.Contains("@Field.") Then varNames.Add(varName) ' and add any that are found to the list of names. End If Next ' Use the list of names and find the value by looking up the appropriate field. For i As Integer = 0 To varNames.Count - 1 ' Get the variable name containing the field string varName = varNames.Element(i) ' Replace the '@Field' with nothing to get just the name of the field. Dim fieldName As String = varName.Replace("@Field.", "") Dim rowFields As IFields = pRow.Fields ' Look up the index of the field name in the row. Dim fieldIndex As Integer = rowFields.FindField(fieldName) ' If it is a valid index and the field type is string, return the value. If fieldIndex <> -1 AndAlso ((rowFields.Field(fieldIndex)).Type = esriFieldType.esriFieldTypeString) Then Return pRow.Value(fieldIndex) End If Next ' If no value has been returned yet, return null. Return Nothing End Function ''' <summary> ''' Open the Raster Dataset given the path to the file. ''' </summary> ''' <param name="path">Path to the Raster Dataset file.</param> ''' <returns>The opened Raster Dataset.</returns> Private Function OpenRasterDataset(path As String) As IRasterDataset Try Dim inputWorkspace As String = System.IO.Path.GetDirectoryName(path) Dim inputDatasetName As String = System.IO.Path.GetFileName(path) Dim factoryType As Type = Type.GetTypeFromProgID("esriDataSourcesRaster.RasterWorkspaceFactory") Dim workspaceFactory As IWorkspaceFactory = DirectCast(Activator.CreateInstance(factoryType), IWorkspaceFactory) Dim workspace As IWorkspace = workspaceFactory.OpenFromFile(inputWorkspace, 0) Dim rasterWorkspace As IRasterWorkspace = DirectCast(workspace, IRasterWorkspace) Dim myRasterDataset As IRasterDataset = rasterWorkspace.OpenRasterDataset(inputDatasetName) Return myRasterDataset Catch exc As Exception Throw exc End Try End Function #End Region #Region "IPersistVariant Members" ''' <summary> ''' UID to identify the object. ''' </summary> Public ReadOnly Property ID() As UID Implements IPersistVariant.ID Get Return myUID End Get End Property ''' <summary> ''' Load the properties of the argument object from the stream provided ''' </summary> ''' <param name="Stream">Stream that contains the serialized form of the argument object</param> Public Sub Load(Stream As IVariantStream) Implements IPersistVariant.Load If TypeOf Stream Is IDocumentVersion Then Dim docVersion As IDocumentVersion = DirectCast(Stream, IDocumentVersion) If docVersion.DocumentVersion >= esriArcGISVersion.esriArcGISVersion10 Then Dim streamVersion As esriArcGISVersion = CType(CInt(Stream.Read()), esriArcGISVersion) If streamVersion >= esriArcGISVersion.esriArcGISVersion10 Then myName = DirectCast(Stream.Read(), String) myDescription = DirectCast(Stream.Read(), String) myProperties = DirectCast(Stream.Read(), IPropertySet) End If End If End If End Sub ''' <summary> ''' Save the properties of the argument object to the stream provided ''' </summary> ''' <param name="Stream">Stream to which to serialize the argument object into</param> Public Sub Save(Stream As IVariantStream) Implements IPersistVariant.Save If TypeOf Stream Is IDocumentVersion Then Dim docVersion As IDocumentVersion = DirectCast(Stream, IDocumentVersion) If docVersion.DocumentVersion >= esriArcGISVersion.esriArcGISVersion10 Then Dim names As Object = Nothing, values As Object = Nothing myProperties.GetAllProperties(names, values) Dim nameArray As String() = DirectCast(names, String()) Dim valArray As Object() = DirectCast(values, Object()) For i As Integer = 0 To nameArray.GetLength(0) - 1 If TypeOf valArray(i) Is IDataset Then Dim myDatasetName As IName = DirectCast(valArray(i), IDataset).FullName myProperties.SetProperty(nameArray(i), myDatasetName) End If Next Stream.Write(CInt(esriArcGISVersion.esriArcGISVersion10)) Stream.Write(myName) Stream.Write(myDescription) Stream.Write(myProperties) End If End If End Sub #End Region #Region "IDocumentVersionSupportGEN Members" ''' <summary> ''' Convert the instance into an object supported by the given version ''' </summary> ''' <param name="docVersion">Version to convert to</param> ''' <returns>Object that supports given version</returns> Public Function ConvertToSupportedObject(docVersion As esriArcGISVersion) As Object Implements IDocumentVersionSupportGEN.ConvertToSupportedObject Return Nothing End Function ''' <summary> ''' Check if the object is supported at the given version ''' </summary> ''' <param name="docVersion">Version to check against</param> ''' <returns>True if the object is supported</returns> Public Function IsSupportedAtVersion(docVersion As esriArcGISVersion) As Boolean Implements IDocumentVersionSupportGEN.IsSupportedAtVersion If docVersion >= esriArcGISVersion.esriArcGISVersion10 Then Return True Else Return False End If End Function #End Region #Region "IXMLSerialize Members" ''' <summary> ''' Deserialize the argument object from the datastream provided ''' </summary> ''' <param name="data">Xml stream to deserialize the argument object from</param> Public Sub Deserialize(data As IXMLSerializeData) Implements IXMLSerialize.Deserialize Dim nameIndex As Integer = data.Find("Names") Dim valIndex As Integer = data.Find("Values") If nameIndex <> -1 AndAlso valIndex <> -1 Then Dim myNames As IStringArray = DirectCast(data.GetVariant(nameIndex), IStringArray) Dim myValues As IVariantArray = DirectCast(data.GetVariant(valIndex), IVariantArray) For i As Integer = 0 To myNames.Count - 1 myProperties.SetProperty(myNames.Element(i), myValues.Element(i)) Next End If End Sub ''' <summary> ''' Serialize the argument object into the stream provided. ''' </summary> ''' <param name="data">Xml stream to serialize the argument object into</param> Public Sub Serialize(data As IXMLSerializeData) Implements IXMLSerialize.Serialize '#Region "Prepare PropertySet" Dim names As Object = Nothing, values As Object = Nothing myProperties.GetAllProperties(names, values) Dim myNames As IStringArray = New StrArray() Dim nameArray As String() = DirectCast(names, String()) Dim myValues As IVariantArray = New VarArray() Dim valArray As Object() = DirectCast(values, Object()) For i As Integer = 0 To nameArray.GetLength(0) - 1 myNames.Add(nameArray(i)) If TypeOf valArray(i) Is IDataset Then Dim myDatasetName As IName = DirectCast(valArray(i), IDataset).FullName myValues.Add(myDatasetName) Else myValues.Add(valArray(i)) End If Next '#End Region data.TypeName = "NDVICustomFunctionArguments" data.TypeNamespaceURI = "http://www.esri.com/schemas/ArcGIS/10.1" data.AddObject("Names", myNames) data.AddObject("Values", myValues) End Sub #End Region #Region "IXMLVersionSupport Members" ''' <summary> ''' Returns the namespaces supported by the object ''' </summary> Public ReadOnly Property MinNamespaceSupported() As String Implements IXMLVersionSupport.MinNamespaceSupported Get Return "http://www.esri.com/schemas/ArcGIS/10.1" End Get End Property #End Region End Class End Namespace