Clip features

Download Sample Viewer

Description

This sample demonstrates the use of a Local Geoprocessing Service to clip US county polygons. A local geoprocessing package (.gpk) is used to start a local geoprocessing service which takes an input distance and an input geometry. On execution, the geometry (polyline) is buffered by the input distance and the service returns polygons of US counties clipped by this buffered geometry. To use the sample, left click on the map to draw a polyline, double-click to complete the polyline, then click the execute button to run the buffer and clip task. The resulting polygon graphics will be added to the map in a graphics layer.

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.Component;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.ComponentAdapter;
import java.awt.event.ComponentEvent;
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.Box;
import javax.swing.BoxLayout;
import javax.swing.JButton;
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.ArcGISLocalTiledLayer;
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.toolkit.overlays.DrawingCompleteEvent;
import com.esri.toolkit.overlays.DrawingCompleteListener;
import com.esri.toolkit.overlays.DrawingOverlay;
import com.esri.toolkit.overlays.DrawingOverlay.DrawingMode;
import com.esri.core.geometry.Envelope;
import com.esri.core.geometry.Geometry.Type;
import com.esri.core.geometry.Polyline;
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.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.GraphicsLayer;
import com.esri.map.JMap;
import com.esri.map.LayerList;
import com.esri.map.MapEvent;
import com.esri.map.MapEventListenerAdapter;
import com.esri.runtime.ArcGISRuntime;

/**
 * This sample demonstrates the use of a Local Geoprocessing Service
 * to clip US county polygons.  A local geoprocessing package (.gpk)
 * is used to start a local geoprocessing service which takes an
 * input distance and an input geometry.  On execution, the geometry
 * (polyline) is buffered by the input distance and the service
 * returns polygons of US counties clipped by this buffered geometry.
 * <p>
 * To use the sample, left click on the map to draw a polyline,
 * double-click to complete the polyline, then click the execute
 * button to run the buffer and clip task. The resulting polygon
 * graphics will be added to the map in a graphics layer.
 */
public class LocalClipFeaturesApp {

  private JComponent contentPane;
  private LocalGeoprocessingService clipFeaturesService;
  private JTextField distanceInput;
  private JMap map;
  private DrawingOverlay polylineOverlay;
  private SpatialReference srMap;
  private GraphicsLayer resultGraphicsLayer;
  private Polyline line;
  private JProgressBar progressBar;
  private AtomicInteger tasksInProgress = new AtomicInteger(0);

  private int PANEL_WIDTH = 250;
  private final String SERVICE_NAME = "ClipFeatures";
  private static final String DEFAULT_BUFFER_DISTANCE = "100";
  private static final String FSP = System.getProperty("file.separator");
  private final static SimpleLineSymbol SYM_LINE =
      new SimpleLineSymbol(new Color(200, 0, 0), 2);
  private final static SimpleFillSymbol SYM_FILL =
      new SimpleFillSymbol(new Color(0, 0, 200, 120), new SimpleLineSymbol(new Color(0, 0, 200), 2));

  // ------------------------------------------------------------------------
  // Constructor
  // ------------------------------------------------------------------------
  public LocalClipFeaturesApp() {

  }

  // ------------------------------------------------------------------------
  // Core functionality
  // ------------------------------------------------------------------------

