ArcGIS Runtime SDK for Android

Line of Sight GeoElement

Loading

Code

/* Copyright 2018 Esri
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *    http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 */

package com.esri.arcgisruntime.sample.lineofsightgeoelement;

import java.io.File;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.Arrays;
import java.util.List;
import java.util.Timer;
import java.util.TimerTask;

import android.content.res.AssetManager;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
import android.widget.SeekBar;
import android.widget.TextView;

import com.esri.arcgisruntime.geoanalysis.GeoElementLineOfSight;
import com.esri.arcgisruntime.geoanalysis.LineOfSight;
import com.esri.arcgisruntime.geometry.AngularUnit;
import com.esri.arcgisruntime.geometry.AngularUnitId;
import com.esri.arcgisruntime.geometry.GeodeticCurveType;
import com.esri.arcgisruntime.geometry.GeodeticDistanceResult;
import com.esri.arcgisruntime.geometry.GeometryEngine;
import com.esri.arcgisruntime.geometry.LinearUnit;
import com.esri.arcgisruntime.geometry.LinearUnitId;
import com.esri.arcgisruntime.geometry.Point;
import com.esri.arcgisruntime.geometry.PointBuilder;
import com.esri.arcgisruntime.geometry.SpatialReferences;
import com.esri.arcgisruntime.layers.ArcGISSceneLayer;
import com.esri.arcgisruntime.mapping.ArcGISScene;
import com.esri.arcgisruntime.mapping.ArcGISTiledElevationSource;
import com.esri.arcgisruntime.mapping.Basemap;
import com.esri.arcgisruntime.mapping.Surface;
import com.esri.arcgisruntime.mapping.view.AnalysisOverlay;
import com.esri.arcgisruntime.mapping.view.Camera;
import com.esri.arcgisruntime.mapping.view.Graphic;
import com.esri.arcgisruntime.mapping.view.GraphicsOverlay;
import com.esri.arcgisruntime.mapping.view.LayerSceneProperties;
import com.esri.arcgisruntime.mapping.view.SceneView;
import com.esri.arcgisruntime.symbology.ModelSceneSymbol;
import com.esri.arcgisruntime.symbology.Renderer;
import com.esri.arcgisruntime.symbology.SceneSymbol;
import com.esri.arcgisruntime.symbology.SimpleMarkerSymbol;
import com.esri.arcgisruntime.symbology.SimpleRenderer;

public class MainActivity extends AppCompatActivity {

  private static final String TAG = MainActivity.class.getSimpleName();
  private static final LinearUnit METERS = new LinearUnit(LinearUnitId.METERS);
  private static final AngularUnit DEGREES = new AngularUnit(AngularUnitId.DEGREES);

  private int mWaypointIndex = 0;

  private SceneView mSceneView;
  private Graphic mTaxiGraphic;
  private List<Point> mWaypoints;

  @Override
  protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    // load taxi model from assets into cache directory
    copyFileFromAssetsToCache(getString(R.string.dolmus_model));
    copyFileFromAssetsToCache(getString(R.string.dolmus_back));
    copyFileFromAssetsToCache(getString(R.string.dolmus_front));
    copyFileFromAssetsToCache(getString(R.string.dolmus_side));
    copyFileFromAssetsToCache(getString(R.string.tire_tread));

    // create a scene and add a basemap to it
    ArcGISScene scene = new ArcGISScene();
    scene.setBasemap(Basemap.createTopographic());

    // get a reference to the scene view and set the scene to it
    mSceneView = findViewById(R.id.sceneView);
    mSceneView.setScene(scene);

    // add base surface for elevation data
    Surface surface = new Surface();
    surface.getElevationSources().add(new ArcGISTiledElevationSource(getString(R.string.elevation_service_url)));
    scene.setBaseSurface(surface);

    // add buildings from New York City
    String buildingsURL = getString(R.string.new_york_buildings_service_url);
    ArcGISSceneLayer buildings = new ArcGISSceneLayer(buildingsURL);
    scene.getOperationalLayers().add(buildings);

    // create a graphics overlay for the graphics
    GraphicsOverlay graphicsOverlay = new GraphicsOverlay();
    graphicsOverlay.getSceneProperties().setSurfacePlacement(LayerSceneProperties.SurfacePlacement.RELATIVE);
    mSceneView.getGraphicsOverlays().add(graphicsOverlay);

    // set up a heading expression to handle graphic rotation
    SimpleRenderer renderer3D = new SimpleRenderer();
    Renderer.SceneProperties renderProperties = renderer3D.getSceneProperties();
    renderProperties.setHeadingExpression("[HEADING]");
    graphicsOverlay.setRenderer(renderer3D);

    // create a point graph near the Empire State Building to be the observer
    Point observationPoint = new Point(-73.9853, 40.7484, 200, SpatialReferences.getWgs84());
    Graphic observer = new Graphic(observationPoint,
        new SimpleMarkerSymbol(SimpleMarkerSymbol.Style.CIRCLE, 0xFFFF0000, 5));
    graphicsOverlay.getGraphics().add(observer);

