ArcObjects Library Reference  

NDVICustomFunction

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