List Transformations by Suitability

Demonstrates how to use the TransformationCatalog to get a list of available DatumTransformations that can be used to project a Geometry between two different SpatialReferences.

Transformations (sometimes known as datum or geographic transformations) are used when projecting data from one spatial reference to another, when there is a difference in the underlying datum of the spatial references. Transformations can be mathematically defined by specific equations (equation-based transformations), or may rely on external supporting files (grid-based transformations). Choosing the most appropriate transformation for a situation can ensure the best possible accuracy for this operation. Some users familiar with transformations may wish to control which transformation is used in an operation.

How it works

To get suitable transformations from one spatial reference to another:

  1. Use TransformationCatalog.getTransformationsBySuitability(inputSR, outputSR) for transformations based on the map's spatial reference OR TransformationCatalog.getTransformationsBySuitability(inputSR, outputSR, mapView.getCurrentVisibileArea().getExtent()) for transformations suitable to the current extent .
  2. Pick one of the DatumTransformations returned. Use GeometryEngine.project(inputGeometry, outputSR, datumTransformation) to get the transformed geometry.


 * Copyright 2018 Esri.
 * Licensed under the Apache License, Version 2.0 (the "License"); you may not
 * use this file except in compliance with the License. You may obtain a copy of
 * the License at
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 * License for the specific language governing permissions and limitations under
 * the License.

package com.esri.samples.geometry.list_transformations_by_suitability;

import java.util.List;

import javafx.application.Application;
import javafx.event.ActionEvent;
import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.CheckBox;
import javafx.scene.control.ListCell;
import javafx.scene.control.ListView;
import javafx.scene.layout.StackPane;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;

import com.esri.arcgisruntime.geometry.DatumTransformation;
import com.esri.arcgisruntime.geometry.GeometryEngine;
import com.esri.arcgisruntime.geometry.Point;
import com.esri.arcgisruntime.geometry.SpatialReference;
import com.esri.arcgisruntime.geometry.TransformationCatalog;
import com.esri.arcgisruntime.mapping.ArcGISMap;
import com.esri.arcgisruntime.mapping.Basemap;
import com.esri.arcgisruntime.mapping.view.Graphic;
import com.esri.arcgisruntime.mapping.view.GraphicsOverlay;
import com.esri.arcgisruntime.mapping.view.MapView;
import com.esri.arcgisruntime.symbology.SimpleMarkerSymbol;

public class ListTransformationsBySuitabilitySample extends Application {

  private MapView mapView;

  public void start(Stage stage) throws Exception {

    try {
      // create stack pane and application scene
      StackPane stackPane = new StackPane();
      Scene scene = new Scene(stackPane);

      // set title, size, and add scene to stage
      stage.setTitle("List Transformations by Suitability Sample");

      // create a map with light gray canvas basemap and add it to the map view
      ArcGISMap map = new ArcGISMap(Basemap.createLightGrayCanvas());
      mapView = new MapView();

      // create a graphics overlay to show the original graphic and the the transformed graphic
      GraphicsOverlay graphicsOverlay = new GraphicsOverlay();

      // create a blue square graphic located in the Greenwich observatory courtyard in London, UK, the location of the
      // Greenwich prime meridian. This will be projected using the selected transformation.
      Point originalPoint = new Point(538985.355, 177329.516, SpatialReference.create(27700));
      Graphic originalGraphic = new Graphic(originalPoint, new SimpleMarkerSymbol(SimpleMarkerSymbol.Style.SQUARE, 0xFF0000FF,

      // create red cross graphic for transformed point
      Graphic transformedGraphic = new Graphic();
      transformedGraphic.setSymbol(new SimpleMarkerSymbol(SimpleMarkerSymbol.Style.CROSS, 0xFFFF0000, 10));

      // zoom to the location of the original graphic
      mapView.setViewpointCenterAsync(originalPoint, 5000);

      // create a list of transformations
      ListView<DatumTransformation> transformationsListView = new ListView<>();

      // show the transformation name in the list
      transformationsListView.setCellFactory(list -> new ListCell<DatumTransformation>() {

        protected void updateItem(DatumTransformation transformation, boolean bln) {

          super.updateItem(transformation, bln);
          if (transformation != null) {


      // if the checkbox is not selected, transformations should be ordered by suitability for the whole
      // spatial reference. If checked, then transformations will be ordered by suitability for the map extent.
      CheckBox suitabilityCheckBox = new CheckBox("Order by extent suitability");
      suitabilityCheckBox.setOnAction(e -> {
        List<DatumTransformation> transformations;
        if (suitabilityCheckBox.isSelected()) {
          transformations = TransformationCatalog.getTransformationsBySuitability(
            originalGraphic.getGeometry().getSpatialReference(), map.getSpatialReference(), mapView.getVisibleArea().getExtent());
        } else {
          transformations = TransformationCatalog.getTransformationsBySuitability(
            originalGraphic.getGeometry().getSpatialReference(), map.getSpatialReference());

      // trigger the event to load the initial transformations list when the map is loaded
      map.addDoneLoadingListener(() -> suitabilityCheckBox.fireEvent(new ActionEvent()));

      // create a button that when clicked, shows a new graphic with the selected transformation applied
      Button transformButton = new Button("Transform");
      transformButton.setOnAction(e -> {
        DatumTransformation transformation = transformationsListView.getSelectionModel().getSelectedItem();
        if (transformation != null) {
          Point projectedPoint = (Point) GeometryEngine.project(originalGraphic.getGeometry(), mapView.getSpatialReference(),

      // add the controls to the view
      VBox vBox = new VBox(6);
      vBox.setMaxSize(300, 500);
      vBox.getChildren().addAll(suitabilityCheckBox, transformationsListView, transformButton);

      // add the map view to stack pane
      stackPane.getChildren().addAll(mapView, vBox);
      StackPane.setAlignment(vBox, Pos.TOP_LEFT);
      StackPane.setMargin(vBox, new Insets(10, 0, 0, 10));
    } catch (Exception e) {
      // on any error, display the stack trace.

   * Stops and releases all resources used in application.
  public void stop() {

    if (mapView != null) {

   * Opens and runs application.
   * @param args arguments passed to this application
  public static void main(String[] args) {



In this topic
  1. How it works
  2. Code