Using custom geoprocessing function tools in ModelBuilder


Summary
To use custom geoprocessing function tools in the ArcGIS ModelBuilder application, the tool's output parameter description must be updated. By updating the description, subsequent processes in ModelBuilder can distinguish changes to the data before the model is executed. This topic describes how to update an output data description by defining schema for the tool's output parameter.

In this topic


About using custom geoprocessing function tools in ModelBuilder

A geoprocessing model chains together a sequence of geoprocessing tools to preserve a set of tasks or to define a complex geographic information system (GIS) workflow. ModelBuilder allows you to build geoprocessing models by using the output of one tool as the input to another tool and chaining them together. The model you create is added to ArcToolbox as a model tool. You can execute this tool using its dialog box or the command line window. To chain together custom geoprocessing tools in ModelBuilder, the custom tool must update its output parameter description.
 
The following example shows a model containing the Add Field and Calculate Field tools:
 
 
In Add Field, the output data variable, Parks (2), is updated to contain the new field, TrackingID. Because the output is updated, the Calculate Field dialog box lists TrackingID under Field Name. If the output data description is not updated, the TrackingID field name is not listed in the Calculate Field tool in ModelBuilder. Updating the output parameter description allows ModelBuilder to recognize the structure (schema) of the output data before the tool is executed.

Using schema for output description

The  GPParameter Schema property allows you to set rules for the output parameter description. The Schema property controls the generation and population of outputs so you don't have to write validation code as was required prior to ArcGIS 9.3. Example output descriptions that can be defined using the Schema property are as follows:

About schema

Schema is assigned to an output parameter by using the GPParameter.setSchemaByRef method in BaseGeoprocessingTool.getParameterInfo() or dynamically in BaseGeoprocessingTool.updateParameters(). The schema class is created by implementing the IGPSchema interface or using any one of the following implementing classes:
Output parameters of feature class, table, raster, or workspace type can only have an associated schema object. The description for the output parameter is set using the methods and properties of a schema object. There are minimum properties that must be set for specific output data.
For feature data, the properties are as follows:
For raster data, the properties are as follows:
  • Extent
  • Cell Size
  • Raster Format
  • Raster Type
For table data, the minimum property is Field Schema.
The following code snippet shows how to update the description of the out_feature parameter of the Add Field tool:
[Java]
class AddTool extends BaseGeoprocessingTool{
    public IArray getParameterInfo()throws IOException, AutomationException{
        IArray parameters = new Array();
        GPParameter parameter;

        //Input parameter: The feature class to which to add a field.
        //Set parameter properties.
        parameter = new GPParameter();
        parameter.setName("in_Feature");
        parameter.setDisplayName("Input Feature");
        parameter.setDirection
            (esriGPParameterDirection.esriGPParameterDirectionInput);
        parameter.setParameterType(esriGPParameterType.esriGPParameterTypeRequired);
        parameter.setDataTypeByRef(new DEFeatureClassType());
        parameter.setValueByRef(new DEFeatureClass());
        parameters.add(parameter);

        //Input parameter: Field name
        //Set properties for field name.
        parameter = new GPParameter();
        parameter.setName("in_FieldName");
        parameter.setDisplayName("Field Name");
        parameter.setDirection
            (esriGPParameterDirection.esriGPParameterDirectionInput);
        parameter.setParameterType(esriGPParameterType.esriGPParameterTypeRequired);
        parameter.setDataTypeByRef(new GPStringType());
        parameter.setValueByRef(new GPString());
        parameters.add(parameter);

        //Output parameter: The same as the input parameter.
        parameter = new GPParameter();
        parameter.setName("out_Feature");
        parameter.setDisplayName("Output Feature");
        parameter.setDirection
            (esriGPParameterDirection.esriGPParameterDirectionOutput);
        parameter.setParameterType(esriGPParameterType.esriGPParameterTypeDerived);
        parameter.setDataTypeByRef(new DEFeatureClassType());
        parameter.setValueByRef(new DEFeatureClass());

        //Create a schema object.
        //Schema means the structure or design of the feature class (field information, geometry information, extent).
        IGPSchema schema = new GPFeatureSchema();

        //Add dependency to the input parameter.
        parameter.addDependency("in_Feature");
        //Clone the schema from the dependency.
        //This means update the output with the same schema by copying the 
        //definition of an input parameter.
        schema.setCloneDependency(true);

        //Set schema of the output parameter.
        parameter.setSchemaByRef(schema);
        parameters.add(parameter);

        return parameters;

    }


