Geodesic geometries

Download Sample Viewer

Description

This application allows you to create geodesically densified lines and polygons using a drawing tool. Geodesic sectors and ellipses can be created by setting properties and using a draw tool to define the center of the sector/ellipse. This application uses static methods on GeometryEngine.

Code snippet


    Geometry geodesicLine = GeometryEngine.geodesicDensifyGeometry(inputGeometry, map.getSpatialReference(), 500000, null);
  
    Geometry ellipse = GeometryEngine.geodesicEllipse(center, map.getSpatialReference(), majorAxisLength, minorAxisLength,
        majorAxisDirection, pointCount, unit, geometryType); 
    
    Geometry sector = GeometryEngine.geodesicSector(center, map.getSpatialReference(), majorAxisLength, minorAxisLength,
        majorAxisDirection, startDirection, sectorAngle, pointCount, pointCount, unit, geometryType);
        
  

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.FlowLayout;
import java.awt.Font;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.util.HashMap;
import java.util.Map;

import javax.swing.BorderFactory;
import javax.swing.Box;
import javax.swing.BoxLayout;
import javax.swing.DefaultComboBoxModel;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JCheckBox;
import javax.swing.JComboBox;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JTextArea;
import javax.swing.JTextField;
import javax.swing.JToolBar;
import javax.swing.SwingConstants;
import javax.swing.SwingUtilities;
import javax.swing.ToolTipManager;
import javax.swing.border.LineBorder;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;

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.LinearUnit;
import com.esri.core.geometry.Point;
import com.esri.core.geometry.Polygon;
import com.esri.core.geometry.Polyline;
import com.esri.core.map.Graphic;
import com.esri.core.symbol.CompositeSymbol;
import com.esri.core.symbol.SimpleFillSymbol;
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.MapEvent;
import com.esri.map.MapEventListener;

/***
 * This application allows you to create geodesically densified lines and polygons using a drawing tool. Geodesic
 * sectors and ellipses can be created by setting properties and using a draw tool to define the center of the
 * sector/ellipse. This application uses static methods on GeometryEngine.
 */
public class GeodesicGeometriesApp {

  // map
  private JMap map;

  // graphics layer
  private GraphicsLayer graphicsLayer;

  // base layer URL
  private static final String URL_BASEMAP = "http://services.arcgisonline.com/ArcGIS/rest/services/World_Topo_Map/MapServer";

  // symbols
  private static SimpleMarkerSymbol projectedMarkerSymbol = new SimpleMarkerSymbol(Color.BLUE, 6, Style.CIRCLE);
  private static SimpleLineSymbol projectedLineSymbol = new SimpleLineSymbol(Color.BLUE, 2);
  private static SimpleFillSymbol projectedPolygonSymbol = new SimpleFillSymbol(Color.BLUE, projectedLineSymbol);

  // composite symbol can be applied to a variety of geometries
  private static CompositeSymbol geodesicSymbol = new CompositeSymbol();
  static {
    geodesicSymbol.add(new SimpleFillSymbol(Color.BLACK));
    geodesicSymbol.add(new SimpleLineSymbol(Color.RED, 5));
    geodesicSymbol.add(new SimpleMarkerSymbol(Color.GREEN, 5, Style.CIRCLE));
  }

  // flag to draw ellipse
  private boolean drawEllipse = false;

  // UI for ellipse and sector properties
  private final JComboBox<String> cbxGeometry = new JComboBox<>();
  private final JTextField txtMajAxisLen = new JTextField("");
  private final JTextField txtMinAxisLen = new JTextField("");
  private final JComboBox<String> cbxLengthUnit = new JComboBox<>();
  private final JCheckBox cbxSector = new JCheckBox("Draw sector");
  private final JTextField txtMajorAxisDirection = new JTextField("");
  private final JTextField txtStartAngle = new JTextField("");
  private final JTextField txtSectorAngle = new JTextField("");
  private final static Color CONTROL_PANEL_COLOR = new Color(0, 0, 0, 255);
  private static final Dimension COMPONENT_DIM = new Dimension(245, 25);

  // initialize linear units of length for combo box
  private final static Map<String, Integer> LENGTH_UNITS = new HashMap<>();
  static {
    LENGTH_UNITS.put(new LinearUnit(LinearUnit.Code.KILOMETER).getDisplayName(), Integer.valueOf(new LinearUnit(
        LinearUnit.Code.KILOMETER).getID()));
    LENGTH_UNITS.put(new LinearUnit(LinearUnit.Code.METER).getDisplayName(),
        Integer.valueOf(new LinearUnit(LinearUnit.Code.METER).getID()));
    LENGTH_UNITS.put(new LinearUnit(LinearUnit.Code.MILE_US).getDisplayName(),
        Integer.valueOf(new LinearUnit(LinearUnit.Code.MILE_US).getID()));
  }

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

