Geodesic buffer

Download Sample Viewer

Description

This sample demonstrates the use of a Local Geoprocessing Service to calculate a buffer - in this case a geodesic buffer around a point. To use the sample, simply enter the buffer distance (in kilometers) and left-click a point on the map. The clicked point and a buffer of the specified distance around the point will be shown. A Local Geoprocessing Service is used to buffer the point, created from a geoprocessing package (gpk).

Code snippet


    // start service, if local
    LocalGeoprocessingService geoprocessingService = 
        new LocalGeoprocessingService("file path to .gpk");
    geoprocessingService.startAsync();
 
    // create a geoprocessor
    Geoprocessor geoprocessor = new Geoprocessor(
        geoprocessingService.getUrlGeoprocessingService() + "/" + GP_SERVICE_NAME);
 
    // provide input arguments
    List<GPParameter> gpInputParams = new ArrayList<GPParameter>(); 
    gpInputParams.add(<appropriate instance of GPParameter>);
    // repeat for each input parameter
    
    // run geoprocessing task and process result
    // one of the options to run the geoprocessing task
    geoprocessor.executeAsync(...);
  

Sample Code

/* Copyright 2014 Esri

All rights reserved under the copyright laws of the United States
and applicable international laws, treaties, and conventions.

You may freely redistribute and use this sample code, with or
without modification, provided you include the original copyright
notice and use restrictions.

See the use restrictions.*/
package com.esri.client.samples.geoprocessing;

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.event.ComponentAdapter;
import java.awt.event.ComponentEvent;
import java.awt.event.MouseEvent;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.io.File;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;

import javax.swing.BorderFactory;
import javax.swing.BoxLayout;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JLayeredPane;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JProgressBar;
import javax.swing.JTextArea;
import javax.swing.JTextField;
import javax.swing.SwingUtilities;
import javax.swing.border.LineBorder;

import com.esri.client.local.GPServiceType;
import com.esri.client.local.LocalGeoprocessingService;
import com.esri.client.local.LocalServiceStartCompleteEvent;
import com.esri.client.local.LocalServiceStartCompleteListener;
import com.esri.core.geometry.Envelope;
import com.esri.core.geometry.Geometry.Type;
import com.esri.core.geometry.Point;
import com.esri.core.geometry.SpatialReference;
import com.esri.core.map.CallbackListener;
import com.esri.core.map.Graphic;
import com.esri.core.symbol.SimpleFillSymbol;
import com.esri.core.symbol.SimpleLineSymbol;
import com.esri.core.symbol.SimpleMarkerSymbol;
import com.esri.core.symbol.SimpleMarkerSymbol.Style;
import com.esri.core.tasks.ags.geoprocessing.GPFeatureRecordSetLayer;
import com.esri.core.tasks.ags.geoprocessing.GPLinearUnit;
import com.esri.core.tasks.ags.geoprocessing.GPParameter;
import com.esri.core.tasks.ags.geoprocessing.Geoprocessor;
import com.esri.map.ArcGISTiledMapServiceLayer;
import com.esri.map.GraphicsLayer;
import com.esri.map.JMap;
import com.esri.map.MapEvent;
import com.esri.map.MapEventListenerAdapter;
import com.esri.map.MapOverlay;
import com.esri.runtime.ArcGISRuntime;

/**
 * This sample demonstrates the use of a local geoprocessing service to
 * calculate a buffer - in this case a buffer around a point. To use
 * the sample, simply enter the buffer distance (in kilometers) and
 * left-click to add a point on the map. The clicked point will be shown and
 * a buffer of the specified distance around the point will be computed
 * and added as a graphic to the map. A LocalGeoprocessingService is
 * used to buffer the point, created from a geoprocessing package (gpk).
 */
public class LocalSimpleBufferApp {

  private JComponent contentPane;
  private JMap map;
  private SpatialReference srMap;
  private JProgressBar progressBar;
  private AtomicInteger tasksInProgress = new AtomicInteger(0);
  private LocalGeoprocessingService simpleBufferService;
  private JTextField distanceInput;
  private SimpleBufferExecutor simpleBufferExecutor;
  private static final String SERVICE_NAME = "SimpleBuffer";
  private static final String DEFAULT_BUFFER_DISTANCE = "500";
  private static final int PANEL_WIDTH = 230;
  private static final String FSP = System.getProperty("file.separator");

  // ------------------------------------------------------------------------
  // Constructors
  // ------------------------------------------------------------------------
  /**
   * Creates an instance of this sample.
   */
  public LocalSimpleBufferApp() {
  }

