Skip to content

Instantly share code, notes, and snippets.

@andygup
Last active August 29, 2015 13:59
Show Gist options
  • Save andygup/10693881 to your computer and use it in GitHub Desktop.
Save andygup/10693881 to your computer and use it in GitHub Desktop.
drag poly android
/* Copyright 2012 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 sample code usage restrictions document for further information.
*
*/
package com.esri.arcgis.android.samples.geometryeditor;
import java.util.ArrayList;
import android.app.Activity;
import android.app.DialogFragment;
import android.app.Fragment;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Color;
import android.os.Bundle;
import android.text.TextUtils;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.view.Window;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.ImageView;
import android.widget.TextView;
import android.widget.Toast;
import com.esri.android.map.FeatureLayer;
import com.esri.android.map.GraphicsLayer;
import com.esri.android.map.Layer;
import com.esri.android.map.MapOnTouchListener;
import com.esri.android.map.MapView;
import com.esri.android.map.ags.ArcGISFeatureLayer;
import com.esri.android.map.event.OnSingleTapListener;
import com.esri.android.map.event.OnStatusChangedListener;
import com.esri.core.geometry.Geometry;
import com.esri.core.geometry.GeometryEngine;
import com.esri.core.geometry.MultiPath;
import com.esri.core.geometry.Point;
import com.esri.core.geometry.Polygon;
import com.esri.core.geometry.Polyline;
import com.esri.core.map.CallbackListener;
import com.esri.core.map.FeatureEditResult;
import com.esri.core.map.FeatureTemplate;
import com.esri.core.map.FeatureType;
import com.esri.core.map.Graphic;
import com.esri.core.renderer.Renderer;
import com.esri.core.symbol.FillSymbol;
import com.esri.core.symbol.LineSymbol;
import com.esri.core.symbol.MarkerSymbol;
import com.esri.core.symbol.SimpleFillSymbol;
import com.esri.core.symbol.SimpleLineSymbol;
import com.esri.core.symbol.SimpleMarkerSymbol;
import com.esri.core.symbol.Symbol;
import com.esri.core.symbol.SymbolHelper;
/**
* The purpose of this sample is to demonstrate how to create features (point, polyline, polygon) with the ArcGIS for
* Android API. The sample supports template based editing for the three types of feature layers (point, line and
* polygon).
* <p>
* Tap the '+' icon in the action bar to start adding a feature. A list of available templates is displayed
* showing the templates' symbol to allow you to quickly select the required feature to add to the map.
* <p>
* When adding a point feature, tap the map to position the feature. Tapping the map again moves the point to
* the new position.
* <p>
* When adding polygon or polyline features:
* <ul>
* <li>add a new vertex by simply tapping on a new location on the map;
* <li>move an existing vertex by tapping it and then tapping its new location on the map;
* <li>delete an existing vertex by tapping it and then tapping the trash can icon on the action bar.
* </ul>
* Additional points are drawn at the midpoint of each line. A midpoint can be moved by tapping the midpoint and then
* tapping its new location on the map.
* <p>
* In addition to the trash can, the action bar presents the following icons when editing a feature:
* <ul>
* <li>floppy disk icon to Save the feature by uploading it to the server;
* <li>'X' icon to Discard the feature;
* <li>undo icon to Undo the last action performed (i.e. the last addition, move or deletion of a point).
* </ul>
* Whenever a feature is being added, a long-press on the map displays a magnifier that allows a location to be selected
* more accurately.
*/
public class GeometryEditorActivity extends Activity {
protected static final String TAG = "EditGraphicElements";
private static final String TAG_DIALOG_FRAGMENTS = "dialog";
private static final String KEY_MAP_STATE = "com.esri.MapState";
private enum EditMode {
NONE, POINT, POLYLINE, POLYGON, SAVING
}
Menu mOptionsMenu;
MapView mMapView;
String mMapState;
DialogFragment mDialogFragment;
GraphicsLayer mGraphicsLayerEditing;
ArrayList<Point> mPoints = new ArrayList<Point>();
ArrayList<Point> mMidPoints = new ArrayList<Point>();
boolean mMidPointSelected = false;
boolean mVertexSelected = false;
int mInsertingIndex;
EditMode mEditMode;
boolean mClosingTheApp = false;
ArrayList<EditingStates> mEditingStates = new ArrayList<EditingStates>();
ArrayList<FeatureTypeData> mFeatureTypeList;
ArrayList<FeatureTemplate> mTemplateList;
ArrayList<ArcGISFeatureLayer> mFeatureLayerList;
FeatureTemplate mTemplate;
ArcGISFeatureLayer mTemplateLayer;
SimpleMarkerSymbol mRedMarkerSymbol = new SimpleMarkerSymbol(Color.RED, 10, SimpleMarkerSymbol.STYLE.CIRCLE);
SimpleMarkerSymbol mBlackMarkerSymbol = new SimpleMarkerSymbol(Color.BLACK, 10, SimpleMarkerSymbol.STYLE.CIRCLE);
SimpleMarkerSymbol mGreenMarkerSymbol = new SimpleMarkerSymbol(Color.GREEN, 7, SimpleMarkerSymbol.STYLE.CIRCLE);
MotionEvent mLongPressEvent;
ArcGISFeatureLayer fl3;
DragListener dragListener;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// Initialize progress bar before setting content
requestWindowFeature(Window.FEATURE_INDETERMINATE_PROGRESS);
setProgressBarIndeterminateVisibility(false);
setContentView(R.layout.main);
mEditMode = EditMode.NONE;
if (savedInstanceState == null) {
mMapState = null;
} else {
mMapState = savedInstanceState.getString(KEY_MAP_STATE);
// If activity is destroyed and recreated, we discard any edit that was in progress.
// Because of that, we also dismiss any dialog that may be in progress, because it would be related to an edit.
Fragment dialogFrag = getFragmentManager().findFragmentByTag(TAG_DIALOG_FRAGMENTS);
if (dialogFrag != null) {
((DialogFragment) dialogFrag).dismiss();
}
}
// Create status listener for feature layers
OnStatusChangedListener statusChangedListener = new OnStatusChangedListener() {
private static final long serialVersionUID = 1L;
@Override
public void onStatusChanged(Object source, STATUS status) {
}
};
// Create feature layers
ArcGISFeatureLayer fl1 = new ArcGISFeatureLayer(
"http://sampleserver5.arcgisonline.com/ArcGIS/rest/services/LocalGovernment/Recreation/FeatureServer/2",
ArcGISFeatureLayer.MODE.ONDEMAND);
fl1.setOnStatusChangedListener(statusChangedListener);
ArcGISFeatureLayer fl2 = new ArcGISFeatureLayer(
"http://sampleserver5.arcgisonline.com/ArcGIS/rest/services/LocalGovernment/Recreation/FeatureServer/0",
ArcGISFeatureLayer.MODE.ONDEMAND);
fl2.setOnStatusChangedListener(statusChangedListener);
fl3 = new ArcGISFeatureLayer(
"http://sampleserver5.arcgisonline.com/ArcGIS/rest/services/LocalGovernment/Recreation/FeatureServer/1",
ArcGISFeatureLayer.MODE.ONDEMAND);
fl3.setOnStatusChangedListener(statusChangedListener);
// Find MapView and add feature layers
mMapView = (MapView) findViewById(R.id.map);
mMapView.addLayer(fl1);
mMapView.addLayer(fl2);
mMapView.addLayer(fl3);
// Set listeners on MapView
mMapView.setOnStatusChangedListener(new OnStatusChangedListener() {
private static final long serialVersionUID = 1L;
@Override
public void onStatusChanged(final Object source, final STATUS status) {
if (STATUS.INITIALIZED == status) {
if (source instanceof MapView) {
mGraphicsLayerEditing = new GraphicsLayer();
mMapView.addLayer(mGraphicsLayerEditing);
}
}
if(status == STATUS.LAYER_LOADED){
String layerName = (String) ((Layer) source).getName();
if(source instanceof ArcGISFeatureLayer && layerName.equals("Trails")){
Log.d("Test","Trails layer loaded!");
}
}
}
});
mMapView.setOnTouchListener(new MyTouchListener(GeometryEditorActivity.this, mMapView));
// If map state (center and resolution) has been stored, update the MapView with this state
if (!TextUtils.isEmpty(mMapState)) {
mMapView.restoreState(mMapState);
}
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu items for use in the action bar
MenuInflater inflater = getMenuInflater();
inflater.inflate(R.menu.actions, menu);
mOptionsMenu = menu;
updateActionBar();
return super.onCreateOptionsMenu(menu);
}
@Override
public boolean onPrepareOptionsMenu(Menu menu) {
return super.onPrepareOptionsMenu(menu);
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
// Handle presses on the action bar items
switch (item.getItemId()) {
case R.id.action_add:
actionAdd();
return true;
case R.id.action_save:
actionSave();
return true;
case R.id.action_discard:
actionDiscard();
return true;
case R.id.action_delete:
actionDelete();
return true;
case R.id.action_undo:
actionUndo();
return true;
default:
return super.onOptionsItemSelected(item);
}
}
@Override
public void onBackPressed() {
if (mEditMode != EditMode.NONE && mEditMode != EditMode.SAVING && mEditingStates.size() > 0) {
// There's an edit in progress, so ask for confirmation
mClosingTheApp = true;
showConfirmDiscardDialogFragment();
} else {
// No edit in progress, so allow the app to be closed
super.onBackPressed();
}
}
@Override
protected void onPause() {
super.onPause();
mMapView.pause();
}
@Override
protected void onResume() {
super.onResume();
mMapView.unpause();
}
@Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
outState.putString(KEY_MAP_STATE, mMapView.retainState());
}
/**
* Handles the 'Add' action.
*/
private void actionAdd() {
listTemplates();
showFeatureTypeDialogFragment();
}
/**
* Handles the 'Discard' action.
*/
private void actionDiscard() {
if (mEditingStates.size() > 0) {
// There's an edit in progress, so ask for confirmation
mClosingTheApp = false;
showConfirmDiscardDialogFragment();
} else {
// No edit in progress, so just exit edit mode
exitEditMode();
}
}
/**
* Handles the 'Delete' action.
*/
private void actionDelete() {
if (!mVertexSelected) {
mPoints.remove(mPoints.size() - 1); // remove last vertex
} else {
mPoints.remove(mInsertingIndex); // remove currently selected vertex
}
mMidPointSelected = false;
mVertexSelected = false;
mEditingStates.add(new EditingStates(mPoints, mMidPointSelected, mVertexSelected, mInsertingIndex));
refresh();
}
/**
* Handles the 'Undo' action.
*/
private void actionUndo() {
mEditingStates.remove(mEditingStates.size() - 1);
mPoints.clear();
if (mEditingStates.size() == 0) {
mMidPointSelected = false;
mVertexSelected = false;
mInsertingIndex = 0;
} else {
EditingStates state = mEditingStates.get(mEditingStates.size() - 1);
mPoints.addAll(state.points);
Log.d(TAG, "# of points = " + mPoints.size());
mMidPointSelected = state.midPointSelected;
mVertexSelected = state.vertexSelected;
mInsertingIndex = state.insertingIndex;
}
refresh();
}
/**
* Handles the 'Save' action. The edits made are applied and hence saved on the server.
*/
private void actionSave() {
Graphic g;
if (mEditMode == EditMode.POINT) {
// For a point, just create a Graphic from the point
g = mTemplateLayer.createFeatureWithTemplate(mTemplate, mPoints.get(0));
} else {
// For polylines and polygons, create a MultiPath from the points...
MultiPath multipath;
if (mEditMode == EditMode.POLYLINE) {
multipath = new Polyline();
} else if (mEditMode == EditMode.POLYGON) {
multipath = new Polygon();
} else {
return;
}
multipath.startPath(mPoints.get(0));
for (int i = 1; i < mPoints.size(); i++) {
multipath.lineTo(mPoints.get(i));
}
// ...then simplify the geometry and create a Graphic from it
Geometry geom = GeometryEngine.simplify(multipath, mMapView.getSpatialReference());
if(mTemplate != null ){
g = mTemplateLayer.createFeatureWithTemplate(mTemplate, geom);
}
else{
return;
}
}
// Show progress bar and disable actions during the save
setProgressBarIndeterminateVisibility(true);
mEditMode = EditMode.SAVING;
updateActionBar();
// Now add the Graphic to the layer
mTemplateLayer.applyEdits(new Graphic[] { g }, null, null, new CallbackListener<FeatureEditResult[][]>() {
@Override
public void onError(Throwable e) {
Log.d(TAG, e.getMessage());
completeSaveAction(null);
}
@Override
public void onCallback(FeatureEditResult[][] results) {
completeSaveAction(results);
}
});
}
/**
* Reports result of 'Save' action to user and exit edit mode.
*
* @param results Results of applyEdits operation, or null if it failed.
*/
void completeSaveAction(final FeatureEditResult[][] results) {
runOnUiThread(new Runnable() {
@Override
public void run() {
if (results != null) {
if (results[0][0].isSuccess()) {
String msg = GeometryEditorActivity.this.getString(R.string.saved);
Toast.makeText(GeometryEditorActivity.this, msg, Toast.LENGTH_SHORT).show();
} else {
EditFailedDialogFragment frag = new EditFailedDialogFragment();
mDialogFragment = frag;
frag.setMessage(results[0][0].getError().getDescription());
frag.show(getFragmentManager(), TAG_DIALOG_FRAGMENTS);
}
}
setProgressBarIndeterminateVisibility(false);
exitEditMode();
}
});
}
/**
* Shows dialog asking user to select the type of feature to add.
*/
private void showFeatureTypeDialogFragment() {
FeatureTypeDialogFragment frag = new FeatureTypeDialogFragment();
mDialogFragment = frag;
frag.setListListener(new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
mTemplate = mTemplateList.get(position);
mTemplateLayer = mFeatureLayerList.get(position);
FeatureTypeData featureType = mFeatureTypeList.get(position);
Symbol symbol = featureType.getSymbol();
if (symbol instanceof MarkerSymbol) {
mEditMode = EditMode.POINT;
} else if (symbol instanceof LineSymbol) {
mEditMode = EditMode.POLYLINE;
} else if (symbol instanceof FillSymbol) {
mEditMode = EditMode.POLYGON;
}
clear();
mDialogFragment.dismiss();
// Set up use of magnifier on a long press on the map
mMapView.setShowMagnifierOnLongPress(true);
mLongPressEvent = null;
}
});
frag.setListAdapter(new FeatureTypeListAdapter(this, mFeatureTypeList));
frag.show(getFragmentManager(), TAG_DIALOG_FRAGMENTS);
}
/**
* Shows dialog asking user to confirm discarding the feature being added.
*/
private void showConfirmDiscardDialogFragment() {
ConfirmDiscardDialogFragment frag = new ConfirmDiscardDialogFragment();
mDialogFragment = frag;
frag.setYesListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
mDialogFragment.dismiss();
if (mClosingTheApp) {
finish();
} else {
exitEditMode();
}
}
});
frag.show(getFragmentManager(), TAG_DIALOG_FRAGMENTS);
}
/**
* Exits the edit mode state.
*/
void exitEditMode() {
mEditMode = EditMode.NONE;
clear();
mMapView.setShowMagnifierOnLongPress(false);
}
/**
* Using this method all the feature templates in the layer are listed. From the MapView we get all the layers in an
* array. Check which of them are instances of ArcGISFeatureLayer. From the feature layer we get all the templates and
* populate the list. Since we go through all the layers we obtain feature templates for all layers.
*/
private void listTemplates() {
mFeatureTypeList = new ArrayList<FeatureTypeData>();
mTemplateList = new ArrayList<FeatureTemplate>();
mFeatureLayerList = new ArrayList<ArcGISFeatureLayer>();
// Loop on all the layers in the MapView
Layer[] layers = mMapView.getLayers();
for (Layer l : layers) {
// Check if this is an ArcGISFeatureLayer
if (l instanceof ArcGISFeatureLayer) {
Log.d(TAG, l.getUrl());
ArcGISFeatureLayer featureLayer = (ArcGISFeatureLayer) l;
// Loop on all feature types in the layer
FeatureType[] types = featureLayer.getTypes();
for (FeatureType featureType : types) {
// Save data for each template for this feature type
addTemplates(featureLayer, featureType.getTemplates());
}
// If no templates provided by feature types, get templates from the layer itself
if (mFeatureTypeList.size() == 0) {
addTemplates(featureLayer, featureLayer.getTemplates());
}
}
}
}
/**
* Saves data for a set of feature templates.
*
* @param featureLayer Feature layer that the templates belong to.
* @param templates Array of templates to save.
*/
private void addTemplates(ArcGISFeatureLayer featureLayer, FeatureTemplate[] templates) {
for (FeatureTemplate featureTemplate : templates) {
String name = featureTemplate.getName();
Graphic g = featureLayer.createFeatureWithTemplate(featureTemplate, null);
Renderer renderer = featureLayer.getRenderer();
Symbol symbol = renderer.getSymbol(g);
final int WIDTH_IN_DP_UNITS = 30;
final float scale = getResources().getDisplayMetrics().density;
final int widthInPixels = (int) (WIDTH_IN_DP_UNITS * scale + 0.5f);
Bitmap bitmap = SymbolHelper.getLegendImage(symbol, widthInPixels, widthInPixels);
mFeatureTypeList.add(new FeatureTypeData(bitmap, name, symbol));
mTemplateList.add(featureTemplate);
mFeatureLayerList.add(featureLayer);
}
}
/**
* Redraws everything on the mGraphicsLayerEditing layer following an edit and updates the items shown on the action
* bar.
*/
void refresh() {
if (mGraphicsLayerEditing != null) {
mGraphicsLayerEditing.removeAll();
}
drawPolylineOrPolygon();
drawMidPoints();
drawVertices();
updateActionBar();
}
/**
* Updates action bar to show actions appropriate for current state of the app.
*/
private void updateActionBar() {
if (mEditMode == EditMode.NONE || mEditMode == EditMode.SAVING) {
// We are not editing
if (mEditMode == EditMode.NONE) {
showAction(R.id.action_add, true);
} else {
showAction(R.id.action_add, false);
}
showAction(R.id.action_discard, false);
showAction(R.id.action_save, false);
showAction(R.id.action_delete, false);
showAction(R.id.action_undo, false);
} else {
// We are editing
showAction(R.id.action_add, false);
showAction(R.id.action_discard, true);
if (isSaveValid()) {
showAction(R.id.action_save, true);
} else {
showAction(R.id.action_save, false);
}
if (mEditMode != EditMode.POINT && mPoints.size() > 0 && !mMidPointSelected) {
showAction(R.id.action_delete, true);
} else {
showAction(R.id.action_delete, false);
}
if (mEditingStates.size() > 0) {
showAction(R.id.action_undo, true);
} else {
showAction(R.id.action_undo, false);
}
}
}
/**
* Shows or hides an action bar item.
*
* @param resId Resource ID of the item.
* @param show true to show the item, false to hide it.
*/
private void showAction(int resId, boolean show) {
MenuItem item = mOptionsMenu.findItem(resId);
item.setEnabled(show);
item.setVisible(show);
}
/**
* Checks if it's valid to save the feature currently being created.
*
* @return true if valid.
*/
private boolean isSaveValid() {
int minPoints;
switch (mEditMode) {
case POINT:
minPoints = 1;
break;
case POLYGON:
minPoints = 3;
break;
case POLYLINE:
minPoints = 2;
break;
default:
return false;
}
return mPoints.size() >= minPoints;
}
/**
* Draws polyline or polygon (dependent on current mEditMode) between the vertices in mPoints.
*/
private void drawPolylineOrPolygon() {
Graphic graphic;
MultiPath multipath;
// Create and add graphics layer if it doesn't already exist
if (mGraphicsLayerEditing == null) {
mGraphicsLayerEditing = new GraphicsLayer();
mMapView.addLayer(mGraphicsLayerEditing);
}
if (mPoints.size() > 1) {
// Build a MultiPath containing the vertices
if (mEditMode == EditMode.POLYLINE) {
multipath = new Polyline();
} else {
multipath = new Polygon();
}
multipath.startPath(mPoints.get(0));
for (int i = 1; i < mPoints.size(); i++) {
multipath.lineTo(mPoints.get(i));
}
// Draw it using a line or fill symbol
if (mEditMode == EditMode.POLYLINE) {
graphic = new Graphic(multipath, new SimpleLineSymbol(Color.BLACK, 4));
} else {
SimpleFillSymbol simpleFillSymbol = new SimpleFillSymbol(Color.YELLOW);
simpleFillSymbol.setAlpha(100);
simpleFillSymbol.setOutline(new SimpleLineSymbol(Color.BLACK, 4));
graphic = new Graphic(multipath, (simpleFillSymbol));
}
mGraphicsLayerEditing.addGraphic(graphic);
}
}
/**
* Draws mid-point half way between each pair of vertices in mPoints.
*/
private void drawMidPoints() {
int index;
Graphic graphic;
mMidPoints.clear();
if (mPoints.size() > 1) {
// Build new list of mid-points
for (int i = 1; i < mPoints.size(); i++) {
Point p1 = mPoints.get(i - 1);
Point p2 = mPoints.get(i);
mMidPoints.add(new Point((p1.getX() + p2.getX()) / 2, (p1.getY() + p2.getY()) / 2));
}
if (mEditMode == EditMode.POLYGON && mPoints.size() > 2) {
// Complete the circle
Point p1 = mPoints.get(0);
Point p2 = mPoints.get(mPoints.size() - 1);
mMidPoints.add(new Point((p1.getX() + p2.getX()) / 2, (p1.getY() + p2.getY()) / 2));
}
// Draw the mid-points
index = 0;
for (Point pt : mMidPoints) {
if (mMidPointSelected && mInsertingIndex == index) {
graphic = new Graphic(pt, mRedMarkerSymbol);
} else {
graphic = new Graphic(pt, mGreenMarkerSymbol);
}
mGraphicsLayerEditing.addGraphic(graphic);
index++;
}
}
}
/**
* Draws point for each vertex in mPoints.
*/
private void drawVertices() {
int index = 0;
SimpleMarkerSymbol symbol;
for (Point pt : mPoints) {
if (mVertexSelected && index == mInsertingIndex) {
// This vertex is currently selected so make it red
symbol = mRedMarkerSymbol;
} else if (index == mPoints.size() - 1 && !mMidPointSelected && !mVertexSelected) {
// Last vertex and none currently selected so make it red
symbol = mRedMarkerSymbol;
} else {
// Otherwise make it black
symbol = mBlackMarkerSymbol;
}
Graphic graphic = new Graphic(pt, symbol);
mGraphicsLayerEditing.addGraphic(graphic);
index++;
}
}
/**
* Clears feature editing data and updates action bar.
*/
void clear() {
// Clear feature editing data
mPoints.clear();
mMidPoints.clear();
mEditingStates.clear();
mMidPointSelected = false;
mVertexSelected = false;
mInsertingIndex = 0;
if (mGraphicsLayerEditing != null) {
mGraphicsLayerEditing.removeAll();
}
// Update action bar to reflect the new state
updateActionBar();
int resId;
switch (mEditMode) {
case POINT:
resId = R.string.title_add_point;
break;
case POLYGON:
resId = R.string.title_add_polygon;
break;
case POLYLINE:
resId = R.string.title_add_polyline;
break;
case NONE:
default:
resId = R.string.app_name;
break;
}
getActionBar().setTitle(resId);
}
/**
* An instance of this class is created when a new point is added/moved/deleted. It records the state of editing at
* that time and allows edit operations to be undone.
*/
private class EditingStates {
ArrayList<Point> points = new ArrayList<Point>();
boolean midPointSelected = false;
boolean vertexSelected = false;
int insertingIndex;
public EditingStates(ArrayList<Point> points, boolean midpointselected, boolean vertexselected, int insertingindex) {
this.points.addAll(points);
this.midPointSelected = midpointselected;
this.vertexSelected = vertexselected;
this.insertingIndex = insertingindex;
}
}
/**
* Custom class for dragging a feature.
* Prototype only works with points.
* @author andy4683
*
*/
private class DragListener extends MapOnTouchListener{
MapView mapView;
Graphic graphic;
Graphic _moveGraphic = null;
Boolean start = false;
public DragListener(Context context, MapView view) {
super(context, view);
mapView = view;
}
@Override
public boolean onDragPointerMove(MotionEvent from, final MotionEvent to) {
Log.d("Test","start = " + start);
if(start == false){
int[] list = mGraphicsLayerEditing.getGraphicIDs(to.getX(), to.getY(), 10);
if(list.length > 0){
_moveGraphic = mGraphicsLayerEditing.getGraphic(list[0]);
Point point = mapView.toMapPoint(new Point(to.getX(), to.getY()));
Graphic moveGraphic = new Graphic(point, _moveGraphic.getSymbol(),_moveGraphic.getAttributes(),_moveGraphic.getDrawOrder());
mGraphicsLayerEditing.updateGraphic(_moveGraphic.getUid(), moveGraphic);
}
start = true;
}
else{
Point point = mapView.toMapPoint(new Point(to.getX(), to.getY()));
if(_moveGraphic != null){
Graphic moveGraphic = new Graphic(point, _moveGraphic.getSymbol(),_moveGraphic.getAttributes(),_moveGraphic.getDrawOrder());
mGraphicsLayerEditing.updateGraphic(_moveGraphic.getUid(), moveGraphic);
}
}
return false;
}
@Override
public boolean onDragPointerUp(MotionEvent from, final MotionEvent to) {
start = false;
Geometry geom = graphic.getGeometry();
Geometry.Type type = geom.getType();
int length = mGraphicsLayerEditing.getNumberOfGraphics();
int[] graphicsArr = mGraphicsLayerEditing.getGraphicIDs();
MultiPath multipath = new Polyline();
Graphic g1 = mGraphicsLayerEditing.getGraphic(graphicsArr[0]);
multipath.startPath((Point) g1.getGeometry());
for (int i = 1; i < length; i++) {
Graphic g2 = mGraphicsLayerEditing.getGraphic(graphicsArr[i]);
if(g2.getGeometry().getType() == Geometry.Type.POINT){
multipath.lineTo((Point) g2.getGeometry());
}
}
if(type == Geometry.Type.POLYLINE){
Graphic toBeModified = fl3.getGraphic(graphic.getUid());
int id = graphic.getUid();
fl3.updateGraphic(id, multipath);
}
// Draw it using a line or fill symbol
graphic = new Graphic(multipath, new SimpleLineSymbol(Color.BLACK, 4));
mGraphicsLayerEditing.addGraphic(graphic);
mapView.setOnTouchListener(new MyTouchListener(GeometryEditorActivity.this, mapView));
return super.onDragPointerUp(from, to);
}
}
/**
* The MapView's touch listener.
*/
private class MyTouchListener extends MapOnTouchListener {
MapView mapView;
Graphic graphic;
public MyTouchListener(Context context, MapView view) {
super(context, view);
mapView = view;
}
@Override
public boolean onDragPointerMove(MotionEvent from, final MotionEvent to) {
return super.onDragPointerMove(from, to);
}
@Override
public boolean onDragPointerUp(MotionEvent from, final MotionEvent to) {
if (mLongPressEvent != null) {
// This is the end of a long-press that will have displayed the magnifier.
// Handle the 'to' point as if it was a single tap.
handleTap(to);
mLongPressEvent = null;
}
return super.onDragPointerUp(from, to);
}
/**
* Custom code to grab the polyline that is touched and draw
* vertices points.
*/
@Override
public boolean onTouch(View v, MotionEvent event) {
if (event.getActionMasked() == MotionEvent.ACTION_DOWN) {
// Start of a new gesture. Make sure mLongPressEvent is cleared.
mLongPressEvent = null;
}
int[] list = fl3.getGraphicIDs(event.getX(), event.getY(), 10);
Geometry geom;
if(list.length > 0){
Graphic g = fl3.getGraphic(list[0]);
int index = 0;
SimpleMarkerSymbol symbol = mBlackMarkerSymbol;
geom = g.getGeometry();
int count = ((MultiPath) geom).getPointCount();
SimpleLineSymbol sls = new SimpleLineSymbol(Color.BLACK, 4);
Graphic graphic = null;
for (int i = 0;i < count; i++) {
graphic = new Graphic(((MultiPath) geom).getPoint(i), mRedMarkerSymbol);
mGraphicsLayerEditing.addGraphic(graphic);
}
dragListener = new DragListener(GeometryEditorActivity.this, mMapView);
dragListener.graphic = g;
mMapView.setOnTouchListener(dragListener);
}
// mEditMode = EditMode.POLYLINE
return super.onTouch(v, event);
}
@Override
public void onLongPress(MotionEvent point) {
// Set mLongPressEvent to indicate we are processing a long-press
mLongPressEvent = point;
super.onLongPress(point);
}
@Override
public boolean onSingleTap(final MotionEvent e) {
handleTap(e);
return true;
}
/***
* Handle a tap on the map (or the end of a magnifier long-press event).
*
* @param e The point that was tapped.
*/
private void handleTap(final MotionEvent e) {
//mEditMode = EditMode.POLYLINE;
// Ignore the tap if we're not creating a feature just now
if (mEditMode == EditMode.NONE || mEditMode == EditMode.SAVING) {
return;
}
Point point = mapView.toMapPoint(new Point(e.getX(), e.getY()));
// If we're creating a point, clear any existing point
if (mEditMode == EditMode.POINT) {
mPoints.clear();
}
// If a point is currently selected, move that point to tap point
if (mMidPointSelected || mVertexSelected) {
movePoint(point);
} else {
// If tap coincides with a mid-point, select that mid-point
int idx1 = getSelectedIndex(e.getX(), e.getY(), mMidPoints, mapView);
if (idx1 != -1) {
mMidPointSelected = true;
mInsertingIndex = idx1;
} else {
// If tap coincides with a vertex, select that vertex
int idx2 = getSelectedIndex(e.getX(), e.getY(), mPoints, mapView);
if (idx2 != -1) {
mVertexSelected = true;
mInsertingIndex = idx2;
} else {
// No matching point above, add new vertex at tap point
mPoints.add(point);
mEditingStates.add(new EditingStates(mPoints, mMidPointSelected, mVertexSelected, mInsertingIndex));
}
}
}
// Redraw the graphics layer
refresh();
}
/**
* Checks if a given location coincides (within a tolerance) with a point in a given array.
*
* @param x Screen coordinate of location to check.
* @param y Screen coordinate of location to check.
* @param points Array of points to check.
* @param map MapView containing the points.
* @return Index within points of matching point, or -1 if none.
*/
private int getSelectedIndex(double x, double y, ArrayList<Point> points, MapView map) {
final int TOLERANCE = 40; // Tolerance in pixels
if (points == null || points.size() == 0) {
return -1;
}
// Find closest point
int index = -1;
double distSQ_Small = Double.MAX_VALUE;
for (int i = 0; i < points.size(); i++) {
Point p = map.toScreenPoint(points.get(i));
double diffx = p.getX() - x;
double diffy = p.getY() - y;
double distSQ = diffx * diffx + diffy * diffy;
if (distSQ < distSQ_Small) {
index = i;
distSQ_Small = distSQ;
}
}
// Check if it's close enough
if (distSQ_Small < (TOLERANCE * TOLERANCE)) {
return index;
}
return -1;
}
/**
* Moves the currently selected point to a given location.
*
* @param point Location to move the point to.
*/
private void movePoint(Point point) {
if (mMidPointSelected) {
// Move mid-point to the new location and make it a vertex
mPoints.add(mInsertingIndex + 1, point);
} else {
// Must be a vertex: move it to the new location
ArrayList<Point> temp = new ArrayList<Point>();
for (int i = 0; i < mPoints.size(); i++) {
if (i == mInsertingIndex) {
temp.add(point);
} else {
temp.add(mPoints.get(i));
}
}
mPoints.clear();
mPoints.addAll(temp);
}
// Go back to the normal drawing mode and save the new editing state
mMidPointSelected = false;
mVertexSelected = false;
mEditingStates.add(new EditingStates(mPoints, mMidPointSelected, mVertexSelected, mInsertingIndex));
}
}
/**
* This class provides the adapter for the list of feature types.
*/
class FeatureTypeListAdapter extends ArrayAdapter<FeatureTypeData> {
public FeatureTypeListAdapter(Context context, ArrayList<FeatureTypeData> featureTypes) {
super(context, 0, featureTypes);
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
View view = convertView;
FeatureTypeViewHolder holder = null;
if (view == null) {
LayoutInflater inflater = (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE);
view = inflater.inflate(R.layout.listitem, null);
holder = new FeatureTypeViewHolder();
holder.imageView = (ImageView) view.findViewById(R.id.icon);
holder.textView = (TextView) view.findViewById(R.id.label);
} else {
holder = (FeatureTypeViewHolder) view.getTag();
}
FeatureTypeData featureType = getItem(position);
holder.imageView.setImageBitmap(featureType.getBitmap());
holder.textView.setText(mFeatureTypeList.get(position).getName());
view.setTag(holder);
return view;
}
}
/**
* Holds data related to an item in the list of feature types.
*/
class FeatureTypeViewHolder {
ImageView imageView;
TextView textView;
}
}
@NIT111
Copy link

NIT111 commented Oct 15, 2014

Hi how do we change the template functions or rename them... I tried a lot couldnt find it

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment