Union

Download Sample Viewer

Description

This application does a union of two or more polygons. Polygons that are spatially disparate can also be combined into one logical polygon. To select/de-select a parcel, click on it. To do a union on the selected parcels, click on the Union button. Note that this application does not write back to the server.

Code snippet


    // do the union of the selected geometries
    Geometry unionGeometry = GeometryEngine.union(
        selectedGeometries, jMap.getSpatialReference());

    // add the union result to the graphics layer
    Graphic unionGraphic = new Graphic(unionGeometry, SYM_PARCEL_UNSELECTED);
    graphicsLayer.addGraphic(unionGraphic);
  

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.Font;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.util.Iterator;
import java.util.List;

import javax.swing.BorderFactory;
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.toolkit.overlays.HitTestEvent;
import com.esri.toolkit.overlays.HitTestListener;
import com.esri.toolkit.overlays.HitTestOverlay;
import com.esri.core.geometry.Envelope;
import com.esri.core.geometry.Geometry;
import com.esri.core.geometry.GeometryEngine;
import com.esri.core.map.Feature;
import com.esri.core.map.FeatureResult;
import com.esri.core.map.Graphic;
import com.esri.core.symbol.SimpleFillSymbol;
import com.esri.core.symbol.SimpleLineSymbol;
import com.esri.core.tasks.query.QueryParameters;
import com.esri.core.tasks.query.QueryTask;
import com.esri.map.ArcGISTiledMapServiceLayer;
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;

/**
 * This application unions two or more polygons. Polygons that are spatially
 * disjoint can also be combined into one logical polygon.
 * <p>
 * To select/de-select a parcel, click on it. To union the selected parcels,
 * click on the Union button. Note that this application does not write back to
 * the server.
 */
public class UnionApp {

  // symbology
  final static SimpleLineSymbol SYM_PARCEL_BORDER = new SimpleLineSymbol(Color.RED, 1);
  final static SimpleFillSymbol SYM_PARCEL =
      new SimpleFillSymbol(new Color(0, 0, 255, 80), SYM_PARCEL_BORDER);
  
  private static final int PANEL_WIDTH = 260;

  // JMap
  private JMap map;

  // resources
  final String URL_USA_TOPO =
      "http://services.arcgisonline.com/ArcGIS/rest/services/ESRI_StreetMap_World_2D/MapServer";
  final String URL_TAX_PARCELS =
      "http://sampleserver1.arcgisonline.com/ArcGIS/rest/services/TaxParcel/AssessorsParcelCharacteristics/MapServer/1";

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

  // ------------------------------------------------------------------------
  // Core functionality
  // ------------------------------------------------------------------------
  /**
   * This method unions two or more geometries that are selected in the graphics layer.
   * The result of the union is another geometry that is added back to the graphics layer, after
   * removing the original geometries.
   * @param jMap Map to get the spatial reference of the geometries.
   * @param graphicsLayer Layer that has the selected graphics. The result of union will be
   * added to this.
   */
  private void doUnion(JMap jMap, GraphicsLayer graphicsLayer) {

    int[] selectedIDs = graphicsLayer.getSelectionIDs();
    // if there are less than 2 selected graphics, there is no need to perform a union
    if (selectedIDs.length < 2) {
      return;
    }

    Geometry[] selectedGeometries = new Geometry[selectedIDs.length];

    // get a list of selected geometries
    int i = 0;
    for (int id : selectedIDs) {
      // add it to the selected collection
      selectedGeometries[i] = graphicsLayer.getGraphic(id).getGeometry();
      i++;
    }

    // union the selected geometries
    Geometry unionGeometry = GeometryEngine.union(selectedGeometries, jMap.getSpatialReference());
    // add the union result to the graphics layer
    Graphic unionGraphic = new Graphic(unionGeometry, SYM_PARCEL);
    graphicsLayer.addGraphic(unionGraphic);
    // remove the original graphics from the graphics layer
    for (int id : selectedIDs) {
      graphicsLayer.removeGraphic(id);
    }
  }

  // ------------------------------------------------------------------------
  // 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
          UnionApp unionApp = new UnionApp();

          // create the UI, including the map, for the application.
          JFrame appWindow = unionApp.createWindow();
          appWindow.add(unionApp.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
    JComponent contentPane = createContentPane();

    // union button
    JButton btnUnion = new JButton("Perform Union");

    // user panel
    JPanel panel = createUserPanel(btnUnion);

    // map
    map = createMap(btnUnion);

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

    return contentPane;
  }

  // ------------------------------------------------------------------------
  // Private methods
  // ------------------------------------------------------------------------

