Difference

Download Sample Viewer

Description

This application shows how to compute the difference of two polygons. The first polygon is drawn on the map programmatically, and the second polygon is drawn by the user which is implemented using a Map Overlay to handle mouse events. The 'difference' operation is then performed (with the drawn polygon substracted from the original polygon) and the resulting graphic is shown on the map. This application uses the static method GeometryEngine.difference which returns the Geometry object resulting from the difference between two Geometry objects.

Code snippet


    // get the difference (polygon1 - polygon2)
    Geometry difference = GeometryEngine.difference(
        polygon1, polygon2, jMap.getSpatialReference()); 
 
    // show the resulting geometry on the map
    Graphic graphic = new Graphic(difference, SYM_FILL_DIFF); 
    graphicsLayer.addGraphic(graphic);
  

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.geometry;

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.io.File;

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.JLayeredPane;
import javax.swing.JPanel;
import javax.swing.JTextArea;
import javax.swing.SwingUtilities;
import javax.swing.border.LineBorder;

import com.esri.client.local.ArcGISLocalTiledLayer;
import com.esri.core.geometry.Envelope;
import com.esri.core.geometry.Geometry;
import com.esri.core.geometry.GeometryEngine;
import com.esri.core.geometry.Polygon;
import com.esri.core.geometry.SpatialReference;
import com.esri.core.map.Graphic;
import com.esri.core.symbol.SimpleFillSymbol;
import com.esri.core.symbol.SimpleLineSymbol;
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;
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;

/**
 * This application shows how to compute the difference of two polygons.
 * The first polygon is drawn on the map programmatically, and the
 * second polygon is drawn by the user using a {@link DrawingOverlay}
 * set up in polygon drawing mode.
 * <p>
 * The 'difference' operation is then performed (with the drawn polygon
 * substracted from the original polygon) and the resulting graphic is
 * shown on the map.  This application uses the static method
 * <code>GeometryEngine.difference</code> which returns the <code>Geometry</code>
 * object resulting from the difference between two <code>Geometry</code>
 * objects.
 */
public class DifferenceApp {

  // symbology
  private final static SimpleLineSymbol SYM_LINE =
      new SimpleLineSymbol(new Color(200, 0, 0), 2);
  private final static SimpleFillSymbol SYM_FILL =
      new SimpleFillSymbol(new Color(200, 0, 0, 120), SYM_LINE);
  private final static SimpleFillSymbol SYM_FILL_DIFF =
      new SimpleFillSymbol(new Color(0, 0, 200, 120), new SimpleLineSymbol(new Color(0, 0, 200), 2));

  // components
  private JMap map;
  private GraphicsLayer graphicsLayer;
  private Polygon shape1; // drawn by default at start
  private Polygon shape2; // drawn by user
  private DrawingOverlay polygonOverlay; // for drawing polygons

  private static final int PANEL_WIDTH = 270;
  private static final Color BG_COLOR = new Color(0, 0, 0, 60);
  private String FSP = System.getProperty("file.separator");
  // the spatial reference of the map, defined by the base layer used
  private SpatialReference srMap;
  // define the spatial reference of our points here for simplicity, WGS84
  private static SpatialReference wgs84 = SpatialReference.create(4326);

  // ------------------------------------------------------------------------
  // Constructor
  // ------------------------------------------------------------------------
  public DifferenceApp() {
  }

  // ------------------------------------------------------------------------
  // Core functionality
  // ------------------------------------------------------------------------
  private void computeDifference(Polygon polygon1, Polygon polygon2) {
    Geometry difference = GeometryEngine.difference(polygon1, polygon2, srMap);

    Graphic graphic = new Graphic(difference, SYM_FILL_DIFF);
    graphicsLayer.addGraphic(graphic);
  }

  /**
   * Creates the map, adding to it a base layer, a graphics layer, and a
   * map overlay enabling the user to draw polygons.
   * @return a map.
   */
  private JMap createMap() throws Exception {
    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);

    // -----------------------------------------------------------------------------------------
    // Graphics Layer - to add polygon graphics to
    // -----------------------------------------------------------------------------------------
    graphicsLayer = new GraphicsLayer();
    layers.add(graphicsLayer);

    // -----------------------------------------------------------------------------------------
    // Drawing Overlay - set up in polygon drawing mode
    // -----------------------------------------------------------------------------------------
    polygonOverlay = new DrawingOverlay();
    polygonOverlay.setUp(DrawingMode.POLYGON, SYM_FILL, null);
    polygonOverlay.addDrawingCompleteListener(new DrawingCompleteListener() {

      @Override
      public void drawingCompleted(DrawingCompleteEvent arg0) {
        // get the graphic
        Graphic graphic = (Graphic) polygonOverlay.getAndClearFeature();
        // add graphic to our map's graphics layer
        graphicsLayer.addGraphic(graphic);
        // store the geometry for the computation
        shape2 = (Polygon) graphic.getGeometry();
        // deactivate overlay so user can only draw one polygon at a time
        polygonOverlay.setActive(false);
      }
    });
    jMap.addMapOverlay(polygonOverlay);
    // activate the overlay to enable the default 'pan tolerance'
    polygonOverlay.setActive(true);

