Add a feature model

You can add and remove data on the Map using Map::getLayerList().

To add a feature model to the map, you:

  1. Create a FeatureLayer based on the model and styling information (IFeaturePainter)

  2. Add that layer to the Map’s LayerList

This code snippet demonstrates how a feature model is added to the map, configured with a custom painter:

Program (C++): Adding a feature layer
std::shared_ptr<IFeatureModel> geometryModel = CustomerGeometryModel::create();
std::shared_ptr<FeatureLayer> geometryLayer = FeatureLayer::newBuilder().model(geometryModel).build();

map->getLayerList()->add(geometryLayer);
Program (C#): Adding a feature layer
var geometryModel = CustomerGeometryModel.Create();
var geometryLayer = FeatureLayer.NewBuilder().Model(geometryModel).Build();
Map.LayerList.Add(geometryLayer);

Styling

Apart from a mandatory IFeatureModel parameter on its constructor, the FeatureLayer::Builder also accepts an optional IFeaturePainter, which you can use to set up custom styling of the model features.

Creating your own IFeaturePainter requires an implementation of two methods:

  • IFeaturePainter::configureMetadata: used to retrieve metadata about the painter. This metadata is used by the layer to determine when a feature needs to be re-processed by the painter. For example, a feature needs to be painted differently after a certain property of the feature has changed. For more information, see the documentation of FeaturePainterMetadata.

  • IFeaturePainter::paint: used to determine how to visualize a feature. Given a Feature and context, this method performs draw calls on the FeatureCanvas, which is also passed as a parameter.

The following code snippet shows an implementation of the IFeaturePainter::paint method.

Program (C++): Using the feature painter
void TrackFeaturePainter::paint(const Feature& feature, const FeaturePainterContext& context, FeatureCanvas& canvas) const {
  auto geometry = feature.findGeometry();
  if (!geometry) {
    return;
  }

  canvas.drawIcon()
      .icon(context.isFeatureStateEnabled(FeatureState::selected()) ? constants.iconSelected : constants.iconRegular)
      .anchor(geometry.value())
      .draped(false)
      .submit();

  if (context.getDetailLevel() == 1) {
    // Paint a line along the track to show the distance it can cover in one minute at the current speed
    auto location = std::dynamic_pointer_cast<Point>(geometry.value());
    auto azimuth = feature.getValue<double>(CustomerTrackModel::getAzimuthPropertyPath());
    auto speed = feature.getValue<double>(CustomerTrackModel::getGroundSpeedValuePropertyPath());
    if (!location || !azimuth || !speed) {
      return;
    }

    // Calculate the expected location within one minute (assuming the speed and azimuth don't change)
    auto lineEnd = _geodesy->extrapolate2D(location->getLocation(), azimuth.value(), speed.value() * 60.0);
    if (!lineEnd) {
      return;
    }

    auto line = GeometryFactory::createLine(location->getCoordinateReference(), location->getLocation(), lineEnd.value(), LineInterpolationType::Geodesic);
    auto style = context.isFeatureStateEnabled(FeatureState::selected()) ? constants.lineStyleSelected : constants.lineStyleRegular;
    canvas.drawGeometry().geometry(line).stroke(style).draped(false).submit();

    // Show the call sign of the track
    auto callSign = feature.getValue<std::string>(CustomerTrackModel::getCallSignPropertyPath());
    if (callSign) {
      RelativePosition relativePosition{0.0, HorizontalAlignment::Left, VerticalAlignment::Below, 5, -5};
      canvas.drawText().anchor(*geometry).text(*callSign).font("Arial Black").textColor(Color(196, 196, 196)).position(relativePosition).submit();
    }
  }
}
Program (C#): Using the feature painter
    public void Paint(Feature feature, FeaturePainterContext context, FeatureCanvas canvas)
    {
        var geometry = feature.FindGeometry();
        if (geometry == null)
        {
            return;
        }
        canvas.DrawIcon()
              .Anchor(geometry)
              .Icon(context.IsFeatureStateEnabled(FeatureState.Selected) ? IconSelected : IconRegular)
              .Draped(false)
              .Submit();
        if (context.DetailLevel == 1)
        {
            var location = geometry as Luciad.Geometries.Point;
            var azimuth = feature.GetValue<double?>(CustomerTrackModel.AzimuthPropertyPath);
            var speed = feature.GetValue<double?>(CustomerTrackModel.GroundSpeedValuePropertyPath);
            if (location == null || azimuth == null || speed == null)
            {
                return;
            }

            var lineEnd = _geodesy.Extrapolate2D(location.Location, azimuth.Value, speed.Value * 60.0);
            if (lineEnd == null)
            {
                return;
            }

            var line = GeometryFactory.CreateLine(location.CoordinateReference, location.Location, lineEnd.Value, LineInterpolationType.Geodesic);
            canvas.DrawGeometry()
                  .Geometry(line)
                  .Stroke(context.IsFeatureStateEnabled(FeatureState.Selected) ? LineStyleSelected : LineStyleRegular)
                  .Draped(false)
                  .Submit();

            // Show the call sign of the track
            var callSign = feature.GetValue<string>(CustomerTrackModel.CallSignPropertyPath);
            if ( callSign != null ) {
              RelativePosition relativePosition = new RelativePosition(0.0, HorizontalAlignment.Left, VerticalAlignment.Below, 5, -5);
              canvas.DrawText()
                    .Anchor(geometry)
                    .Text(callSign)
                    .Font("Arial Black")
                    .TextColor(Color.FromArgb(196, 196, 196))
                    .Position(relativePosition)
                    .Submit();
            }
        }
    }
}

You can visualize geometries with the FeatureCanvas::drawGeometry. This method requires at least a Geometry and FeatureStyle.

You create Feature styles through builder methods on the FeatureStyle class. The different types of feature styles are:

  • Fill Style: describes the style of a surface, a fill color or specific textures for example.

  • Line Style: describes the style of a line, a line color or width for example.

Finally, you can draw icons and text labels with FeatureCanvas::drawIcon and FeatureCanvas::drawText respectively.

For more information on how to configure icon and label options, see the API reference documentation of these methods.