Spatial Models can be saved to disk, or loaded from a saved file. These include models created in the Spatial Model Editor; in some cases it may be more convenient to create a complex model in the editor and execute it later from C++.
This example is located in smStatsExample. Look in Statistics::RunProcess() in Statistics.cpp. It creates a new model by loading an already saved Spatial Model, adding an operator to the end of the processing chain, and then saving the new model to disk.
This example begins with a saved model (statistics.gmdx), which just contains a RasterInput operator and a Statistics operator. Here’s what it would look in the ERDAS IMAGINE Spatial Modeler Editor (not included in the SMSDK).
Using the ModelFormatFactory, the model is loaded into a Model object. The ModelFormatFactory supports legacy graphical models (.gmd) in addition to the new formats introduced for Spatial Modeler (.gmdx, .gmdz). The Open function takes in a URI, which is an internal representation of a file name, a URL, etc. The fromFile function will create a URI from a file name.
ModelPtr model = ModelFormatFactory::Open( urilib::URI::fromFile( L$IMAGINE_HOME/smsdk/examples/smStatsExample/data/statistics.gmdx" ) );
Next, a report operator is created. This will be connected to the statistics operator to print the minimum and maximum of the input raster to a text file. It’s added to the model as a tail, since it will be the operator at the end of the chain.
OperatorPtr report = OperatorFactory::Create( L"IMAGINE", L"Report" ); model->AddTail( report );
Now, the port connections between the new report operator and the existing statistics operators can be created. First, the statistics operator must be located. This can be done by supplying a display name to FindOperator. The display name is the name shown in the Spatial Model Editor, and it guaranteed to be unique for every operator in a model. Once we have the statistics operator, we can connect the statistics operator’s Min port as the parent of the report operator’s Input1 port.
OperatorPtr statistics = model->FindOperator( L"Statistics", false ); report->ConnectParent( statistics->GetPort( L"Min" ), report->GetPort( L"Input1" ) );
Since the report operator only contains a single input port by default, we must tell the operator to add an additional port. This is done by calling the Expand function, which acts exactly as the Add Port button in the Spatial Model Editor. Once the port is created, connect it to the Max port of the statistics operator.
report->Expand(); report->ConnectParent( statistics->GetPort( L"Max" ), report->GetPort( L"Input2" ) );
By default the report operator prints the information to the session log, which isn’t needed for this model. Setting the value of the ToSessionLog port will turn this off.
report->GetPort( L"ToSessionLog" )->SetData<BoolData>( false );
Also by default the TextFilename port is hidden from the editor. Let’s expose this.
report->GetPort( L"TextFilename" )->SetIsHidden( false );
Now the model can be saved to a file using the ModelFormatFactory. The Save function also takes in a URI. The last parameter tells the factory which format to use when saving. Currently “SpatialModelFormat” for a gmdx and “ZippedSpatialModelFormat” for a gmdz are supported.
ModelFormatFactory::Save( model, urilib::URI::fromFile( L"$IMAGINE_HOME/smsdk/examples/smStatsExample/data/statistics_with_report.gmdx" ), L"SpatialModelFormat" );
The model now contains a report operator that will “print” out the minimum and maximum of the input raster—we’ll tell it where to “print” the values later. Here’s how the model would now look in the ERDAS IMAGINE Spatial Modeler Editor (not included in the SMSDK).
This model can now be run. The input files are set on the appropriate ports and the model is executed. We locate the raster input using a slightly different method. FindOperatorsByName will locate all operators in a model with a given name. Since names are not unique, this returns a list of operators. In this model, we know there is only a single raster input, so we use the first item in the list.
OperatorPtr rasterInput = model->FindOperatorsByName( L"RasterInput" ).front(); rasterInput->GetPort(L"Filename")->SetData<FileData>( L$IMAGINE_HOME/smsdk/examples/smStatsExample/data/lanier.img" ); report->GetPort(L"TextFilename")->SetData<FileData>( L"$IMAGINE_HOME/smsdk/examples/smStatsExample/data/stats.txt" ); model->Execute();
Previous article: Example 1: Building Spatial Models in C++
Next article: Extending Spatial Modeler