  // ------------------------------------------------------------------------
  // Core functionality
  // ------------------------------------------------------------------------
  /**
   * Class that executes a remote geoprocessing service to calculate zones with
   * different drive times.
   */
  class SimpleBufferExecutor extends MapOverlay {

    private static final long serialVersionUID = 1L;
    JMap jMap;
    GraphicsLayer graphicsLayer;

    // symbology
    private final SimpleMarkerSymbol SYM_POINT = new SimpleMarkerSymbol(Color.MAGENTA, 14, Style.CIRCLE);
    private final SimpleLineSymbol SYM_BORDER = new SimpleLineSymbol(Color.RED, 1);
    private final SimpleFillSymbol SYM_FILL = new SimpleFillSymbol(new Color(255, 0, 0, 80), SYM_BORDER);

    public SimpleBufferExecutor(JMap jMap, GraphicsLayer graphicsLayer) {
      this.jMap = jMap;
      this.graphicsLayer = graphicsLayer;
    }

    /**
     * Computes the buffer on click of the mouse.
     */
    @Override
    public void onMouseClicked(MouseEvent mouseEvent) {

      if (!simpleBufferExecutor.isActive()) {
        return;
      }

      if (mouseEvent.getButton() == MouseEvent.BUTTON3) {
        graphicsLayer.removeAll();
        return;
      }

      tasksInProgress.incrementAndGet();
      updateProgressBarUI("Computing buffer...", true);

      // obtain the point from the mouse click
      Point point = jMap.toMapPoint(mouseEvent.getX(), mouseEvent.getY());
      // obtain the buffer distance from the text field
      double distance = Double.parseDouble(distanceInput.getText());
      if (distance > 2000 || distance < 50) {
        JOptionPane.showMessageDialog(contentPane,
            "Please enter a value from 50 to 2000.", "", JOptionPane.WARNING_MESSAGE);
        return;
      }

      // use the point from the mouse click and add a graphic
      Graphic pointGraphic = new Graphic(point, SYM_POINT);
      graphicsLayer.addGraphic(pointGraphic);

      // execute the buffer and display the buffer zone
      executeSimpleBuffer(pointGraphic, distance);
    }

    private void executeSimpleBuffer(Graphic pointGraphic, double bufferDistance) {

      // create a Geoprocessor that points to the geoprocessing service URL
      Geoprocessor geoprocessor = new Geoprocessor(simpleBufferService.getUrlGeoprocessingService()
          + "/" + SERVICE_NAME);
      geoprocessor.setProcessSR(srMap);
      geoprocessor.setOutSR(srMap);

      // initialize the required input parameters: refer to help link in the
      // geoprocessing service URL for a list of required parameters
      List<GPParameter> parameters = new ArrayList<>();

      GPFeatureRecordSetLayer pointParam = new GPFeatureRecordSetLayer("InputFeatures");
      pointParam.setGeometryType(Type.POINT);
      pointParam.setSpatialReference(srMap);
      pointParam.addGraphic(pointGraphic);

      GPLinearUnit distanceParam = new GPLinearUnit("Distance");
      distanceParam.setUnits("esriKilometers");
      distanceParam.setDistance(bufferDistance);

      parameters.add(pointParam);
      parameters.add(distanceParam);

      // execute the geoprocessing request

      // -------------------------------------------------------------------------------------
      // Option 1 - execute (synchronous)
      // Client execution will happen in this thread.
      // This is ideal for jobs that take less processing time and whose result size is small.
      // This will freeze the UI.
      // -------------------------------------------------------------------------------------

      /*GPParameter[] result = geoprocessor.execute(parameters);
            processResult(result);*/

      // -------------------------------------------------------------------------------------
      // Option 2 - executeAsync (asynchronous)
      // Client execution and result collection will happen in that thread.
      //
      // This is ideal for jobs that take relatively more processing time than option 1
      // and whose result size is small.
      // -------------------------------------------------------------------------------------

      geoprocessor.executeAsync(
          parameters,
          new CallbackListener<GPParameter[]>() {

            @Override
            public void onError(Throwable th) {
              th.printStackTrace();
            }

            @Override
            public void onCallback(final GPParameter[] result) {
              updateProgressBarUI(null, tasksInProgress.decrementAndGet() > 0);
              processResult(result);
            }
          }
          );
    }