  // ------------------------------------------------------------------------
  // Core functionality
  // ------------------------------------------------------------------------
  /**
   * Densify a line or polygon
   * 
   * @param inputGeometry
   * @return geodesic line or polygon
   */
  private Geometry createGeodesic(Geometry inputGeometry) {
    return GeometryEngine.geodesicDensifyGeometry(inputGeometry, map.getSpatialReference(), 500000, null);
  }

  private Geometry createGeodesicEllipse(Point center) {
    int majorAxisLength = Integer.parseInt(txtMajAxisLen.getText());
    int minorAxisLength = Integer.parseInt(txtMinAxisLen.getText());
    int majorAxisDirection = Integer.parseInt(txtMajorAxisDirection.getText());
    int pointCount = 3000;
    LinearUnit unit = new LinearUnit(LENGTH_UNITS.get(cbxLengthUnit.getSelectedItem()).intValue());
    Type geometryType = Geometry.Type.valueOf((String) cbxGeometry.getSelectedItem());

    return GeometryEngine.geodesicEllipse(center, map.getSpatialReference(), majorAxisLength, minorAxisLength,
        majorAxisDirection, pointCount, unit, geometryType);

  }

  private Geometry createGeodesicSector(Point center) {
    int majorAxisLength = Integer.parseInt(txtMajAxisLen.getText());
    int minorAxisLength = Integer.parseInt(txtMinAxisLen.getText());
    int majorAxisDirection = Integer.parseInt(txtMajorAxisDirection.getText());
    int startDirection = Integer.parseInt(txtStartAngle.getText());
    int sectorAngle = Integer.parseInt(txtSectorAngle.getText());
    LinearUnit unit = new LinearUnit(LENGTH_UNITS.get(cbxLengthUnit.getSelectedItem()).intValue());
    Type geometryType = Geometry.Type.valueOf((String) cbxGeometry.getSelectedItem());

    return GeometryEngine.geodesicSector(center, map.getSpatialReference(), majorAxisLength, minorAxisLength,
        majorAxisDirection, startDirection, sectorAngle, 1, 1, unit, geometryType);

  }

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

    // application content
    JPanel applicationPanel = new JPanel();
    applicationPanel.setLayout(new BorderLayout(0, 0));

    // create map
    map = new JMap();
    map.addMapEventListener(new MapEventListener() {

      @Override
      public void mapReady(MapEvent event) {
        addGraphics();
      }

      @Override
      public void mapExtentChanged(MapEvent event) {
      }

      @Override
      public void mapDispose(MapEvent event) {
      }
    });

    map.addMouseListener(new MouseAdapter() {
      @Override
      public void mouseClicked(MouseEvent e) {
        if (drawEllipse) {
          Geometry ellipseOrSector = null;
          Point p = map.toMapPoint(e.getX(), e.getY());

          if (cbxSector.isSelected()) {// draw a sector, not an ellipse
            ellipseOrSector = createGeodesicSector(p);
          } else {
            ellipseOrSector = createGeodesicEllipse(p);
          }
          graphicsLayer.addGraphic(new Graphic(ellipseOrSector, geodesicSymbol));
          graphicsLayer.addGraphic(new Graphic(p, projectedMarkerSymbol));
        }
      }
    });

    // add base layer
    ArcGISTiledMapServiceLayer tiledLayer = new ArcGISTiledMapServiceLayer(URL_BASEMAP);
    map.getLayers().add(tiledLayer);

    // add graphics layer for our drawn graphics
    graphicsLayer = new GraphicsLayer();
    map.getLayers().add(graphicsLayer);

    // create drawing overlay on which graphics will be drawn, add to map, and activate
    final DrawingOverlay drawingOverlay = new DrawingOverlay();
    map.addMapOverlay(drawingOverlay);
    drawingOverlay.setActive(true);

    // add a listener to add the drawn graphic into our graphics layer
    drawingOverlay.addDrawingCompleteListener(new DrawingCompleteListener() {

      @Override
      public void drawingCompleted(DrawingCompleteEvent arg0) {
        // get the graphic drawn
        Graphic inputGraphic = (Graphic) drawingOverlay.getAndClearFeature();
        graphicsLayer.addGraphic(inputGraphic);

        // get the corresponding geodesic geometry
        Geometry geodesicGeometry = createGeodesic(inputGraphic.getGeometry());
        if (geodesicGeometry != null) {
          Graphic geodesicGraphic = new Graphic(geodesicGeometry, geodesicSymbol);
          graphicsLayer.addGraphic(geodesicGraphic);
        }
      }
    });

