Create Local JSON Features

This sample depends on your Eclipse environment being setup to work with the ArcGIS Runtime SDK for Android. Please refer to the installation docs located at http://resources.arcgis.com/en/help/android-sdk/concepts/index.html#//01190000002m000000 if you need assistance.

Deploy Basemap Data

The CreateLocalJsonFeatures sample is an example of working with data in an offline setting. The sample depends on basemap data to be located on the device. This includes installing a local tile map cache (tpk) to device as described below:

NOTE: <storage> is used to represent your device external storage location.

More information about this location at https://developer.android.com/guide/topics/data/data-storage.html#filesExternal.

  1. Download Basemap data from http://www.arcgis.com/home/item.html?id=4497b7bb42e543b691027840d1b9092a.
  2. Create the the sample data folder at the root <storage> folder on your device, /<storage>/ArcGIS/samples/cljf/OfflineData.
  3. Push the downloaded basemap from step 1, ImageryTPK.tpk to your device. /<storage>/ArcGIS/samples/cljf/OfflineData/ImageryTPK.tpk

This sample will create json file in the directory set up above which represents the features selected in the app for offline usage.

How to use the Sample

This sample has 2 map activities, one which accesses services from ArcGIS Online and another which uses local data. The local data is a basemap deployed above and a json file representing features selected in the online map activity.

App usage

  1. Pan the map to center on the wind turbine features.
  2. Zoom into the a subsection of the wind turbine features you would like to persist locally to your device.
  3. Click the Edit ActionBar button.
  4. Single tap the map to create a polygon over the features you want to persist.
  5. Once your polygon is created, click the Save ActionBar button to save the geometry representation of the area you want to select.
  6. Click the Submit download ActionBar button to query the underlying features and create a local json feature set. A progess dialog will take focus.
  7. Once the dialog is dismissed, click the JSON file ActionBar button to switch activities and see your json feature set in the local map activity.

Sample Code

/* 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.android.tutorial.cljf;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;

import org.codehaus.jackson.JsonFactory;
import org.codehaus.jackson.JsonParseException;
import org.codehaus.jackson.JsonParser;

import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.os.Environment;
import android.widget.TextView;

import com.esri.android.map.MapView;
import com.esri.android.map.ags.ArcGISFeatureLayer;
import com.esri.android.map.ags.ArcGISLocalTiledLayer;
import com.esri.android.map.event.OnStatusChangedListener;
import com.esri.core.geometry.Polygon;
import com.esri.core.map.FeatureSet;

/**
 * The local map activity for CreateLocalJsonFeatures app.  
 * The MapView uses a local tile package (*.tpk) as a 
 * baselayer and sets it's extent from OnlineMapActivity.
 * It renders features from local json file persisted on disk
 * and created by OnlineMapActivity. 
 * 
 * @author EsriAndroidTeam
 * @version 2.0
 *
 */

public class LocalMapActivity extends Activity {

  TextView pathLabel;
  
  private static File demoDataFile;
  private static String offlineDataSDCardDirName;
  private static String filename;

  MapView mMapView;
  ArcGISLocalTiledLayer baseLayer;
  ArcGISFeatureLayer windTurbinesFeatureLayer;
  FeatureSet windTurbineFeatureSet;
  Polygon extent;
  
  protected static String windTurbineLayerDefinition;

