In Carmenta Engine we define data flows by linking operators together. An operator reads features from its input, processes or manipulates those features and pass the result to the next operator. In the typical case, operators are added and configured in a configuration file and calls are managed by the map view without direct user interaction with the operators.
But in some cases a more custom approach is necessary and the application need to access the processed features directly in code. For example, the application may want to display information produced by the operators or an external component (or service) may want to use the result as input. In this article, we will explain how to approach such use-case.
All codes and pictures shown in this article are from the sample that can be downloaded here.
Setting up the operator chain
The first step is to get the operator chain set up in your application, there are two ways to do this:
- The easiest way is to prepare and configure the operator chain in a map configuration file using Carmenta Studio; then load the file from the code as you would normally do for a map configuration containing a view. But instead of getting hold of a view object you get the operator using its name as identifier.
Configuration routingConfig = new Configuration("bathymetry_routing.px"); Operator terrainRouteOperator = routingConfig.GetPublicObject("TerrainRouteOperator0") as Operator;
- The second way is to build the operator chain in code. This allows for building operator chains dynamically, where conditions at runtime affects how the operator chain is composed. While this solution can provide more flexibility it also requires more of the developer, to foresee and handle different situations. Therefore, building your operator chain in a map configuration file using Carmenta Studio is the suggested approach, if your use case allows for it.
The second step is to call the getFeatures function which retrieves all features produced by the operator chain. The number of features returned depends on the operator used, check the documentation for information on specific operators. When called from code, the result will be returned as a FeatureEnumerator object allowing you to enumerate over all features in the result.
Additionally, depending on the operator called, the features may get new attributes. The documentation indicates if a feature is updated with new attributes and what information these attributes holds.
Note: The getFeatures function also exist on DataSet and Layer classes. Providing the same functionality, retrieving features directly in code.
Calling the getFeatures function with a Crs will return features projected to the coordinate reference system (CRS) specified.
Before choosing a CRS it is good practice to check the documentation about the operator to understand how it works and in which CRS it usually output its result. Using an appropriate CRS help getting accurate result; for example a VerticalProfileOperator usually expect a NonGeoreferenced CRS and an EllipseOperator use the CRS of the View.
In the code below, result will contain all features produced by the operator.
FeatureEnumerator result = terrainRouteOperator.GetFeatures(Crs.Wgs84LongLat);
The featureQuery parameter will limit the number of returned features. Only the features matching the query will go through, all others will be discarded. To limit the number of features returned you can use the following properties:
- Area: limit the features returned to a specific location. The area coordinates need to be expressed in the same CRS as the one used in getFeatures.
- Condition: the condition is evaluated for each feature and like using Condition in a configuration file you can test feature attributes. If the condition does not match, the feature is not returned.
In the code below, result will only contain the features with the attribute
isLastLeg set to
true (see documentation about TerrainRouteOperator for more information about the attribute)
FeatureQuery featureQuery = new FeatureQuery(); featureQuery.Condition = new Condition("isLastLeg = true"); FeatureEnumerator result = terrainRouteOperator.GetFeatures(Crs.Wgs84LongLat, featureQuery);
Complete example using TerrainRouteOperator for nautical routing
The sample describes a simple use-case where a TerrainRouteOperator and the getFeatures method are used in the code to determine the travel time from start to finish and display it in the UI.
To use the sample:
- Download the Tampa Bay bathymetric data from https://topotools.cr.usgs.gov/topobathy_viewer/dwndata.htm unzip the content into the Bathymetry folder.
- Download the C# code sample nautical routing. unzip and compile the solution.
- Using the EllipseOperator to get the area surrounding a specific location, like a safety zone, and use it to detect or identify object(s) crossing the circle.
- Using the VerticalProfileOperator to retrieve elevations along a line.