    // toolbar
    final JToolBar toolBar = createToolBar(drawingOverlay);

    JPanel mainPanel = new JPanel();
    mainPanel.setLayout(new BorderLayout());
    mainPanel.add(toolBar, BorderLayout.NORTH);
    mainPanel.add(map, BorderLayout.CENTER);

    final JPanel panel = createControlPanel();

    applicationPanel.add(panel, BorderLayout.WEST);
    applicationPanel.add(mainPanel, BorderLayout.CENTER);

    return applicationPanel;
  }

  // ------------------------------------------------------------------------
  // Private methods
  // ------------------------------------------------------------------------
  /**
   * Create a toolbar with our drawing tool buttons. Clicking a button will change the drawing mode and symbology (and
   * attributes, optionally) to that specified in the setUp method.
   * 
   * @param drawingOverlay - the drawing overlay associated with the toolbar
   * @return toolBar - the toolBar
   */
  private JToolBar createToolBar(final DrawingOverlay drawingOverlay) {

    JToolBar toolBar = new JToolBar();
    toolBar.setLayout(new FlowLayout(FlowLayout.CENTER));

    ToolTipManager.sharedInstance().setInitialDelay(100);

    // line
    JButton polylineButton = new JButton(new ImageIcon(getClass().getResource(
        "/com/esri/client/toolkit/images/EditingLineTool16.png")));
    polylineButton.setFocusable(false);
    polylineButton.setToolTipText("Polyline tool");
    polylineButton.addActionListener(new ActionListener() {
      @Override
      public void actionPerformed(ActionEvent e) {
        drawingOverlay.setUp(DrawingMode.POLYLINE, projectedLineSymbol, null);
        drawingOverlay.setActive(true);
      }
    });
    toolBar.add(polylineButton);

    // polygon
    JButton polygonButton = new JButton(new ImageIcon(getClass().getResource(
        "/com/esri/client/toolkit/images/EditingPolygonTool16.png")));
    polygonButton.setFocusable(false);
    polygonButton.setToolTipText("Polygon tool");
    polygonButton.addActionListener(new ActionListener() {
      @Override
      public void actionPerformed(ActionEvent e) {
        drawingOverlay.setUp(DrawingMode.POLYGON, projectedPolygonSymbol, null);
        drawingOverlay.setActive(true);
      }
    });
    toolBar.add(polygonButton);

    // center of ellipse
    JButton btnEllipse = new JButton(new ImageIcon(getClass().getResource(
        "/com/esri/client/toolkit/images/EditingEllipseTool16.png")));
    btnEllipse.setFocusable(false);
    btnEllipse.setToolTipText("Ellipse/sector center point");
    btnEllipse.addActionListener(new ActionListener() {
      @Override
      public void actionPerformed(ActionEvent e) {
        drawingOverlay.setActive(false);
        drawEllipse = true;
      }
    });
    toolBar.add(btnEllipse);

    // remove graphics
    JButton btnRemoveGraphics = new JButton("Remove graphics");
    btnRemoveGraphics.setFocusPainted(false);
    btnRemoveGraphics.addActionListener(new ActionListener() {
      @Override
      public void actionPerformed(ActionEvent e) {
        graphicsLayer.removeAll();
      }
    });
    toolBar.add(btnRemoveGraphics);

    return toolBar;
  }

  private void addGraphics() {
    // line
    Polyline line = new Polyline();
    line.startPath(-392888.37391226366, 7399413.3147899695);
    line.lineTo(8840007.443533156, 1440594.0283535644);
    graphicsLayer.addGraphic(new Graphic(line, projectedLineSymbol));
    Geometry geodesicGeometry = createGeodesic(line);
    graphicsLayer.addGraphic(new Graphic(geodesicGeometry, geodesicSymbol));

    // polygon
    Polygon polygon = new Polygon();
    polygon.startPath(-7072004.497170653, 1.6304901479134485E7);
    polygon.lineTo(-1244148.2719746083, 1.6828753724095933E7);
    polygon.lineTo(-5434966.231666148, 8578080.865953214);
    graphicsLayer.addGraphic(new Graphic(polygon, projectedPolygonSymbol));
    geodesicGeometry = createGeodesic(polygon);
    graphicsLayer.addGraphic(new Graphic(geodesicGeometry, geodesicSymbol));

    // ellipse
    Point center = new Point(-4190817.1498827226, -7202968.013510233);
    graphicsLayer.addGraphic(new Graphic(center, projectedMarkerSymbol));
    geodesicGeometry = GeometryEngine.geodesicEllipse(center, map.getSpatialReference(), 2000000, 1000000, 0, 10000,
        new LinearUnit(LinearUnit.Code.METER), Type.POLYGON);
    graphicsLayer.addGraphic(new Graphic(geodesicGeometry, geodesicSymbol));
  }

  // ------------------------------------------------------------------------
  // Static methods
  // ------------------------------------------------------------------------
  /**
   * Launch the application.
   */
  public static void main(String[] args) {
    SwingUtilities.invokeLater(new Runnable() {
      @Override
      public void run() {
        try {
          GeodesicGeometriesApp app = new GeodesicGeometriesApp();
          JFrame appWindow = app.createWindow();
          appWindow.add(app.createUI());
          appWindow.setVisible(true);
        } catch (Exception e) {
          e.printStackTrace();
        }
      }
    });
  }

  /**
   * Creates a window.
   * 
   * @return a window.
   */
  private JFrame createWindow() {
    JFrame window = new JFrame("Geodesic Geometries Application");
    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 description for this application.
   * 
   * @return description
   */
  private JPanel createDescription() {
    JPanel descriptionContainer = new JPanel();
    descriptionContainer.setLayout(new BoxLayout(descriptionContainer, 0));
    descriptionContainer.setSize(280, 60);
    JTextArea description = new JTextArea(
        "Select a drawing tool button above to interactively add graphics "
            + "to the map using the mouse.\n\nGeodesic geometries are shown in red with "
            + "green dots. The dots indicate the vertices generated by the algorithm. "
            + "\n\nThe Polyline Tool and Polygon Tool will draw the planar geometry and the new densified geodesic geometry. "
            + "\n\nThe Ellipse/Sector Tool will draw the ellipse/sector with the center point and the values defined below. ");
    description.setFont(new Font("Verdana", Font.PLAIN, 11));
    description.setForeground(Color.WHITE);
    description.setBackground(Color.BLACK);
    description.setEditable(false);
    description.setLineWrap(true);
    description.setWrapStyleWord(true);
    description.setBorder(BorderFactory.createEmptyBorder(5, 10, 5, 5));
    descriptionContainer.add(description);
    descriptionContainer.setBackground(new Color(0, 0, 0, 0));
    descriptionContainer.setBorder(new LineBorder(Color.BLACK, 3, false));
    return descriptionContainer;
  }

  private JPanel createControlPanel() {

    // label for title
    JTextField lblTitle = new JTextField("Ellipse and Sector Properties");
    lblTitle.setHorizontalAlignment(SwingConstants.CENTER);
    lblTitle.setMaximumSize(COMPONENT_DIM);
    lblTitle.setForeground(Color.WHITE);
    lblTitle.setBackground(null);
    lblTitle.setEditable(false);

    // label for text
    JTextField lblTextMajor = new JTextField("Major axis length:");
    lblTextMajor.setMaximumSize(COMPONENT_DIM);
    lblTextMajor.setForeground(Color.WHITE);
    lblTextMajor.setBackground(null);
    lblTextMajor.setBorder(null);

    // textbox for Major Axis Length
    txtMajAxisLen.setMaximumSize(COMPONENT_DIM);

    // label for text
    JTextField lblTextMajorDir = new JTextField("Major axis direction (\u21b6 from East):");
    lblTextMajorDir.setMaximumSize(COMPONENT_DIM);
    lblTextMajorDir.setForeground(Color.WHITE);
    lblTextMajorDir.setBackground(null);
    lblTextMajorDir.setEditable(false);
    lblTextMajorDir.setBorder(null);

    // textbox for Major Axis Direction
    txtMajorAxisDirection.setMaximumSize(COMPONENT_DIM);

    // label for text
    JTextField lblTextMin = new JTextField("Minor axis length:");
    lblTextMin.setMaximumSize(COMPONENT_DIM);
    lblTextMin.setForeground(Color.WHITE);
    lblTextMin.setBackground(null);
    lblTextMin.setEditable(false);
    lblTextMin.setBorder(null);

    // textbox for Minor Axis Length
    txtMinAxisLen.setMaximumSize(COMPONENT_DIM);

    // label for length units
    JTextField lblLength = new JTextField("Length units:");
    lblLength.setPreferredSize(COMPONENT_DIM);
    lblLength.setMaximumSize(COMPONENT_DIM);
    lblLength.setForeground(Color.WHITE);
    lblLength.setBackground(null);
    lblLength.setEditable(false);
    lblLength.setBorder(null);

    // drop-down list for units
    cbxLengthUnit.setMaximumSize(COMPONENT_DIM);

    // label for geometry type
    JTextField lblGeomType = new JTextField("Geometry type:");
    lblGeomType.setMaximumSize(COMPONENT_DIM);
    lblGeomType.setForeground(Color.WHITE);
    lblGeomType.setBackground(null);
    lblGeomType.setEditable(false);
    lblGeomType.setBorder(null);

    // drop-down list for geometry type
    cbxGeometry.setMaximumSize(COMPONENT_DIM);

    // checkbox option for sector instead of ellipse
    cbxSector.setMaximumSize(COMPONENT_DIM);
    cbxSector.setForeground(Color.WHITE);
    cbxSector.setBackground(null);
    cbxSector.setAlignmentX(SwingConstants.LEFT);
    cbxSector.setFocusPainted(false);
    cbxSector.addChangeListener(new ChangeListener() {

      @Override
      public void stateChanged(ChangeEvent e) {
        if (cbxSector.isSelected()){
          //enable the sector properties
          txtStartAngle.setEditable(true);
          txtSectorAngle.setEditable(true);         
        }  else{
          //enable the sector properties
          txtStartAngle.setEditable(false);
          txtSectorAngle.setEditable(false);   
        }
      }
    });

    // label for text
    JTextField lblTextStartAngle = new JTextField("Start angle (\u21b6 from major axis):");
    lblTextStartAngle.setMaximumSize(COMPONENT_DIM);
    lblTextStartAngle.setForeground(Color.WHITE);
    lblTextStartAngle.setBackground(null);
    lblTextStartAngle.setEditable(false);
    lblTextStartAngle.setBorder(null);

    // textbox for start angle
    txtStartAngle.setMaximumSize(COMPONENT_DIM);
    txtStartAngle.setEditable(false);

    // label for text
    JTextField lblTextSectorAngle = new JTextField("Sector angle (\u21b7 from start angle):");
    lblTextSectorAngle.setMaximumSize(COMPONENT_DIM);
    lblTextSectorAngle.setForeground(Color.WHITE);
    lblTextSectorAngle.setBackground(null);
    lblTextSectorAngle.setEditable(false);
    lblTextSectorAngle.setBorder(null);

    // textbox for sector angle
    txtSectorAngle.setMaximumSize(COMPONENT_DIM);
    txtSectorAngle.setEditable(false);   

    // group the above UI items into a control panel
    final JPanel controlPanel = new JPanel();
    BoxLayout boxLayout = new BoxLayout(controlPanel, BoxLayout.Y_AXIS);
    controlPanel.setAlignmentX(SwingConstants.CENTER);
    controlPanel.setLayout(boxLayout);
    controlPanel.setBackground(CONTROL_PANEL_COLOR);
    controlPanel.setDoubleBuffered(true);
    controlPanel.setBorder(new LineBorder(Color.BLACK, 5, false));
    controlPanel.setVisible(true);

    controlPanel.add(createDescription());
    controlPanel.add(lblTitle);
    controlPanel.add(Box.createHorizontalStrut(5));
    controlPanel.add(lblTextMajor);
    controlPanel.add(txtMajAxisLen);
    controlPanel.add(lblTextMajorDir);
    controlPanel.add(txtMajorAxisDirection);
    controlPanel.add(lblTextMin);
    controlPanel.add(txtMinAxisLen);
    controlPanel.add(lblLength);
    controlPanel.add(cbxLengthUnit);
    controlPanel.add(lblGeomType);
    controlPanel.add(cbxGeometry);

    controlPanel.add(cbxSector);
    controlPanel.add(lblTextStartAngle);
    controlPanel.add(txtStartAngle);
    controlPanel.add(lblTextSectorAngle);
    controlPanel.add(txtSectorAngle);

    populateControlPanel();

    return controlPanel;
  }

  private void populateControlPanel() {
    // initialize UI to match state
    txtMajAxisLen.setText("500");
    txtMinAxisLen.setText("500");
    cbxLengthUnit.setModel(new DefaultComboBoxModel<>(LENGTH_UNITS.keySet().toArray(new String[0])));
    cbxLengthUnit.setSelectedIndex(0);
    cbxGeometry.setModel(new DefaultComboBoxModel<>(new String[]{Type.POLYLINE.name(), Type.POLYGON.name(), Type.MULTIPOINT.name()}));
    cbxGeometry.setSelectedIndex(0);
    cbxSector.setSelected(false);
    txtMajorAxisDirection.setText("0");
    txtStartAngle.setText("0");
    txtSectorAngle.setText("90");
  }
}
Feedback on this topic?