  @Override
  protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_localmap);
    
    demoDataFile = Environment.getExternalStorageDirectory();
    offlineDataSDCardDirName = this.getResources().getString(R.string.config_data_sdcard_offline_dir);
    filename = this.getResources().getString(R.string.config_local_basemap);
    String basemap = demoDataFile + File.separator + offlineDataSDCardDirName + File.separator + filename;
    String basemapurl = "file://" + basemap;
    
    mMapView = (MapView) findViewById(R.id.localMap);
    baseLayer = new ArcGISLocalTiledLayer(basemapurl);

    // Get the json path from the intent
    Intent intent = getIntent();
    String jsonPath = intent.getStringExtra(OnlineMapActivity.EXTRA_JSON_PATH);
    // Get current extent from intent
    Bundle extras = intent.getExtras();
    extent = (Polygon)extras.getSerializable(OnlineMapActivity.CURRENT_MAP_EXTENT);
    
    // Display the path in the TextView 
    pathLabel = (TextView) findViewById(R.id.pathLable);
    pathLabel.setText(jsonPath);

    // Create wind turbine featurelayer from json
    windTurbineFeatureSet = createWindTurbinesFeatureSet(jsonPath);
    windTurbineLayerDefinition = this.getResources().getString(R.string.config_windturbine_layer_definition);
    ArcGISFeatureLayer.Options layerOptions = new ArcGISFeatureLayer.Options();
    layerOptions.mode = ArcGISFeatureLayer.MODE.SNAPSHOT;
    windTurbinesFeatureLayer = new ArcGISFeatureLayer(windTurbineLayerDefinition, windTurbineFeatureSet, layerOptions);
    
    // add layers to map
    mMapView.addLayer(baseLayer);
    mMapView.addLayer(windTurbinesFeatureLayer);
    
    mMapView.setOnStatusChangedListener(new OnStatusChangedListener(){
      private static final long serialVersionUID = 1L;

      @Override
      public void onStatusChanged(Object source, STATUS status) {
          if(source == mMapView && status == STATUS.INITIALIZED){
            mMapView.setExtent(extent);
          }
      }
    });
    
  }

  public FeatureSet createWindTurbinesFeatureSet(String path) {
    FeatureSet fs = null;
    
    try {
      JsonFactory factory = new JsonFactory();
      JsonParser parser = factory.createJsonParser(new FileInputStream(path));
      parser.nextToken();
      fs = FeatureSet.fromJson(parser);
    } catch (JsonParseException e) {
      e.printStackTrace();
    } catch (FileNotFoundException e) {
      e.printStackTrace();
    } catch (IOException e) {
      e.printStackTrace();
    } catch (Exception e) {
      e.printStackTrace();
    }
    
    return fs;
  } 

}
/* 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.android.tutorial.cljf;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;

import android.app.Activity;
import android.app.ProgressDialog;
import android.content.Context;
import android.content.Intent;
import android.graphics.Color;
import android.os.Bundle;
import android.os.Environment;
import android.os.Handler;
import android.util.Log;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.widget.Toast;

import com.esri.android.map.GraphicsLayer;
import com.esri.android.map.MapView;
import com.esri.android.map.ags.ArcGISFeatureLayer;
import com.esri.android.map.ags.ArcGISFeatureLayer.MODE;
import com.esri.android.map.ags.ArcGISTiledMapServiceLayer;
import com.esri.android.map.event.OnStatusChangedListener;
import com.esri.android.tutorial.cljf.Sketcher.SKETCHMODE;
import com.esri.core.geometry.Geometry;
import com.esri.core.geometry.Polygon;
import com.esri.core.geometry.SpatialReference;
import com.esri.core.map.CallbackListener;
import com.esri.core.map.FeatureSet;
import com.esri.core.renderer.SimpleRenderer;
import com.esri.core.symbol.SimpleLineSymbol;
import com.esri.core.tasks.SpatialRelationship;
import com.esri.core.tasks.ags.query.Query;

/**
 * The main activity for CreateLocalJsonFeatures app. It uses a Tiled Map
 * Service Layer from ArcGIS Online and Feature Layer from Esri's mobile demo
 * server. App allows users to create a sketch polygon to query underlying
 * features. Selected features are persisted device and shown as json feature
 * layer over a local tile map package.
 * 
 * json features are persisted to the following device dir:
 * /<storage_dir>/ArcGIS/samples/cljf/OfflineData/ where <storage-dir> is
 * relative to device naming.
 * 
 * Please be aware that the Feature Layer service is not guaranteed to be
 * running.
 * 
 * @author EsriAndroidTeam
 * @version 2.0
 * 
 */

