Line length

Download Sample Viewer

Description

The purpose of this application is to measure the length of a line. The user can draw a polyline via left-clicks of mouse, and the application will calculate the total length of the polyline. The user can then right-click to start over. The length of the line is calculated using the static method GeometryEngine.geodesicLength(), and the output is in miles, which, in this application, is different from the units used by the map itself.

Code snippet


    // add length of latest line segment to the total.
    totalLength += GeometryEngine.geodesicLength(
        polyline,
        jMap.getSpatialReference(),
        (LinearUnit) LinearUnit.create(LinearUnit.Code.MILE_STATUTE));
  

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.event.MouseEvent;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.text.DecimalFormat;

import javax.swing.BorderFactory;
import javax.swing.BoxLayout;
import javax.swing.JComponent;
import javax.swing.JEditorPane;
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.core.geometry.Envelope;
import com.esri.core.geometry.GeometryEngine;
import com.esri.core.geometry.LinearUnit;
import com.esri.core.geometry.Point;
import com.esri.core.geometry.Polyline;
import com.esri.core.geometry.Unit;
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.map.ArcGISTiledMapServiceLayer;
import com.esri.map.GraphicsLayer;
import com.esri.map.JMap;
import com.esri.map.LayerList;
import com.esri.map.MapOverlay;

/**
 * The purpose of this application is to measure the length of a line. To use this 
 * application, draw a line via left-clicks of mouse, and as you click to add a new 
 * line segment, the application will calculate the total length of the line. 
 * Right-click to start over.
 * <p>
 * The length of the line is calculated using <code>GeometryEngine.geodesicLength()</code>, 
 * and the output is in miles, which, in this application, is different from the units 
 * used by the map itself.
 */
public class LineLengthApp {

  // symbology
  private final static SimpleLineSymbol SYM_LINE   = new SimpleLineSymbol(Color.RED, 2);
  private final static SimpleMarkerSymbol SYM_CITY =
      new SimpleMarkerSymbol(new Color(200, 0, 0, 200), 8, Style.CIRCLE);

  // resources
  private final String URL_USA_TOPO =
      "http://services.arcgisonline.com/ArcGIS/rest/services/ESRI_StreetMap_World_2D/MapServer";

  // JMap
  private JMap map;

  // graphics layer
  private GraphicsLayer graphicsLayer;

  // format to display result
  private final static DecimalFormat resultFormat = new DecimalFormat("##,###.##");

  // ------------------------------------------------------------------------
  // Constructors
  // ------------------------------------------------------------------------
  public LineLengthApp() {
  }

  // ------------------------------------------------------------------------
  // Core functionality
  // ------------------------------------------------------------------------
  /**
   * Map overlay to handle mouse-clicks.
   */
  class UserCommandOverlay extends MapOverlay {

    private static final long serialVersionUID = 1L;
    // map
    JMap jMap;
    // graphics layer required to add new graphics
    GraphicsLayer myGraphicsLayer;
    // UI where the result will be displayed
    JEditorPane resultBox;
    // previous clicked point
    Point prevPoint;
    // total length of all the lines created so far
    double totalLength = 0.0;

    /**
     * Constructor
     * @param jMap JMap to which this overlay belongs.
     * @param graphicsLayer graphics layer on the map.
     * @param resultBox UI where the result will be displayed.
     */
    UserCommandOverlay(JMap jMap, GraphicsLayer graphicsLayer, JEditorPane resultBox) {
      this.jMap = jMap;
      this.myGraphicsLayer = graphicsLayer;
      this.resultBox = resultBox;
    }

    /**
     * Handle mouse-clicks.
     * On left-click, create a line from previous point to current, get its geodesic length,
     * then add it to the the total length.
     * On right-click, start over.
     */
    @Override
    public void onMouseClicked(MouseEvent event) {

      if (event.getButton() == MouseEvent.BUTTON1) {

        // show point clicked
        Point currPoint = jMap.toMapPoint(event.getX(), event.getY());
        Graphic currPointGraphic = new Graphic(currPoint, LineLengthApp.SYM_CITY);
        myGraphicsLayer.addGraphic(currPointGraphic);

        // on left-click, add length of current line to the total length
        if (prevPoint != null) {

          Polyline polyline = new Polyline();
          polyline.startPath(prevPoint);
          polyline.lineTo(currPoint);

          // show the new line by adding it to the graphics layer.
          Graphic polylineGraphic = new Graphic(polyline, LineLengthApp.SYM_LINE);
          myGraphicsLayer.addGraphic(polylineGraphic);

          // add length of current line to the total.
          totalLength += GeometryEngine.geodesicLength(
              polyline,
              jMap.getSpatialReference(),
              (LinearUnit) Unit.create(LinearUnit.Code.MILE_STATUTE));
        }

        prevPoint = currPoint;
      } else if (event.getButton() == MouseEvent.BUTTON3) {
        // on right-click, reset to start over.
        totalLength = 0.0;
        prevPoint = null;
        myGraphicsLayer.removeAll();
      }
      resultBox.setText(
          "Total length: " + LineLengthApp.resultFormat.format(totalLength) + " miles.");
    }
  }

  // ------------------------------------------------------------------------
  // 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
          LineLengthApp lineLengthApp = new LineLengthApp();

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

    // description
    JTextArea description = createDescription();

    // result
    JEditorPane resultBox = createResultBox();

    // description and result UI component
    final JPanel panel = new JPanel();
    BoxLayout boxLayout = new BoxLayout(panel, BoxLayout.Y_AXIS);
    panel.setLayout(boxLayout);
    panel.setLocation(10, 10);
    panel.setSize(320, 130);
    panel.setBackground(new Color(0, 0, 0, 80));
    panel.setDoubleBuffered(true);
    panel.setBorder(new LineBorder(Color.BLACK, 3));

    panel.add(description);
    panel.add(resultBox);

    // add the panel to the main window
    contentPane.add(panel);

    // map
    map = createMap(resultBox);
    contentPane.add(map);

    return contentPane;
  }

  // ------------------------------------------------------------------------
  // Private methods
  // ------------------------------------------------------------------------
  /**
   * 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 map.
   * @return a map.
   */
  private JMap createMap(JEditorPane resultBox) 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);
    // Zoom to U.S.
    jMap.setExtent(new Envelope(-141.12213323593141, 3.34210829734802, -61.229555110931415, 64.05499892234802));
    LayerList layers = jMap.getLayers();
    layers.add(baseLayer);

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

    // -----------------------------------------------------------------------------------------
    // User command overlay - a map overlay to handle mouse-clicks
    // -----------------------------------------------------------------------------------------
    jMap.addMapOverlay(new UserCommandOverlay(jMap, graphicsLayer, resultBox));

    return jMap;
  }

  /**
   * Creates a description for this application.
   * @return description
   */
  private JTextArea createDescription() {
    JTextArea description = new JTextArea(
        "This application measures the length of a polyline.\n" +
            "- Create a polyline using left-clicks on the map\n" +
        "- Right-click to start over");
    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;
  }

  /**
   * Creates a description for this application.
   * @return a JPanel that has the description text.
   */
  private JEditorPane createResultBox() {
    JEditorPane result = new JEditorPane("text", "Result will be displayed here.");
    result.setForeground(Color.BLACK);
    result.setEditable(false);
    result.setBackground(new Color(255, 255, 255));
    result.setEditable(false);
    result.setBorder(BorderFactory.createEmptyBorder(5,10,5,5));
    result.setVisible(true);

    return result;
  }
}
Feedback on this topic?