  private void executeClipFeatures(Polyline polyline, double distance) {

    tasksInProgress.incrementAndGet();
    updateProgressBarUI("Clipping features...", true);

    // create a Geoprocessor that points to the geoprocessing service URL
    Geoprocessor geoprocessor = new Geoprocessor(clipFeaturesService.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 inputPolyline = new GPFeatureRecordSetLayer("Input");
    inputPolyline.setGeometryType(Type.POLYLINE);
    inputPolyline.setSpatialReference(map.getSpatialReference());
    // add our user-drawn polyline to this input parameter
    inputPolyline.addGraphic(new Graphic(polyline, SYM_LINE));

    GPLinearUnit linearUnit = new GPLinearUnit("Linear_Unit");
    linearUnit.setUnits("esriMiles");
    linearUnit.setDistance(distance);

    parameters.add(inputPolyline);
    parameters.add(linearUnit);

    // 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(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) {
    // get image via URL from service result
    for (GPParameter outputParameter : result) {
      if (outputParameter instanceof GPFeatureRecordSetLayer) {
        GPFeatureRecordSetLayer gpLayer = (GPFeatureRecordSetLayer) outputParameter;
        for (Graphic graphic : gpLayer.getGraphics()) {
          // add the graphics to the result graphics layer
          resultGraphicsLayer.addGraphic(new Graphic(graphic.getGeometry(), SYM_FILL));
        }
      }
    }
  }

  // ------------------------------------------------------------------------
  // 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
          LocalClipFeaturesApp clipFeaturesApp = new LocalClipFeaturesApp();

          // create the UI, including the map, for the application
          JFrame appWindow = clipFeaturesApp.createWindow();
          appWindow.add(clipFeaturesApp.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 a map, sets the initial extent when the map is ready,
   * adds a DrawingOverlay to enable the user to draw a polyline
   * onto the map and get the drawn Geometry back.
   * @return a map.
   */
  private JMap createMap() {

    final JMap jMap = new JMap();
    // -----------------------------------------------------------------------------------------
    // Base Layer: local tile package
    // -----------------------------------------------------------------------------------------
    final ArcGISLocalTiledLayer tiledLayer = new ArcGISLocalTiledLayer(getPathSampleData() + "tpks" + FSP + "Topographic.tpk");
    LayerList layers = jMap.getLayers();
    layers.add(tiledLayer);

    // set the initial extent
    jMap.setExtent(new Envelope(-15000000, 2000000, -7000000, 8000000));

    // 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 = mapEvent.getMap().getSpatialReference();
          }
        });
      }
    });

    // -----------------------------------------------------------------------------------------
    // graphics layer - to add clip result graphics
    // -----------------------------------------------------------------------------------------
    resultGraphicsLayer = new GraphicsLayer();
    layers.add(resultGraphicsLayer);

    // -----------------------------------------------------------------------------------------
    // overlay to draw a polyline and return the drawn geometry
    // -----------------------------------------------------------------------------------------
    polylineOverlay = new DrawingOverlay();
    polylineOverlay.setUp(DrawingMode.POLYLINE, SYM_LINE, null);
    polylineOverlay.setActive(false); // don't activate until local service started
    polylineOverlay.addDrawingCompleteListener(new DrawingCompleteListener() {

      @Override
      public void drawingCompleted(DrawingCompleteEvent arg0) {
        // get and store the polyline geometry
        line = (Polyline) polylineOverlay.getFeature().getGeometry();
      }
    });
    jMap.addMapOverlay(polylineOverlay);

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

      @Override
      public void localServiceStartComplete(LocalServiceStartCompleteEvent arg0) {
        // enable our map overlay which responds to button clicks
        polylineOverlay.setActive(true);
        updateProgressBarUI(null, false);
      }
    });
    // start the service asynchronously
    updateProgressBarUI("Starting geoprocessing service...", true);
    clipFeaturesService.startAsync();

    return jMap;
  }

  private double getInputDistance() {

    double distance = Double.parseDouble(distanceInput.getText());
    if (distance > 300 || distance < 10) {
      JOptionPane.showMessageDialog(contentPane,
          "Please enter a value from 10 to 300.", "", JOptionPane.WARNING_MESSAGE);
      return 0;
    }
    return distance;
  }

  /**
   * 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 (miles): ");
    lblDistance.setForeground(Color.BLACK);
    lblDistance.setFont(new Font("Verdana", Font.BOLD, 12));
    lblDistance.setMaximumSize(new Dimension(130, 20));

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

    // button panel
    Dimension preferredSize = new Dimension(PANEL_WIDTH, 30);
    final JButton btnExecute = new JButton("Execute buffer and clip");
    btnExecute.setMinimumSize(preferredSize);
    btnExecute.setPreferredSize(preferredSize);
    btnExecute.addActionListener(new ActionListener() {
      @Override
      public void actionPerformed(ActionEvent e) {
        double distance = getInputDistance();
        if (distance > 0 && line != null) {
          executeClipFeatures(line, distance);
        }
      }
    });

    final JButton btnClear = new JButton("Clear county graphics");
    btnClear.setMinimumSize(preferredSize);
    btnClear.setPreferredSize(preferredSize);
    btnClear.addActionListener(new ActionListener() {
      @Override
      public void actionPerformed(ActionEvent e) {
        resultGraphicsLayer.removeAll(); // clear result graphics
        polylineOverlay.clearFeature(); // clear polyline feature
        line = null;
      }
    });

    final JPanel btnPanel = new JPanel();
    btnPanel.setLayout(new BorderLayout());
    btnPanel.add(btnExecute, BorderLayout.NORTH);
    btnPanel.add(btnClear, BorderLayout.SOUTH);
    btnPanel.setBorder(null);
    btnPanel.setAlignmentX(Component.CENTER_ALIGNMENT);

    // group the above UI items into a panel
    final JPanel inputPanel = new JPanel();
    BoxLayout boxLayout = new BoxLayout(inputPanel, BoxLayout.X_AXIS);
    inputPanel.setLayout(boxLayout);
    inputPanel.setPreferredSize(preferredSize);
    inputPanel.setBorder(BorderFactory.createEmptyBorder(2,5,2,5));
    inputPanel.setBackground(new Color(255, 255, 255, 255));
    inputPanel.add(Box.createRigidArea(new Dimension(20, 0)));
    inputPanel.add(lblDistance);
    inputPanel.add(Box.createRigidArea(new Dimension(10, 0)));
    inputPanel.add(distanceInput);

    final JPanel userPanel = new JPanel();
    userPanel.setSize(PANEL_WIDTH, 90);
    userPanel.setLayout(new BorderLayout());
    userPanel.add(inputPanel, BorderLayout.CENTER);
    userPanel.add(btnPanel, BorderLayout.SOUTH);

    // the container panel for everything
    JPanel panel = new JPanel();
    panel.setLayout(new BorderLayout(0, 0));
    panel.setLocation(10, 10);
    panel.setSize(PANEL_WIDTH, 230);
    panel.setBackground(new Color(0, 0, 0, 0));
    panel.setBorder(new LineBorder(new Color(0, 0, 0, 60), 5, false));

    panel.add(description, BorderLayout.CENTER);
    panel.add(userPanel, BorderLayout.SOUTH);

    return panel;
  }

  /**
   * Creates a window.
   * @return a window.
   */
  private JFrame createWindow() {
    JFrame window = new JFrame("Clip USA Counties from Polyline 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 the 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 polyline; double-click to complete " +
            "the polyline. Click on the execute button to buffer the polyline " +
            "and clip US county polygons by this buffer. The resulting county " +
            "graphics will display on the map. Enter the desired buffer distance " +
        "in the box below.");
    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,10,5,10));
    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?