public class OnlineMapActivity extends Activity {

	private static File demoDataFile;
	private static String offlineDataSDCardDirName;
	private static String filename;

	static ProgressDialog dialog;
	static Handler handler;

	protected static String OFFLINE_FILE_EXTENSION = ".json";

	public final static String EXTRA_JSON_PATH = "com.esri.android.tutorial.JSONPATH";
	public final static String CURRENT_MAP_EXTENT = "com.esri.android.tutorial.EXTENT";

	// Mapview and Layers
	MapView mMapView;
	ArcGISTiledMapServiceLayer basemap;
	ArcGISFeatureLayer windTurbine;
	// drawable layers
	GraphicsLayer gLayer;
	GraphicsLayer sketchLayer;
	Sketcher sketcher;
	Geometry selection;

	Context context;
	String path;
	
	//To check if the feature service is loaded or not
	boolean service_loaded = false;

	MenuItem start_sketch;
	MenuItem save_sketch;
	MenuItem query_features;
	MenuItem view_offline;

	@Override
	public void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.main);

		// create handler to update the UI
		handler = new Handler();

		// get sdcard resource names
		demoDataFile = Environment.getExternalStorageDirectory();
		offlineDataSDCardDirName = this.getResources().getString(
				R.string.config_data_sdcard_offline_dir);
		filename = this.getResources().getString(
				R.string.config_windturbine_name);

		// Retrieve the map and initial extent from XML layout
		mMapView = (MapView) findViewById(R.id.map);
		// create feature layer
		windTurbine = new ArcGISFeatureLayer(this.getResources().getString(
				R.string.featurelayer_url), MODE.SNAPSHOT);
		// add feature layer
		mMapView.addLayer(windTurbine);

		// add graphics layer to draw on
		sketchLayer = new GraphicsLayer();
		mMapView.addLayer(sketchLayer);

		// add graphics layer to show selection
		gLayer = new GraphicsLayer();
		SimpleRenderer selected = new SimpleRenderer(new SimpleLineSymbol(
				Color.RED, 2));
		gLayer.setRenderer(selected);
		mMapView.addLayer(gLayer);
		// attribute Esri logo on map
		mMapView.setEsriLogoVisible(true);

		mMapView.setOnStatusChangedListener(new OnStatusChangedListener() {

			private static final long serialVersionUID = 1L;

			public void onStatusChanged(final Object source, final STATUS status) {
				if (STATUS.LAYER_LOADED == status) {
					if (source instanceof ArcGISFeatureLayer) {
						// ArcGISFeatureLayer loaded successfully
						service_loaded = true;
					}
				}
			}
		});

	}

	@Override
	public boolean onCreateOptionsMenu(Menu menu) {
		MenuInflater inflater = getMenuInflater();
		inflater.inflate(R.menu.menu_layout, menu);

		start_sketch = menu.getItem(0);
		save_sketch = menu.getItem(1);
		query_features = menu.getItem(2);
		view_offline = menu.getItem(3);

		save_sketch.setEnabled(false);
		query_features.setEnabled(false);
		view_offline.setEnabled(false);
		return super.onCreateOptionsMenu(menu);
	}

	@Override
	public boolean onOptionsItemSelected(MenuItem item) {
		switch (item.getItemId()) {
		case R.id.start_sketch:
			if (service_loaded) {
				start_sketch.setEnabled(false);
				save_sketch.setEnabled(true);
				startSketch();
			} else {
				Toast.makeText(this, "Feature service layer is offline ",
						Toast.LENGTH_LONG).show();
			}
			return true;
		case R.id.save_sketch:
			save_sketch.setEnabled(false);
			query_features.setEnabled(true);
			saveSketch();
			return true;
		case R.id.query_features:
			query_features.setEnabled(false);
			view_offline.setEnabled(true);
			submit();
			return true;
		case R.id.view_offline:
			view_offline.setEnabled(false);
			start_sketch.setEnabled(true);
			sendMessage();
			return true;
		default:
			return super.onOptionsItemSelected(item);
		}

	}

	/*
	 * Create a polygon graphic representing the area to query for features
	 */

	public boolean startSketch() {
		sketcher = new Sketcher(mMapView, sketchLayer, gLayer,
				SKETCHMODE.POLYGON);
		sketcher.start();
		return true;
	}

	/*
	 * Save the area to query for features
	 */
	public boolean saveSketch() {
		selection = sketcher.save();
		sketcher.stop();
		return true;
	}

	/*
	 * Submit query based on saved polygon representing area to query
	 */
	public boolean submit() {
		gLayer.removeAll();
		queryFeatureLayer();
		return true;
	}

	/*
	 * Send the current extent and path to local json features to
	 * LocalMapActivity
	 */
	public boolean sendMessage() {

		if (path != null) {
			Intent intent = new Intent(this, LocalMapActivity.class);
			Polygon currExtent = mMapView.getExtent();
			intent.putExtra(CURRENT_MAP_EXTENT, currExtent);
			intent.putExtra(EXTRA_JSON_PATH, path);
			startActivity(intent);
		} else {
			Toast toast = Toast.makeText(this,
					"Features did not save to disk!  Please try again.",
					Toast.LENGTH_LONG);
			toast.show();
		}
		return true;
	}

	/*
	 * Create the json file location and name structure
	 */
	public String createJsonFile() {
		StringBuilder sb = new StringBuilder();
		sb.append(demoDataFile.getAbsolutePath());
		sb.append(File.separator);
		sb.append(offlineDataSDCardDirName);
		sb.append(File.separator);
		sb.append(filename);
		sb.append(OFFLINE_FILE_EXTENSION);
		return sb.toString();
	}

	/*
	 * Query features from the feature layer
	 */
	private void queryFeatureLayer() {
		// show progress dialog while querying feature layer
		dialog = ProgressDialog.show(mMapView.getContext(),
				"Query FeatureLayer", "Creating local JSON FeatureLayer");
		// create a Query
		Query query = new Query();
		// set spatial reference
		SpatialReference sr = SpatialReference.create(102100);
		// set the geometry to the sketch polygon
		query.setGeometry(selection);
		// query features that are completely contained by selection
		query.setSpatialRelationship(SpatialRelationship.CONTAINS);
		// set query in/out spatial ref
		query.setInSpatialReference(sr);
		query.setOutSpatialReference(sr);
		// return all features
		query.setOutFields(new String[] { "*" });
		// include geometry in result set
		query.setReturnGeometry(true);
		// run query on FeatureLayer off UI thread
		windTurbine.queryFeatures(query, new CallbackListener<FeatureSet>() {

			// an error occurred, log exception
			@Override
			public void onError(Throwable e) {
				Log.e("Test", "Unable to perform query", e);
				dialog.dismiss();
			}

			// create json from resulting FeatureSet
			@Override
			public void onCallback(FeatureSet result) {
				if (result != null) {
					FileOutputStream outstream = null;
					try {
						// create feature set as json string
						String fsstring = FeatureSet.toJson(result);
						// create fully qualified path for json file
						path = createJsonFile();
						// create a File from json fully qualified path
						File outfile = new File(path);
						// create output stream to write to json file
						outstream = new FileOutputStream(outfile);
						outstream.write(fsstring.getBytes());
						// close output stream
						outstream.close();
						// create new Runnable to be added to message queue
						handler.post(new MyRunnable());
					} catch (Exception e) {
						e.printStackTrace();
						if (outstream != null) {
							try {
								outstream.close();
								handler.post(new MyRunnable());
							} catch (IOException e1) {
								e1.printStackTrace();
							}
						}
					}

				}
			}
		});
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see android.app.Activity#onPause()
	 */
	@Override
	protected void onPause() {
		super.onPause();
		mMapView.pause();
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see android.app.Activity#onResume()
	 */
	@Override
	protected void onResume() {
		super.onResume();
		mMapView.unpause();
	}

	/*
	 * Dismiss dialog if activity is destroyed(non-Javadoc)
	 * 
	 * @see android.app.Activity#onDestroy()
	 */
	@Override
	protected void onDestroy() {
		super.onDestroy();
		if (dialog != null && dialog.isShowing()) {
			dialog.dismiss();
			dialog = null;
		}
	}

	/*
	 * Dismiss progress dialog when query thread completes
	 */
	static public class MyRunnable implements Runnable {
		@Override
		public void run() {
			dialog.dismiss();
		}

	}

}
/* 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.android.tutorial.cljf;

import java.util.ArrayList;

import android.graphics.Color;

import com.esri.android.map.GraphicsLayer;
import com.esri.android.map.MapView;
import com.esri.android.map.event.OnSingleTapListener;
import com.esri.core.geometry.Envelope;
import com.esri.core.geometry.Geometry;
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.Graphic;
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.core.symbol.Symbol;

/**
 * Class to allow interaction with a maps
 * graphic layer to create a geometric shape.
 * 
 * @author EsriAndroidTeam
 * @version 2.0
 *
 */
public class Sketcher {
	
	public enum SKETCHMODE {
		POINT, POLYLINE, POLYGON, ENVELOPE
	}
	
	/**
	 * Sketcher constructor which creates all the tools to draw on the
	 * provided map, layers, and geometry types.
	 * 
	 * @param map MapView The MapView which contains the layers
	 * @param sketchlayer GraphicsLayer The layer to draw on
	 * @param storagelayer GraphicsLayer
	 * @param mode SKETCHMODE The Geometry type to be drawn
	 */
	public Sketcher(MapView map, GraphicsLayer sketchlayer,
			GraphicsLayer storagelayer, SKETCHMODE mode) {
		this.map = map;
		this.sketchlayer = sketchlayer;
		this.storagelayer = storagelayer;
		this.mode = mode;
		this.pointList = new ArrayList<Point>();

		sketchFillSymbol = new SimpleFillSymbol(Color.MAGENTA);
		sketchFillSymbol.setAlpha(100);
		sketchFillSymbol.setOutline(new SimpleLineSymbol(Color.GRAY, 4));

		sketchLineSymbol = new SimpleLineSymbol(Color.MAGENTA, 4);

		sketchMarkerSymbol = new SimpleMarkerSymbol(Color.GREEN, 10,
				STYLE.CIRCLE);

		storageFillSymbol = new SimpleFillSymbol(Color.argb(100, 204, 204,
				204));
		storageFillSymbol.setAlpha(100);

		storageLineSymbol = new SimpleLineSymbol(Color.BLACK, 4);
		storageLineSymbol.setAlpha(200);

		storageMarkerSymbol = new SimpleMarkerSymbol(Color.BLACK, 8,
				SimpleMarkerSymbol.STYLE.CIRCLE);
	}
	/**
	 * This method is called when the sending activity wants to start
	 * drawing a geometry type on a graphics layer
	 */
	public void start() {
		map.setOnSingleTapListener(new SketchingListener());
	}

	public void stop() {
		map.setOnSingleTapListener(null);
	}

	/**
	 * This method is called when the sending activity has finished
	 * and requests the return geometry.
	 * @return Geometry The 
	 */
	public Geometry save() {
		Symbol symbol;
		if (editedGeometry instanceof Polygon
				|| editedGeometry instanceof Envelope) {
			symbol = storageFillSymbol;
		} else if (editedGeometry instanceof Polyline) {
			symbol = storageLineSymbol;
		} else {
			symbol = storageMarkerSymbol;
		}
		
		Graphic gr = new Graphic(editedGeometry, symbol);
		if (storagelayer != null) {
		   storagelayer.addGraphic(gr);
		}
		sketchlayer.removeAll();
		pointList.clear();
		return editedGeometry;

	}

	void rendertoSketchlayer() {
		sketchlayer.removeAll();
		Symbol symbol;
		if ((mode == SKETCHMODE.POLYGON || mode == SKETCHMODE.POLYLINE) && pointList.size() > 2) {
			MultiPath multiPath;

			if (mode == SKETCHMODE.POLYGON) {
				multiPath = new Polygon();
				symbol = sketchFillSymbol;
			} else {
				multiPath = new Polyline();
				symbol = sketchLineSymbol;
			}
			multiPath.startPath(pointList.get(0));
			for (int i = 1; i < pointList.size(); i++) {
				multiPath.lineTo(pointList.get(i));
			}
			editedGeometry = multiPath;

		} else if (mode == SKETCHMODE.POINT) {
			editedGeometry = pointList.get(0);
			symbol = sketchMarkerSymbol;
		} else { // SKETCHMODE : Envelope
			Envelope envelope = new Envelope();
			for (Point point : pointList) {
				envelope.merge(point);
			}
			editedGeometry = envelope;
			symbol = sketchFillSymbol;

		}

		Graphic gr = new Graphic(editedGeometry, symbol);
		sketchlayer.addGraphic(gr);
		for (Point point : pointList) {
			gr = new Graphic(point, sketchMarkerSymbol);
			sketchlayer.addGraphic(gr);
		}

	}

	/**
	 * Method getStorageFillSymbol.
	 * @return SimpleFillSymbol
	 */
	public SimpleFillSymbol getStorageFillSymbol() {
		return storageFillSymbol;
	}

	/**
	 * Method getStorageLineSymbol.
	 * @return SimpleLineSymbol
	 */
	public SimpleLineSymbol getStorageLineSymbol() {
		return storageLineSymbol;
	}

	/**
	 * Method getStorageMarkerSymbol.
	 * @return SimpleMarkerSymbol
	 */
	public SimpleMarkerSymbol getStorageMarkerSymbol() {
		return storageMarkerSymbol;
	}
	
	/**
	 * Using a single tap interaction this class allows for 
	 * drawing a geometry type, e.g. POINT, LINE, POlYGON, on 
	 * a graphics layer.
	 */
	private class SketchingListener implements OnSingleTapListener {

		private static final long serialVersionUID = 1L;

		public SketchingListener() {
		}

		/**
		 * This method uses a single tap interaction with device to draw
		 * on a graphics layer.  
		 * @param x float The x screen coordinate
		 * @param y float The y screen coordinate
		 * @see com.esri.android.map.event.OnSingleTapListener#onSingleTap(float, float)
		 */
		@Override
		public void onSingleTap(float x, float y) {
			Point curPoint = map.toMapPoint(x, y);
			if (mode == SKETCHMODE.POINT) {
				if (pointList.size() == 1) {
					pointList.set(0, curPoint);
				} else {
					pointList.add(curPoint);
				}
			} else if (mode == SKETCHMODE.POLYLINE
					|| mode == SKETCHMODE.POLYGON) {
				pointList.add(curPoint);
			} else if (mode == SKETCHMODE.ENVELOPE) {
				if (pointList.size() == 2) {
					pointList.set(1, curPoint);
				} else {
					pointList.add(curPoint);
				}
			}
			rendertoSketchlayer();
		}
	}
	
	private GraphicsLayer sketchlayer;
	private GraphicsLayer storagelayer;

	private SimpleFillSymbol sketchFillSymbol;
	private SimpleLineSymbol sketchLineSymbol;
	private SimpleMarkerSymbol sketchMarkerSymbol;

	private SimpleLineSymbol storageLineSymbol;
	private SimpleMarkerSymbol storageMarkerSymbol;

	private Geometry editedGeometry;
	
	private SimpleFillSymbol storageFillSymbol;
	
	SKETCHMODE mode;
	MapView map;
	ArrayList<Point> pointList;
}
Feedback on this topic?