    /**
     * Process result from geoprocessing execution.
     * @param result output of geoprocessing execution.
     */
    private void processResult(GPParameter[] result) {
      for (GPParameter outputParameter : result) {
        if (outputParameter instanceof GPFeatureRecordSetLayer) {
          GPFeatureRecordSetLayer gpLayer = (GPFeatureRecordSetLayer) outputParameter;
          Graphic resultGraphic = gpLayer.getGraphics().get(0);
          // get the graphic and add to the graphics layer
          Graphic theGraphic = new Graphic(resultGraphic.getGeometry(),SYM_FILL);
          // add to the graphics layer
          graphicsLayer.addGraphic(theGraphic);
        }
      }
    }
  }

  // ------------------------------------------------------------------------
  // Static methods
  // ------------------------------------------------------------------------
  /**
   * Starting point of this application.
   * @param args arguments to this application.
   */
  public static void main(String[] args) {
    SwingUtilities.invokeLater(new Runnable() {
      @Override
      public void run() {
        try {
          // instance of this application
          LocalSimpleBufferApp simpleBufferApp = new LocalSimpleBufferApp();

          // create the UI, including the map, for the application
          JFrame appWindow = simpleBufferApp.createWindow();
          appWindow.add(simpleBufferApp.createUI());
          appWindow.setVisible(true);
        } catch (Exception e) {
          e.printStackTrace();
        }
      }
    });
  }

  // ------------------------------------------------------------------------
  // Public methods
  // ------------------------------------------------------------------------
  /**
   * Creates and displays the UI, including the map, for this application.
   * @return the UI for this sample.
   */
  public JComponent createUI() {

    // application content
    contentPane = createContentPane();

    // progress bar
    progressBar = createProgressBar(contentPane);

    // map
    map = createMap();

    // user panel
    JPanel panel = createUserPanel();

    contentPane.add(panel);
    contentPane.add(progressBar);
    contentPane.add(map);

    return contentPane;
  }

  // ------------------------------------------------------------------------
  // Private methods
  // ------------------------------------------------------------------------
  /**
   * Creates the map.
   * @return the jMap
   */
  private JMap createMap() {

    final JMap jMap = new JMap();
    // zoom to desired extent
    jMap.setExtent(new Envelope(-15.8,-37.8, 156.8, 77.3));

    // store the spatial reference for later once the map is ready
    jMap.addMapEventListener(new MapEventListenerAdapter() {
      @Override
      public void mapReady(final MapEvent mapEvent) {
        SwingUtilities.invokeLater(new Runnable() {
          @Override
          public void run() {        
            srMap = ((JMap) mapEvent.getSource()).getSpatialReference();
          }
        });
      }
    });

    // create and add the tiled layer
    ArcGISTiledMapServiceLayer tiledLayer = new ArcGISTiledMapServiceLayer(
        "http://services.arcgisonline.com/ArcGIS/rest/services/NGS_Topo_US_2D/MapServer");
    jMap.getLayers().add(tiledLayer);

    // graphics layer to add point and buffer graphics
    GraphicsLayer graphicsLayer = new GraphicsLayer();
    jMap.getLayers().add(graphicsLayer);

    // create and add our custom map overlay
    simpleBufferExecutor = new SimpleBufferExecutor(jMap, graphicsLayer);
    simpleBufferExecutor.setActive(false);
    jMap.addMapOverlay(simpleBufferExecutor);

    // create and start the local geoprocessing service
    simpleBufferService = new LocalGeoprocessingService(getPathSampleData() + 
        "gpks" + FSP + "SimpleBuffer" + FSP + SERVICE_NAME + ".gpk");
    simpleBufferService.setServiceType(GPServiceType.EXECUTE);
    simpleBufferService.addLocalServiceStartCompleteListener(new LocalServiceStartCompleteListener() {

      @Override
      public void localServiceStartComplete(LocalServiceStartCompleteEvent arg0) {
        // enable our map overlay which responds to button clicks
        simpleBufferExecutor.setActive(true);
        updateProgressBarUI(null, false);
      }
    });
    updateProgressBarUI("Initializing local service...", true);

    simpleBufferService.startAsync();

    return jMap;
  }


