Geometric network trace

Download Sample Viewer

Description

The sample uses a geoprocessing package (.gpk) which contains a model involving the Trace Geometric Network (Data Management) geoprocessing tool to perform an upstream trace from the incident location to determine the affected water distribution mains and system valves. The geoprocessing package takes an input point (the incident location) and outputs two sets of features: affected mains, and affected valves. To use the sample, click on the map to draw a point, then press the 'Trace geometric network' button to run the task. The results for mains and valves will be added to the map as graphics.

Code snippet


    // create a geoprocessor
    Geoprocessor geoprocessor = new Geoprocessor(URL_GEOPROCESSING_SERVICE);
 
    // 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.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 javax.swing.BorderFactory;
import javax.swing.JButton;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JLayeredPane;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JProgressBar;
import javax.swing.JTextArea;
import javax.swing.SwingUtilities;
import javax.swing.border.LineBorder;

import com.esri.client.local.ArcGISLocalDynamicMapServiceLayer;
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.Geometry;
import com.esri.core.geometry.Geometry.Type;
import com.esri.core.geometry.GeometryEngine;
import com.esri.core.geometry.Point;
import com.esri.core.map.CallbackListener;
import com.esri.core.map.Graphic;
import com.esri.core.symbol.SimpleLineSymbol;
import com.esri.core.symbol.SimpleMarkerSymbol;
import com.esri.core.symbol.SimpleMarkerSymbol.Style;
import com.esri.core.symbol.Symbol;
import com.esri.core.tasks.ags.geoprocessing.GPFeatureRecordSetLayer;
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.runtime.ArcGISRuntime;

/**
 * The sample uses a geoprocessing package (.gpk) which contains a model 
 * involving the Trace Geometric Network (Data Management) geoprocessing 
 * tool to perform an upstream trace from the "incident location" 
 * to determine the affected water distribution mains and system valves.
 * <p>
 * The geoprocessing package takes an input point (the incident location) 
 * and outputs two sets of features: affected mains, and affected valves. 
 * <p>
 * To use the sample, click on the map to draw a point, then press the 
 * 'Trace geometric network' button to run the task. The results for 
 * mains and valves will be added to the map as graphics.
 */
public class LocalNetworkTraceApp {

  private JComponent contentPane;
  private LocalGeoprocessingService networkTraceService;
  private JMap map;
  private DrawingOverlay pointOverlay;
  private GraphicsLayer graphicsLayer;
  private Point point;
  private JProgressBar progressBar;

  private int PANEL_WIDTH = 270;
  private final String SERVICE_NAME = "TraceGeometricNetwork";
  private ArcGISLocalDynamicMapServiceLayer networkLayer;
  private static final String FSP = System.getProperty("file.separator");

  // symbology
  private static final SimpleMarkerSymbol SYM_POINT = new SimpleMarkerSymbol(Color.RED, 18, Style.CROSS);
  private static final SimpleMarkerSymbol SYM_VALVES = new SimpleMarkerSymbol(Color.BLUE, 15, Style.DIAMOND);
  private static final SimpleLineSymbol SYM_MAINS = new SimpleLineSymbol(Color.DARK_GRAY, 2.0f);

  // ------------------------------------------------------------------------
  // Constructor
  // ------------------------------------------------------------------------
  public LocalNetworkTraceApp() {

  }

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