    // set extent to Europe and get spatial reference
    jMap.setExtent(new Envelope(-3054370, 2633000, 6553460, 9041460));

    // store the map's spatial reference once the map is ready, then add the initial polygon
    jMap.addMapEventListener(new MapEventListenerAdapter() {
      @Override
      public void mapReady(final MapEvent mapEvent) {
        SwingUtilities.invokeLater(new Runnable() {
          @Override
          public void run() {
            srMap = mapEvent.getMap().getSpatialReference();
            addFirstPolygon();
          }
        });
      }
    });

    return jMap;
  }

  // ------------------------------------------------------------------------
  // 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
          DifferenceApp differenceApp = new DifferenceApp();

          // create the UI, including the map, for the application.
          JFrame appWindow = differenceApp.createWindow();
          appWindow.add(differenceApp.createUI());
          appWindow.setVisible(true);
        } catch (Exception e) {
          // on any error, display the stack trace.
          e.printStackTrace();
        }
      }
    });
  }

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

    // application content
    JLayeredPane contentPane = createContentPane();

    // map
    map = createMap();

    // user panel
    JPanel panel = createUserPanel();

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

    return contentPane;
  }

  // ------------------------------------------------------------------------
  // Private methods
  // ------------------------------------------------------------------------
  private void addFirstPolygon() {
    Polygon polygon1 = new Polygon();
    polygon1.startPath(25, 52);
    polygon1.lineTo(25, 59);
    polygon1.lineTo(40, 59);
    polygon1.lineTo(40, 48);
    polygon1.closePathWithLine();

    // project polygon to our map's spatial reference
    shape1 = (Polygon) GeometryEngine.project(polygon1, wgs84, srMap);
    Graphic graphic = new Graphic(shape1, SYM_FILL);
    graphicsLayer.addGraphic(graphic);
  }

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

    // description
    JTextArea description = createDescription();

    // buttons
    Dimension buttonDim = new Dimension(PANEL_WIDTH, 30);

    // button panel
    final JButton btnDiff = new JButton("Compute and show difference");
    btnDiff.setMinimumSize(buttonDim);
    btnDiff.setMaximumSize(buttonDim);
    btnDiff.addActionListener(new ActionListener() {
      @Override
      public void actionPerformed(ActionEvent e) {
        if (shape2 != null) {
          computeDifference(shape1, shape2);
          shape2 = null;
        }
      }
    });

    final JButton btnReset = new JButton("Reset");
    btnReset.setMinimumSize(buttonDim);
    btnReset.setMaximumSize(buttonDim);
    btnReset.addActionListener(new ActionListener() {
      @Override
      public void actionPerformed(ActionEvent e) {
        graphicsLayer.removeAll();
        addFirstPolygon();
        shape2 = null;
        polygonOverlay.setActive(true); // reactivate the overlay
      }
    });

    // button panel
    JPanel buttonPanel = new JPanel();
    buttonPanel.setBackground(BG_COLOR);
    buttonPanel.setLayout(new BoxLayout(buttonPanel, BoxLayout.Y_AXIS));
    buttonPanel.add(Box.createRigidArea(new Dimension(0, 5)));
    buttonPanel.add(btnDiff);
    buttonPanel.add(Box.createRigidArea(new Dimension(0, 5)));
    buttonPanel.add(btnReset);

    JPanel panel = new JPanel();
    panel.setLayout(new BorderLayout(0, 0));
    panel.setLocation(10, 10);
    panel.setSize(PANEL_WIDTH, 210);
    panel.setBackground(new Color(0, 0, 0, 0));
    panel.setBorder(new LineBorder(BG_COLOR, 5, false));

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

    return panel;
  }

  /**
   * Creates a window.
   * @return a window.
   */
  private JFrame createWindow() {
    JFrame window = new JFrame();
    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 description for this application.
   * @return description
   */
  private JTextArea createDescription() {
    JTextArea description = new JTextArea(
        "Draw a second polygon on the map via left clicks of the mouse, double-clicking " +
            "to complete the polygon. Click the button below to compute the 'difference' operation " +
            "and show the resulting geometry on the map. Click the " +
        "'reset' button to clear the drawn polygon and start over.");
    description.setFont(new Font("Verdana", Font.PLAIN, 11));
    description.setForeground(Color.WHITE);
    description.setEditable(false);
    description.setLineWrap(true);
    description.setWrapStyleWord(true);
    description.setBackground(new Color(0, 0, 0, 180));
    description.setBorder(BorderFactory.createEmptyBorder(5,10,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?