  /**
   * Creates the panel to display description and capture user input
   */
  private JPanel createUserPanel() {

    // create description
    JTextArea description = createDescription();

    // label to input buffer distance
    JLabel lblDistance = new JLabel("Distance (km): ");
    lblDistance.setForeground(Color.BLACK);
    lblDistance.setFont(new Font("Verdana", Font.BOLD, 12));
    lblDistance.setMaximumSize(new Dimension(120, 20));

    // text field to input number of days
    distanceInput = new JTextField(DEFAULT_BUFFER_DISTANCE, 5);
    distanceInput.setMaximumSize(new Dimension(30, 20));

    // group the above UI items into a panel
    final JPanel controlPanel = new JPanel();
    BoxLayout boxLayout = new BoxLayout(controlPanel, BoxLayout.X_AXIS);
    controlPanel.setLayout(boxLayout);
    controlPanel.setSize(PANEL_WIDTH, 20);
    controlPanel.setBorder(BorderFactory.createEmptyBorder(2,5,2,5));
    controlPanel.setBackground(new Color(255, 255, 255, 255));
    controlPanel.add(lblDistance);
    controlPanel.add(distanceInput);

    JPanel panel = new JPanel();
    panel.setLayout(new BorderLayout(0, 0));
    panel.setLocation(10, 10);
    panel.setSize(PANEL_WIDTH, 140);
    panel.setBackground(new Color(0, 0, 0, 0));
    panel.setBorder(new LineBorder(Color.BLACK, 3, false));

    // group control and description in a panel
    panel.add(description, BorderLayout.CENTER);
    panel.add(controlPanel, BorderLayout.SOUTH);

    return panel;
  }

  /**
   * Creates a window.
   * @return a window.
   */
  private JFrame createWindow() {
    JFrame window = new JFrame("Simple Buffer");
    window.setBounds(100, 100, 1000, 700);
    window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    window.getContentPane().setLayout(new BorderLayout(0, 0));
    window.addWindowListener(new WindowAdapter() {
      @Override
      public void windowClosing(WindowEvent windowEvent) {
        super.windowClosing(windowEvent);
        map.dispose();
      }
    });
    return window;
  }

  /**
   * Creates a content pane.
   * @return a content pane.
   */
  private static JLayeredPane createContentPane() {
    JLayeredPane contentPane = new JLayeredPane();
    contentPane.setBounds(100, 100, 1000, 700);
    contentPane.setLayout(new BorderLayout(0, 0));
    contentPane.setVisible(true);
    return contentPane;
  }

  /**
   * Creates a progress bar.
   * @param parent progress bar's parent. The horizontal axis of the progress bar will be
   * center-aligned to the parent.
   * @return a progress bar.
   */
  private static JProgressBar createProgressBar(final JComponent parent) {
    final JProgressBar progressBar = new JProgressBar();
    progressBar.setSize(260, 20);
    parent.addComponentListener(new ComponentAdapter() {
      @Override
      public void componentResized(ComponentEvent e) {
        progressBar.setLocation(
            parent.getWidth()/2 - progressBar.getWidth()/2,
            parent.getHeight() - progressBar.getHeight() - 20);
      }
    });
    progressBar.setStringPainted(true);
    progressBar.setIndeterminate(true);
    return progressBar;
  }

  /**
   * Updates progress bar UI from Swing's Event Dispatch Thread.
   * @param str string to be set.
   * @param visible flag to indicate visibility of the progress bar.
   */
  private void updateProgressBarUI(final String str, final boolean visible) {
    SwingUtilities.invokeLater(new Runnable() {
      @Override
      public void run() {
        if (str != null) {
          progressBar.setString(str);
        }
        progressBar.setVisible(visible);
      }
    }); 
  }

  /**
   * Creates description UI component.
   * @return description.
   */
  private JTextArea createDescription() {
    JTextArea description = new JTextArea(
        "Left click on the map to create a point graphic and automatically " +
            "compute a buffer around the clicked point. Enter the desired buffer " +
        "distance in the box below. Right click to remove graphics.");
    description.setFont(new Font("Verdana", Font.PLAIN, 11));
    description.setForeground(Color.WHITE);
    description.setBackground(new Color(0, 0, 0, 180));
    description.setEditable(false);
    description.setLineWrap(true);
    description.setWrapStyleWord(true);
    description.setBorder(BorderFactory.createEmptyBorder(5,5,5,5));
    return description;
  }

  private String getPathSampleData() {
    String dataPath = null;
    String javaPath = ArcGISRuntime.getInstallDirectory();
    if (javaPath != null) {
      if (!(javaPath.endsWith("/") || javaPath.endsWith("\\"))){
        javaPath += FSP;
      }
      dataPath = javaPath + "sdk" + FSP + "samples" + FSP + "data" + FSP;
    }
    File dataFile = new File(dataPath);
    if (!dataFile.exists()) { 
      dataPath = ".." + FSP + "data" + FSP;
    }
    return dataPath;
  }
}
Feedback on this topic?