    //This method updates the output parameter value with the additional field
    //when the value of the in_feature parameter is entered by the end user.
    public void updateParameters(IArray paramvalues, IGPEnvironmentManager envMgr){


        try{
            //Check whether the end user entered or modified the in_feature parameter. 

            IGPParameter3 input_feature = (IGPParameter3)paramvalues.getElement(0);

            if (input_feature.isAltered()){

                //Retrieve the input parameter value.
                IGPValue parameterValue = this.gpUtilities.unpackGPValue
                    (input_feature);

                //Get the derived output feature class schema and examine the fields. 
                //This ensures you don't get duplicate entries.
                IGPParameter3 derivedFeatures = (IGPParameter3)
                    paramvalues.getElement(2);
                IGPFeatureSchema schema = (IGPFeatureSchema)
                    derivedFeatures.getSchema();
                schema.setAdditionalFieldsByRef(null);

                //If you have an input value, create a field based on the field name the end user entered. 
                if (parameterValue.isEmpty()){
                    IGPParameter3 fieldNameParameter = (IGPParameter3)
                        paramvalues.getElement(1);
                    String fieldName = fieldNameParameter.getValue().getAsText();

                    //Check whether the end user's input field exists.
                    IField areaField = this.gpUtilities.findField(parameterValue,
                        fieldName);
                    if (areaField == null){
                        IFieldsEdit fieldsEdit = new Fields();
                        IFieldEdit fieldEdit = new Field();
                        fieldEdit.setName(fieldName);
                        fieldEdit.setType(esriFieldType.esriFieldTypeDouble);
                        fieldsEdit.addField(fieldEdit);

                        //Add an additional field for the area value of the derived output.
                        schema.setAdditionalFieldsByRef((IFields)fieldsEdit);
                    }
                }
            }
        }
        catch (IOException e){
            e.printStackTrace();
        }

    }
When you set the CloneDependency property to true using the IGPSchema.setCloneDependency()  method, you are making a copy (clone) of the description in the first dependent parameter in the parameter dependency list. Always set the CloneDependency property to true in the getParameterInfo() method, not in the updateParameters() method.
If the ParameterType property of the output parameter is set to esriGPParameterType.esriGPParameterTypeDerived, a clone is made. This is the behavior of the Add Field tool. If the ParameterType is set to esriGPParameterType.esriGPParameterTypeRequired, a clone is made, but the catalog path to the dataset is changed. Since most tools create new data, this is the most common behavior. Cloning can be thought of as setting the initial state of the output.
The following illustration is of a model where the output of the Clip tool is used as input to the Polygon to Raster tool:
 
The Clip tool "cookie-cuts" the input features of the Buildings data based on the StudyArea data. The output feature class of the Clip tool has the same properties as the input feature class with one exception: its geographic extent. The geographic extent of the output feature class is the geometric intersection of the geographic extents of the input feature (Buildings) and the clip feature (StudyArea). The Polygon to Raster tool uses the new geographic extent to determine a default cell size.
 
The following code snippet shows how to define the dependency of the output parameter on the input features and clip features and to define the schema for the output feature in the getParameterInfo() method:
[Java]
class AddTool extends BaseGeoprocessingTool{
    public IArray getParameterInfo()throws IOException, AutomationException{
        IArray parameters = new Array();


        //Define the input feature parameter andclip feature parameter (code not provided in this snippet).


        //Output feature
        GPParameter outParameter = new GPParameter();
        outParameter.setName("Out_Feature_Class");
        outParameter.setDisplayName("Output Feature Class");
        outParameter.setDataTypeByRef(new DEFeatureClassType());
        outParameter.setValueByRef(new DEFeatureClass());
        outParameter.setDirection
            (esriGPParameterDirection.esriGPParameterDirectionOutput);
        outParameter.setParameterType
            (esriGPParameterType.esriGPParameterTypeRequired);

        //Set the dependencies for the output. 
        outParameter.addDependency("input_features");
        outParameter.addDependency("clip_features");
        //Feature type, geometry type, and fields all come from the first 
        // dependent parameter, the input feature.
        GPFeatureSchema outSchema = new GPFeatureSchema();
        outSchema.setFieldsRule
            (esriGPSchemaFieldsType.esriGPSchemaFieldsFirstDependency);
        outSchema.setFeatureTypeRule
            (esriGPSchemaFeatureType.esriGPSchemaFeatureFirstDependency);
        outSchema.setGeometryType(esriGeometryType.esriGeometryPolygon);
        outSchema.setExtentRule
            (esriGPSchemaExtentType.esriGPSchemaExtentIntersection);

        //Make an exact copy of the description in the first dependent parameter
        //in its dependency list.
        outSchema.setCloneDependency(true);

        //Change the catalog output path since the parameterType is required.
        outSchema.setGenerateOutputCatalogPath(true);
        outParameter.setSchemaByRef((IGPSchema)outSchema);
        parameters.add(outParameter);

        return parameters;

    }
}

Setting schema in getParameterInfo() versus updateParameters()

Note that Clip example above modifies the Schema in getParameterInfo() and that updateParameters() does nothing but return. Add Field, on the other hand, has to modify the Schema in updateParameters() because it doesn't know the definition of the field to add until the user provides the information (and updateParameters() is called).
You can think of these two cases as static versus dynamic. Clip doesn't rely on anything but the datasets found in the dependent parameters (static case) whereas Add Field needs to examine other parameters (such as field name and field type) that are not dependent parameters (dynamic case).
This static and dynamic behavior is evident in way a tool validation is performed, as follows:
  1. When the tool dialog is first launched, getParameterInfo() is called. You set up the static rules for describing the output. No output description is created at this time since the user hasn't specified values for any of the parameters. 
  2. Once the user interacts with the tool dialog in any way, updateParameters() is called. updateParameters() can modify the Schema to account for dynamic behavior that can't be determined from the parameter dependencies, such as adding a new field like Add Field. 
  3. After returning from updateParameters(), the internal validation routines are called and the rules found in the Schema object are applied to update the description of the output data. 
  4. updateMessages() is then called. You can examine the warning and error messages that internal validation may have created and modify them, or add warnings and errors based upon the interaction of actual parameter values.


See Also:

Tool parameter domains
Geoprocessing tool parameter data types
Creating a custom function tool class




Development licensingDeployment licensing
Engine Developer KitEngine
ServerServer