  private void traceGeometricNetwork(Point userPoint) {

    updateProgressBarUI("Tracing affected mains and valves...", true);

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

    // 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 inputPoint = new GPFeatureRecordSetLayer("Flags");
    inputPoint.setGeometryType(Type.POINT);
    inputPoint.setSpatialReference(networkLayer.getDefaultSpatialReference());
    // add our user-drawn point to this input parameter
    Point projectedPoint = (Point) GeometryEngine.project(
        userPoint, map.getSpatialReference(), networkLayer.getDefaultSpatialReference());
    inputPoint.addGraphic(new Graphic(projectedPoint, SYM_POINT));

    parameters.add(inputPoint);

    // execute the geoprocessing request asynchronously

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

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

          @Override
          public void onCallback(GPParameter[] result) {
            updateProgressBarUI(null, false);
            if (result != null && result.length > 0) {
              processResult(result);
            } else {
              // no results - most likely because user clicked far away from the data
              JOptionPane.showMessageDialog(contentPane.getParent(),
                  "No results found. Try a different input point.",
                  "",
                  JOptionPane.ERROR_MESSAGE);
            }
          }
        }
        );
  }

  /**
   * Process result from geoprocessing execution.
   * @param result output of geoprocessing execution
   */
  private void processResult(GPParameter[] result) {
    Symbol symbol = null;
    int drawOrder = 0;
    for (GPParameter outputParameter : result) {
      // Note that the gpk output parameter details available at service endpoint
      if (outputParameter.getParamName().equals("Sysvalves_Layer")) {
        // Point geometry for valves
        symbol = SYM_VALVES;
        drawOrder = 2;
      } else if (outputParameter.getParamName().equals("DistribMains_Layer")) {
        // Polyline geometry for mains
        symbol = SYM_MAINS;
        drawOrder = 1;
      }
      GPFeatureRecordSetLayer gpLayer = (GPFeatureRecordSetLayer) outputParameter;
      for (Graphic graphic : gpLayer.getGraphics()) {
        // add the result graphics to the graphics layer, projecting back to our map SR first
        Geometry projectedGeometry = GeometryEngine.project(
            graphic.getGeometry(), networkLayer.getDefaultSpatialReference(), map.getSpatialReference());
        graphicsLayer.addGraphic(new Graphic(projectedGeometry, symbol, drawOrder));
      }
    }
  }

  // ------------------------------------------------------------------------
  // 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
          LocalNetworkTraceApp myApp = new LocalNetworkTraceApp();

          // create the UI, including the map, for the application
          JFrame appWindow = myApp.createWindow();
          appWindow.add(myApp.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 point
   * onto the map.
   * 
   * @return a map.
   */
  private JMap createMap() {

    final JMap jMap = new JMap();
    final LayerList layers = jMap.getLayers();

    // -----------------------------------------------------------------------------------------
    // Operational layer: local map package
    // -----------------------------------------------------------------------------------------
    networkLayer = new ArcGISLocalDynamicMapServiceLayer(
        getPathSampleData() + FSP + "mpks" + FSP + "WaterDistributionNetwork.mpk");
    layers.add(networkLayer);

    // -----------------------------------------------------------------------------------------
    // Graphics layer - to add user-drawn and result graphics
    // -----------------------------------------------------------------------------------------
    graphicsLayer = new GraphicsLayer();
    layers.add(graphicsLayer);

    // -----------------------------------------------------------------------------------------
    // Drawing overlay to draw an input point
    // -----------------------------------------------------------------------------------------
    pointOverlay = new DrawingOverlay();
    pointOverlay.setUp(DrawingMode.POINT, SYM_POINT, null);
    pointOverlay.setActive(false); // don't activate until local service started
    pointOverlay.addDrawingCompleteListener(new DrawingCompleteListener() {

      @Override
      public void drawingCompleted(DrawingCompleteEvent event) {
        // clear any previous graphics
        graphicsLayer.removeAll();
        // get and store the point geometry drawn
        point = (Point) pointOverlay.getAndClearFeature().getGeometry();
        // add point graphic
        graphicsLayer.addGraphic(new Graphic(point, SYM_POINT));
      }
    });
    jMap.addMapOverlay(pointOverlay);

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

      @Override
      public void localServiceStartComplete(LocalServiceStartCompleteEvent arg0) {
        // enable our map overlay and hide progress bar
        pointOverlay.setActive(true);
        updateProgressBarUI(null, false);
      }
    });
    // start the service asynchronously
    updateProgressBarUI("Starting geoprocessing service...", true);
    networkTraceService.startAsync();

    return jMap;
  }

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

    // create description
    JTextArea description = createDescription();

    // button panel
    Dimension preferredSize = new Dimension(PANEL_WIDTH, 30);
    final JButton btnExecute = new JButton("Trace geometric network");
    btnExecute.setMinimumSize(preferredSize);
    btnExecute.setPreferredSize(preferredSize);
    btnExecute.addActionListener(new ActionListener() {
      @Override
      public void actionPerformed(ActionEvent e) {
        if (point != null) {
          traceGeometricNetwork(point);
        }
      }
    });

    // the container panel for everything
    JPanel panel = new JPanel();
    panel.setLayout(new BorderLayout(0, 0));
    panel.setLocation(10, 10);
    panel.setSize(PANEL_WIDTH, 180);
    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(btnExecute, BorderLayout.SOUTH);

    return panel;
  }

  /**
   * Creates the application window.
   * @return a window.
   */
  private JFrame createWindow() {
    JFrame window = new JFrame("Trace Geometric Network geoprocessing application");
    window.setBounds(0, 0, 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);
        if (map != null) {
          map.dispose();
        }
      }
    });
    return window;
  }

  /**
   * Creates a layered content pane.
   * @return a content pane.
   */
  private static JLayeredPane createContentPane() {
    JLayeredPane contentPane = new JLayeredPane();
    contentPane.setBounds(0, 0, 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 the 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 a description UI component.
   * @return the description.
   */
  private JTextArea createDescription() {
    JTextArea description = new JTextArea(
        "Click on the map to add an incident point, then click on the 'Trace " +
            "geometric network' button to execute a geoprocessing task. The task " +
            "will perform an upstream network trace on the geometric network " +
            "and return affected mains and valves. These will be displayed on the " +
        "map as 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,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?