    // create a slider to change the observer's Z value
    SeekBar heightSeekBar = findViewById(R.id.heightSeekBar);
    TextView currHeightTextView = findViewById(R.id.currHeightTextView);
    // offset the minimum height of the observer on the seek bar
    int seekBarMinHeightOffset = 150;
    heightSeekBar.setMax(seekBarMinHeightOffset);
    heightSeekBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
      @Override public void onProgressChanged(SeekBar seekBar, int progress, boolean b) {
        // use the offset to calculate the height value
        int height = progress + seekBarMinHeightOffset;
        currHeightTextView.setText(String.valueOf(height));
        PointBuilder pointBuilder = new PointBuilder((Point) observer.getGeometry());
        pointBuilder.setZ(height);
        observer.setGeometry(pointBuilder.toGeometry());
      }

      @Override public void onStartTrackingTouch(SeekBar seekBar) {

      }

      @Override public void onStopTrackingTouch(SeekBar seekBar) {

      }
    });
    // set seek bar initial progress with offset
    heightSeekBar.setProgress((int) observationPoint.getZ() - seekBarMinHeightOffset);

    // create waypoints around a block for the taxi to drive to
    mWaypoints = Arrays.asList(
        new Point(-73.984513, 40.748469, SpatialReferences.getWgs84()),
        new Point(-73.985068, 40.747786, SpatialReferences.getWgs84()),
        new Point(-73.983452, 40.747091, SpatialReferences.getWgs84()),
        new Point(-73.982961, 40.747762, SpatialReferences.getWgs84())
    );

    // create a graphic of a taxi to be the target
    String pathToModel = getCacheDir() + File.separator + getString(R.string.dolmus_model);
    ModelSceneSymbol taxiSymbol = new ModelSceneSymbol(pathToModel, 1.0);
    taxiSymbol.setAnchorPosition(SceneSymbol.AnchorPosition.BOTTOM);
    taxiSymbol.loadAsync();
    mTaxiGraphic = new Graphic(mWaypoints.get(0), taxiSymbol);
    mTaxiGraphic.getAttributes().put("HEADING", 0.0);
    graphicsOverlay.getGraphics().add(mTaxiGraphic);

    // create an analysis overlay to hold the line of sight
    AnalysisOverlay analysisOverlay = new AnalysisOverlay();
    mSceneView.getAnalysisOverlays().add(analysisOverlay);

    // create a line of sight between the two graphics and add it to the analysis overlay
    GeoElementLineOfSight lineOfSight = new GeoElementLineOfSight(observer, mTaxiGraphic);
    analysisOverlay.getAnalyses().add(lineOfSight);

    // select (highlight) the taxi when the line of sight target visibility changes to visible
    lineOfSight.addTargetVisibilityChangedListener(targetVisibilityChangedEvent -> mTaxiGraphic
        .setSelected(targetVisibilityChangedEvent.getTargetVisibility() == LineOfSight.TargetVisibility.VISIBLE)
    );

    // create a timer to animate the tank
    Timer timer = new Timer();
    timer.scheduleAtFixedRate(new TimerTask() {
      @Override public void run() {
        animate();
      }
    }, 0, 50);

    // zoom to show the observer
    Camera camera = new Camera((Point) observer.getGeometry(), 700, -30, 45, 0);
    mSceneView.setViewpointCamera(camera);
  }

  /**
   * Moves the taxi toward the current waypoint a short distance.
   */
  private void animate() {
    Point waypoint = mWaypoints.get(mWaypointIndex);
    // get current location and distance from waypoint
    Point location = (Point) mTaxiGraphic.getGeometry();
    GeodeticDistanceResult distance = GeometryEngine.distanceGeodetic(location, waypoint, METERS, DEGREES,
        GeodeticCurveType.GEODESIC);

    // move toward waypoint a short distance
    location = GeometryEngine.moveGeodetic(location, 1.0, METERS, distance.getAzimuth1(), DEGREES,
        GeodeticCurveType.GEODESIC);
    mTaxiGraphic.setGeometry(location);

    // rotate to the waypoint
    mTaxiGraphic.getAttributes().put("HEADING", distance.getAzimuth1());

    // reached waypoint, move to next waypoint
    if (distance.getDistance() <= 2) {
      mWaypointIndex = (mWaypointIndex + 1) % mWaypoints.size();
    }
  }

  /**
   * Copy the given file from the app's assets folder to the app's cache directory.
   *
   * @param fileName as String
   */
  private void copyFileFromAssetsToCache(String fileName) {
    AssetManager assetManager = getApplicationContext().getAssets();
    File file = new File(getCacheDir() + File.separator + fileName);
    if (!file.exists()) {
      try {
        InputStream in = assetManager.open(fileName);
        OutputStream out = new FileOutputStream(getCacheDir() + File.separator + fileName);
        byte[] buffer = new byte[1024];
        int read = in.read(buffer);
        while (read != -1) {
          out.write(buffer, 0, read);
          read = in.read(buffer);
        }
        Log.i(TAG, fileName + " copied to cache.");
      } catch (Exception e) {
        Log.e(TAG, "Error writing " + fileName + " to cache. " + e.getMessage());
      }
    } else {
      Log.i(TAG, fileName + " already in cache.");
    }
  }

  @Override
  protected void onPause() {
    mSceneView.pause();
    super.onPause();
  }

  @Override
  protected void onResume() {
    super.onResume();
    mSceneView.resume();
  }

  @Override
  protected void onDestroy() {
    mSceneView.dispose();
    super.onDestroy();
  }
}


In this topic
  1. Code