Step 3b: Create the Client Code for the Mapping Service

The next step is to create a map image with the found subway stations using Toronto as the base map. We need to use the RenderNamedMapWithOverlay method of the Mapping Service.

The steps are:

  1. Create an instance of RenderNamedMapWithOverlayRequest.
  2. Set the desired width and height of the image.
  3. Set the view (bounds) of the map.
  4. Set the named map to render.
  5. Set the MIME type (image format) to generate.
  6. Create a FeatureLayer overlay based on the specified FeatureCollection.
  7. Set some label properties to label each subway station with its name and distance in meters.
  8. Create a theme to give the subway stations a recognizable style.
  9. Execute the request and return the image's bytes.

Here is the code:


/**
 * Returns the image of the map overlayed with Features in the specified FeatureCollection.
 * @param fc the FeatureCollection to render on top of the map.
 * @param centerLongitude the longitude of the center of the map
 * @param centerLatitude the latitude of the center of the map
 * @param zoom the zoom (distance across the map) assumed to be kilometers.
 * @return the image of the map overlayed with Features in the specified FeatureCollection.
 */
private byte[] createMap(FeatureCollection fc, double centerLongitude, double centerLatitude, double zoom) {
    RenderNamedMapWithOverlayRequest request = new RenderNamedMapWithOverlayRequest();
    ZoomAndCenterMapView mapView = new ZoomAndCenterMapView();

    // set the dimensions of the returned image to be 640 x 480
    mapView.setWidth(640);
    mapView.setHeight(480);

    // set the view. in this case we are using the zoom/center view
    Point center = new Point();
    center.setSrsName("epsg:4326");
    center.setPos(new Pos());
    center.getPos().setX(centerLatitude);
    center.getPos().setY(centerLongitude);
    mapView.setMapCenter(center);

    Distance zoomLevel = new Distance();
    zoomLevel.setValue(zoom);
    zoomLevel.setUom(DistanceUnit.KILOMETER);
    mapView.setZoomLevel(zoomLevel);

    request.setMapView(mapView);

    // use the /demo/namedmaps/ontario Named Map for the background
    String namedMap = "/demo/namedmaps/ontario";
    request.setNamedMap(namedMap);

    // we want a GIF
    String mimeType = "image/gif";
    request.setImageMimeType(mimeType);

    // return the image NOT a URL to the image
    request.setReturnImage(true);

    // now create the FeatureCollection overlay using a MemoryTable and a FeatureLayer
    OverlayList overlayList = new OverlayList();
    List<Layer> overlays = overlayList.getOverlay();
    MemoryTable table = new MemoryTable();
    table.setFeatureCollection(fc);

    FeatureLayer layer = new FeatureLayer();
    layer.setTable(table);

    {
        // create the label properties
        MapBasicPointStyle style = new MapBasicPointStyle();

        MapBasicFontSymbol mapBasicSymbol;
        mapBasicSymbol = new MapBasicFontSymbol();
        mapBasicSymbol.setBold(true);
        mapBasicSymbol.setColor("black");
        mapBasicSymbol.setFontName("Arial");
        mapBasicSymbol.setSize((short) 14);
        mapBasicSymbol.setShape(33);
        style.setMapBasicSymbol(mapBasicSymbol);

        LabelProperties labelProperties = new LabelProperties();
        // the label expression is an MI SQL fragment
        labelProperties.setExpression("name + '(' + round(distance) + ' m)'");
        labelProperties.setAllowDuplicate(AllowDuplicateType.ALL);
        labelProperties.setAllowOverlap(true);
        labelProperties.setXOffset(10.0); // a small offset in the X direction so the label does not overwrite the symbol
        layer.setLabelProperties(labelProperties);
    }

    overlays.add(layer);
    request.setOverlayList(overlayList);

    // add theme to set the style of the overlay
    OverrideTheme theme = new OverrideTheme();
    MapBasicPointStyle featureStyle = new MapBasicPointStyle();
    MapBasicFontSymbol mapBasicFontSymbol = new MapBasicFontSymbol();
    mapBasicFontSymbol.setShape(64);
    mapBasicFontSymbol.setColor("red");
    mapBasicFontSymbol.setFontName("MapInfo Transportation");
    mapBasicFontSymbol.setSize((short) 14);
    featureStyle.setMapBasicSymbol(mapBasicFontSymbol);
    theme.setStyle(featureStyle);

    ThemeList themeList = new ThemeList();
    themeList.getTheme().add(theme);
    layer.setThemeList(themeList);

    // create the client-side instance/interface to the FeatureService and specify the security settings to access the service
    MappingService mappingServiceBootstrap = new MappingService();
    MappingServiceInterface servicePort = mappingServiceBootstrap.getPort(MappingServiceInterface.class);
    ((BindingProvider)servicePort).getRequestContext().put(BindingProvider.USERNAME_PROPERTY, ADMIN_USERNAME);
    ((BindingProvider)servicePort).getRequestContext().put(BindingProvider.PASSWORD_PROPERTY, ADMIN_PASSWORD);

    RenderNamedMapWithOverlayResponse response;
    try {
        response = servicePort.renderNamedMapWithOverlay(request);
    } catch (com.mapinfo.midev.service.mapping.ws.v1.ServiceException e) {
        throw new RuntimeException(e);
    }
    MapImage mapImage = response.getMapImage();
    return mapImage.getImage();
}