  /**
   * Creates a map.
   * @return a map.
   */
  private JMap createMap(JButton button) throws Exception {

    final JMap jMap = new JMap();
    // -----------------------------------------------------------------------------------------
    // Base Layer - with US topology, focus on U.S by default
    // -----------------------------------------------------------------------------------------
    final ArcGISTiledMapServiceLayer baseLayer = new ArcGISTiledMapServiceLayer(URL_USA_TOPO);
    LayerList layers = jMap.getLayers();
    layers.add(baseLayer);

    // -----------------------------------------------------------------------------------------
    // Graphics Layer with the parcel graphics
    // -----------------------------------------------------------------------------------------
    final GraphicsLayer graphicsLayer = new GraphicsLayer();
    layers.add(graphicsLayer);

    jMap.addMapEventListener(new MapInitializer(graphicsLayer));

    // -----------------------------------------------------------------------------------------
    // Map overlay - to select a graphic on a mouse-click
    // -----------------------------------------------------------------------------------------
    HitTestListener listener = new  GraphicSelectedListener();
    final HitTestOverlay selectionOverlay = new HitTestOverlay(graphicsLayer, listener);
    jMap.addMapOverlay(selectionOverlay);

    // "Union" button listener - do a union on click
    button.addActionListener(new ActionListener() {
      @Override
      public void actionPerformed(ActionEvent e) {
        doUnion(jMap, graphicsLayer);
      }
    });

    return jMap;
  }

  /**
   * Creates a description for this application.
   * @return description
   */
  private JTextArea createDescription() {
    JTextArea description = new JTextArea("Click on a parcel to select or deselect it. " +
        "Click the Union button to join the selected parcels. The union of spatially " +
        "disparate parcels is allowed.");
    description.setFont(new Font("Verdana", Font.PLAIN, 11));
    description.setForeground(Color.WHITE);
    description.setBackground(new Color(0, 0, 0, 180));
    description.setBorder(BorderFactory.createEmptyBorder(5,10,5,5));
    description.setEditable(false);
    description.setWrapStyleWord(true);
    description.setLineWrap(true);
    return description;
  }

  /**
   * Class to initialize the map with required parcels.
   */
  class MapInitializer extends MapEventListenerAdapter {

    // graphics layer to add parcels
    GraphicsLayer graphicsLayer = null;
    // limit the editing to a certain area
    Envelope initialExtent = new Envelope(-83.3188,42.6142,-83.3129,42.6167);

    /**
     * Constructor
     * @param graphicsLayer layer to which the parcels will be added to.
     */
    MapInitializer(GraphicsLayer graphicsLayer) {
      this.graphicsLayer = graphicsLayer;
    }

    @Override
    public void mapReady(final MapEvent mapEvent) {
      SwingUtilities.invokeLater(new Runnable() {
        @Override
        public void run() {
          mapEvent.getMap().setExtent(initialExtent);
          initializeParcels();
        }
      });

    }

    /**
     * Initialize the graphics layer with parcels so that they can be selected.
     */
    private void initializeParcels() {
      // set a selection symbol on the graphics layer
      graphicsLayer.setSelectionColor(Color.YELLOW);
      // select all records in the initial extent.
      QueryParameters queryParams = new QueryParameters();
      queryParams.setGeometry(initialExtent);
      queryParams.setSpatialRelationship(com.esri.core.tasks.SpatialRelationship.INTERSECTS);

      try {
        // execute the query.
        QueryTask task = new QueryTask(URL_TAX_PARCELS);
        FeatureResult queryResult = task.execute(queryParams);

        // add the query result to the graphics layer.
        Iterator<Object> it = queryResult.iterator();
        while (it.hasNext()) {
          Object object = it.next();
          if (object instanceof Feature) {
            Graphic dispGraphic = new Graphic(((Feature) object).getGeometry(), SYM_PARCEL);
            graphicsLayer.addGraphic(dispGraphic);
          }
        }
      } catch (Exception ex) {
        ex.printStackTrace();
      }
    }
  }

  class GraphicSelectedListener implements HitTestListener {

    @Override
    public void featureHit(HitTestEvent event) {
      HitTestOverlay overlay = (HitTestOverlay) event.getSource();
      List<Feature> hitFeatures = overlay.getHitFeatures();
      GraphicsLayer graphicsLayer = (GraphicsLayer) overlay.getLayer();
      //select or de-select each hit graphic
      for (Feature feature : hitFeatures) {
        if (graphicsLayer.isGraphicSelected((int) feature.getId())) {
          graphicsLayer.unselect((int) feature.getId());
        }
        else {
          graphicsLayer.select((int) feature.getId());
        }
      }
    }
  }

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

    // description
    JTextArea description = createDescription();

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

    // group description and input in a panel
    panel.add(description, BorderLayout.CENTER);
    panel.add(button, 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.setLayout(new BorderLayout(0, 0));
    contentPane.setVisible(true);
    return contentPane;
  }
}
Feedback on this topic?