diff --git a/demo/AndroidManifest.xml b/demo/AndroidManifest.xml index ea88a8e0b..026e23735 100644 --- a/demo/AndroidManifest.xml +++ b/demo/AndroidManifest.xml @@ -57,6 +57,7 @@ + diff --git a/demo/build.gradle b/demo/build.gradle index 0ffb30225..965c91747 100644 --- a/demo/build.gradle +++ b/demo/build.gradle @@ -14,12 +14,12 @@ dependencies { compile project(':library') // Or, fetch from Maven: // compile 'com.google.maps.android:android-maps-utils:0.3+' - compile 'com.google.android.gms:play-services-maps:6.+' + compile 'com.google.android.gms:play-services:6.+' } android { compileSdkVersion 19 - buildToolsVersion "21.1.2" + buildToolsVersion "21.1.1" sourceSets { main { diff --git a/demo/res/layout/geojson_demo.xml b/demo/res/layout/geojson_demo.xml new file mode 100644 index 000000000..e3ca7217b --- /dev/null +++ b/demo/res/layout/geojson_demo.xml @@ -0,0 +1,18 @@ + + + + + + + + \ No newline at end of file diff --git a/demo/res/values/strings.xml b/demo/res/values/strings.xml index ddd6fd4d5..b5a53cb36 100644 --- a/demo/res/values/strings.xml +++ b/demo/res/values/strings.xml @@ -8,6 +8,9 @@ Data from <a href = "%s">data.gov.au</a>, modified under <a href = \"http://creativecommons.org/licenses/by/3.0/au/\">CC BY 3.0 AU</a> http://data.gov.au/dataset/police-station-locations/resource/76110b24-0f0a-4c29-9583-3f99eaba486c http://data.gov.au/dataset/location-of-medicare-offices/resource/5d38e1be-4011-49c4-8b8b-75405eeb1088 + Remove + Add + Toggle Vis @string/police_stations @string/medicare diff --git a/demo/src/com/google/maps/android/utils/demo/GeoJsonDemoActivity.java b/demo/src/com/google/maps/android/utils/demo/GeoJsonDemoActivity.java new file mode 100644 index 000000000..c98d40c37 --- /dev/null +++ b/demo/src/com/google/maps/android/utils/demo/GeoJsonDemoActivity.java @@ -0,0 +1,131 @@ +package com.google.maps.android.utils.demo; + +import com.google.android.gms.maps.model.BitmapDescriptor; +import com.google.android.gms.maps.model.BitmapDescriptorFactory; +import com.google.maps.android.geojson.GeoJsonFeature; +import com.google.maps.android.geojson.GeoJsonLayer; +import com.google.maps.android.geojson.GeoJsonPointStyle; + +import org.json.JSONException; +import org.json.JSONObject; + +import android.os.AsyncTask; +import android.util.Log; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.net.URL; + +public class GeoJsonDemoActivity extends BaseDemoActivity { + + private final static String mLogTag = "GeoJsonDemo"; + + // GeoJSON file to download + private final String mGeoJsonUrl + = "http://earthquake.usgs.gov/earthquakes/feed/v1.0/summary/all_day.geojson"; + + private GeoJsonLayer mLayer; + + /** + * Assigns a color based on the given magnitude + */ + private static float magnitudeToColor(double magnitude) { + if (magnitude < 1.0) { + return BitmapDescriptorFactory.HUE_CYAN; + } else if (magnitude < 2.5) { + return BitmapDescriptorFactory.HUE_GREEN; + } else if (magnitude < 4.5) { + return BitmapDescriptorFactory.HUE_YELLOW; + } else { + return BitmapDescriptorFactory.HUE_RED; + } + } + + protected int getLayoutId() { + return R.layout.geojson_demo; + } + + @Override + protected void startDemo() { + DownloadGeoJsonFile downloadGeoJsonFile = new DownloadGeoJsonFile(); + // Download the GeoJSON file + downloadGeoJsonFile.execute(mGeoJsonUrl); + } + + /** + * Adds a point style to all features to change the color of the marker based on its magnitude + * property + */ + private void addColorsToMarkers() { + // Iterate over all the features stored in the layer + for (GeoJsonFeature feature : mLayer.getFeatures()) { + // Check if the magnitude property exists + if (feature.hasProperty("mag") && feature.hasProperty("place")) { + double magnitude = Double.parseDouble(feature.getProperty("mag")); + + // Get the icon for the feature + BitmapDescriptor pointIcon = BitmapDescriptorFactory + .defaultMarker(magnitudeToColor(magnitude)); + + // Create a new point style + GeoJsonPointStyle pointStyle = new GeoJsonPointStyle(); + + // Set options for the point style + pointStyle.setIcon(pointIcon); + pointStyle.setTitle("Magnitude of " + magnitude); + pointStyle.setSnippet("Earthquake occured " + feature.getProperty("place")); + + // Assign the point style to the feature + feature.setPointStyle(pointStyle); + } + } + } + + private class DownloadGeoJsonFile extends AsyncTask { + + @Override + protected JSONObject doInBackground(String... params) { + try { + // Open a stream from the URL + InputStream stream = new URL(params[0]).openStream(); + + String line; + StringBuilder result = new StringBuilder(); + BufferedReader reader = new BufferedReader(new InputStreamReader(stream)); + + while ((line = reader.readLine()) != null) { + // Read and save each line of the stream + result.append(line); + } + + // Close the stream + reader.close(); + stream.close(); + + // Convert result to JSONObject + return new JSONObject(result.toString()); + } catch (IOException e) { + Log.e(mLogTag, "GeoJSON file could not be read"); + } catch (JSONException e) { + Log.e(mLogTag, "GeoJSON file could not be converted to a JSONObject"); + } + return null; + } + + @Override + protected void onPostExecute(JSONObject jsonObject) { + if (jsonObject != null) { + // Create a new GeoJsonLayer, pass in downloaded GeoJSON file as JSONObject + mLayer = new GeoJsonLayer(getMap(), jsonObject); + // Add the layer onto the map + addColorsToMarkers(); + mLayer.addLayerToMap(); + } + } + + + } +} + diff --git a/demo/src/com/google/maps/android/utils/demo/MainActivity.java b/demo/src/com/google/maps/android/utils/demo/MainActivity.java index 8a04dd1c4..f1213f2b0 100644 --- a/demo/src/com/google/maps/android/utils/demo/MainActivity.java +++ b/demo/src/com/google/maps/android/utils/demo/MainActivity.java @@ -10,6 +10,8 @@ public class MainActivity extends Activity implements View.OnClickListener { private ViewGroup mListView; + //Comment to see if I can push to the repository + @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); @@ -26,6 +28,7 @@ protected void onCreate(Bundle savedInstanceState) { addDemo("Generating tiles", TileProviderAndProjectionDemo.class); addDemo("Heatmaps", HeatmapsDemoActivity.class); addDemo("Heatmaps with Places API", HeatmapsPlacesDemoActivity.class); + addDemo("GeoJSON Layer", GeoJsonDemoActivity.class); } private void addDemo(String demoName, Class activityClass) { diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index c45883a75..58e8e6f32 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,4 +1,4 @@ -#Sat Dec 20 10:27:44 MST 2014 +#Wed Dec 17 14:51:18 EST 2014 distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME diff --git a/library/AndroidManifest.xml b/library/AndroidManifest.xml index 2c2bb5d4d..15767d90c 100644 --- a/library/AndroidManifest.xml +++ b/library/AndroidManifest.xml @@ -3,5 +3,10 @@ package="com.google.maps.android"> - + + + + diff --git a/library/build.gradle b/library/build.gradle index df60dea47..77bfc7ef2 100644 --- a/library/build.gradle +++ b/library/build.gradle @@ -4,7 +4,7 @@ buildscript { } dependencies { - classpath 'com.android.tools.build:gradle:1.0.0' + classpath 'com.android.tools.build:gradle:1.0.0-rc4' } } @@ -16,13 +16,13 @@ archivesBaseName = 'android-maps-utils' group = 'com.google.maps.android' dependencies { - compile 'com.google.android.gms:play-services-maps:6.5.87' + compile 'com.google.android.gms:play-services:6.+' } android { compileSdkVersion 19 - buildToolsVersion "21.1.2" + buildToolsVersion "21.0.1" sourceSets { main { diff --git a/library/src/com/google/maps/android/geojson/GeoJsonFeature.java b/library/src/com/google/maps/android/geojson/GeoJsonFeature.java new file mode 100644 index 000000000..a5a940b14 --- /dev/null +++ b/library/src/com/google/maps/android/geojson/GeoJsonFeature.java @@ -0,0 +1,276 @@ +package com.google.maps.android.geojson; + +import com.google.android.gms.maps.model.LatLngBounds; + +import java.util.Arrays; +import java.util.HashMap; +import java.util.Observable; +import java.util.Observer; + +/** + * A GeoJsonFeature has a geometry, bounding box, id and set of properties. Styles are also stored + * in this class. + */ +public class GeoJsonFeature extends Observable implements Observer { + + private final String mId; + + private final LatLngBounds mBoundingBox; + + private final HashMap mProperties; + + private GeoJsonGeometry mGeometry; + + private GeoJsonPointStyle mPointStyle; + + private GeoJsonLineStringStyle mLineStringStyle; + + private GeoJsonPolygonStyle mPolygonStyle; + + /** + * Creates a new GeoJsonFeature object + * + * @param geometry type of geometry to assign to the feature + * @param id common identifier of the feature + * @param properties hashmap of containing properties related to the feature + * @param boundingBox bounding box of the feature + */ + public GeoJsonFeature(GeoJsonGeometry geometry, String id, + HashMap properties, LatLngBounds boundingBox) { + mGeometry = geometry; + mId = id; + mBoundingBox = boundingBox; + if (properties == null) { + mProperties = new HashMap(); + } else { + mProperties = properties; + } + } + + /** + * Returns all the stored property keys + * + * @return iterable of property keys + */ + public Iterable getPropertyKeys() { + return mProperties.keySet(); + } + + /** + * Gets the value for a stored property + * + * @param property key of the property + * @return value of the property if its key exists, otherwise null + */ + public String getProperty(String property) { + return mProperties.get(property); + } + + /** + * Store a new property key and value + * + * @param property key of the property to store + * @param propertyValue value of the property to store + * @return previous value with the same key, otherwise null if the key didn't exist + */ + public String setProperty(String property, String propertyValue) { + return mProperties.put(property, propertyValue); + } + + /** + * Checks whether the given property key exists + * + * @param property key of the property to check + * @return true if property key exists, false otherwise + */ + public boolean hasProperty(String property) { + return mProperties.containsKey(property); + } + + /** + * Removes a given property + * + * @param property key of the property to remove + * @return value of the removed property or null if there was no corresponding key + */ + public String removeProperty(String property) { + return mProperties.remove(property); + } + + /** + * Returns the style used to render GeoJsonPoints + * + * @return style used to render GeoJsonPoints + */ + public GeoJsonPointStyle getPointStyle() { + return mPointStyle; + } + + /** + * Sets the style used to render GeoJsonPoints + * + * @param pointStyle style used to render GeoJsonPoints + */ + public void setPointStyle(GeoJsonPointStyle pointStyle) { + if (pointStyle == null) { + throw new IllegalArgumentException("Point style cannot be null"); + } + + if (mPointStyle != null) { + // Remove observer for previous style + mPointStyle.deleteObserver(this); + } + mPointStyle = pointStyle; + mPointStyle.addObserver(this); + checkRedrawFeature(mPointStyle); + } + + /** + * Returns the style used to render GeoJsonLineStrings + * + * @return style used to render GeoJsonLineStrings + */ + public GeoJsonLineStringStyle getLineStringStyle() { + return mLineStringStyle; + } + + /** + * Sets the style used to render GeoJsonLineStrings + * + * @param lineStringStyle style used to render GeoJsonLineStrings + */ + public void setLineStringStyle(GeoJsonLineStringStyle lineStringStyle) { + if (lineStringStyle == null) { + throw new IllegalArgumentException("Line string style cannot be null"); + } + + if (mLineStringStyle != null) { + // Remove observer for previous style + mLineStringStyle.deleteObserver(this); + } + mLineStringStyle = lineStringStyle; + mLineStringStyle.addObserver(this); + checkRedrawFeature(mLineStringStyle); + + } + + /** + * Returns the style used to render GeoJsonPolygons + * + * @return style used to render GeoJsonPolygons + */ + public GeoJsonPolygonStyle getPolygonStyle() { + return mPolygonStyle; + } + + /** + * Sets the style used to render GeoJsonPolygons + * + * @param polygonStyle style used to render GeoJsonPolygons + */ + public void setPolygonStyle(GeoJsonPolygonStyle polygonStyle) { + if (polygonStyle == null) { + throw new IllegalArgumentException("Polygon style cannot be null"); + } + + if (mPolygonStyle != null) { + // Remove observer for previous style + mPolygonStyle.deleteObserver(this); + } + mPolygonStyle = polygonStyle; + mPolygonStyle.addObserver(this); + checkRedrawFeature(mPolygonStyle); + + } + + /** + * Checks whether the new style that was set requires the feature to be redrawn. If the + * geometry + * and the style that was set match, then the feature is redrawn. + * + * @param style style to check if a redraw is needed + */ + private void checkRedrawFeature(GeoJsonStyle style) { + if (mGeometry != null && Arrays.asList(style.getGeometryType()) + .contains(mGeometry.getType())) { + // Don't redraw objects that aren't on the map + setChanged(); + notifyObservers(); + } + } + + /** + * Gets the stored GeoJsonGeometry + * + * @return GeoJsonGeometry + */ + public GeoJsonGeometry getGeometry() { + return mGeometry; + } + + /** + * Sets the stored GeoJsonGeometry and redraws it on the layer if it has already been added + * + * @param geometry GeoJsonGeometry to set + */ + public void setGeometry(GeoJsonGeometry geometry) { + mGeometry = geometry; + setChanged(); + notifyObservers(); + } + + /** + * Gets the ID of the feature + * + * @return ID of the feature, if there is no ID then null will be returned + */ + public String getId() { + return mId; + } + + /** + * Checks if the geometry is assigned + * + * @return true if feature contains geometry object, otherwise null + */ + public boolean hasGeometry() { + return (mGeometry != null); + } + + /** + * Gets the array containing the coordinates of the bounding box for the feature. If + * the feature did not have a bounding box then null will be returned. + * + * @return LatLngBounds containing bounding box of the feature, null if no bounding box + */ + public LatLngBounds getBoundingBox() { + return mBoundingBox; + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder("Feature{"); + sb.append("\n bounding box=").append(mBoundingBox); + sb.append(",\n geometry=").append(mGeometry); + sb.append(",\n point style=").append(mPointStyle); + sb.append(",\n line string style=").append(mLineStringStyle); + sb.append(",\n polygon style=").append(mPolygonStyle); + sb.append(",\n id=").append(mId); + sb.append(",\n properties=").append(mProperties); + sb.append("\n}\n"); + return sb.toString(); + } + + /** + * Update is called if the developer modifies a style that is stored in this feature + * + * @param observable GeoJsonStyle object + * @param data null, no extra argument is passed through the notifyObservers method + */ + @Override + public void update(Observable observable, Object data) { + if (observable instanceof GeoJsonStyle) { + checkRedrawFeature((GeoJsonStyle) observable); + } + } +} diff --git a/library/src/com/google/maps/android/geojson/GeoJsonGeometry.java b/library/src/com/google/maps/android/geojson/GeoJsonGeometry.java new file mode 100644 index 000000000..39a2f6c2b --- /dev/null +++ b/library/src/com/google/maps/android/geojson/GeoJsonGeometry.java @@ -0,0 +1,16 @@ +package com.google.maps.android.geojson; + +/** + * Represents a GeoJSON geometry object. Note that only the first two elements in each position are + * considered. Altitude and any further values are not considered. + */ +public interface GeoJsonGeometry { + + /** + * Gets the type of geometry. The type of geometry conforms to the GeoJSON 'type' + * specification. + * + * @return type of geometry + */ + public String getType(); +} diff --git a/library/src/com/google/maps/android/geojson/GeoJsonGeometryCollection.java b/library/src/com/google/maps/android/geojson/GeoJsonGeometryCollection.java new file mode 100644 index 000000000..4a1354863 --- /dev/null +++ b/library/src/com/google/maps/android/geojson/GeoJsonGeometryCollection.java @@ -0,0 +1,49 @@ +package com.google.maps.android.geojson; + +import java.util.List; + +/** + * A GeoJsonGeometryCollection geometry contains a number of GeoJsonGeometry objects. + */ +public class GeoJsonGeometryCollection implements GeoJsonGeometry { + + private final static String GEOMETRY_TYPE = "GeometryCollection"; + + private final List mGeometries; + + /** + * Creates a new GeoJsonGeometryCollection object + * + * @param geometries array of GeoJsonGeometry objects to add to the GeoJsonGeometryCollection + */ + public GeoJsonGeometryCollection( + List geometries) { + if (geometries == null) { + throw new IllegalArgumentException("Geometries cannot be null"); + } + mGeometries = geometries; + } + + /** {@inheritDoc} */ + @Override + public String getType() { + return GEOMETRY_TYPE; + } + + /** + * Gets the stored GeoJsonGeometry objects + * + * @return stored GeoJsonGeometry objects + */ + public List getGeometries() { + return mGeometries; + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(GEOMETRY_TYPE).append("{"); + sb.append("\n Geometries=").append(mGeometries); + sb.append("\n}\n"); + return sb.toString(); + } +} diff --git a/library/src/com/google/maps/android/geojson/GeoJsonLayer.java b/library/src/com/google/maps/android/geojson/GeoJsonLayer.java new file mode 100644 index 000000000..e1997b0d1 --- /dev/null +++ b/library/src/com/google/maps/android/geojson/GeoJsonLayer.java @@ -0,0 +1,223 @@ +package com.google.maps.android.geojson; + +import com.google.android.gms.maps.GoogleMap; +import com.google.android.gms.maps.model.LatLngBounds; + +import org.json.JSONException; +import org.json.JSONObject; + +import android.content.Context; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.util.HashMap; + +/** + * A class that allows the developer to import GeoJSON data, style it and interact with the + * imported data. + * + * To create a new GeoJsonLayer from a resource stored locally + * {@code GeoJsonLayer layer = new GeoJsonLayer(getMap(), R.raw.resource, + * getApplicationContext());} + * + * To render the imported GeoJSON data onto the layer + * {@code layer.addLayerToMap();} + * + * To remove the rendered data from the layer + * {@code layer.removeLayerFromMap();} + */ +public class GeoJsonLayer { + + private final GeoJsonRenderer mRenderer; + + private LatLngBounds mBoundingBox; + + /** + * Creates a new GeoJsonLayer object. Default styles are applied to the GeoJsonFeature objects. + * + * @param map map where the layer is to be rendered + * @param geoJsonFile GeoJSON data to add to the layer + */ + public GeoJsonLayer(GoogleMap map, JSONObject geoJsonFile) { + if (geoJsonFile == null) { + throw new IllegalArgumentException("GeoJSON file cannot be null"); + } + + mBoundingBox = null; + GeoJsonParser parser = new GeoJsonParser(geoJsonFile); + // Assign GeoJSON bounding box for FeatureCollection + mBoundingBox = parser.getBoundingBox(); + HashMap geoJsonFeatures = new HashMap(); + for (GeoJsonFeature feature : parser.getFeatures()) { + geoJsonFeatures.put(feature, null); + } + mRenderer = new GeoJsonRenderer(map, geoJsonFeatures); + } + + /** + * Creates a new GeoJsonLayer object. Default styles are applied to the GeoJsonFeature objects. + * + * @param map map where the layer is to be rendered + * @param resourceId GeoJSON file to add to the layer + * @param context context of the application, required to open the GeoJSON file + * @throws IOException if the file cannot be open for read + * @throws JSONException if the JSON file has invalid syntax and cannot be parsed successfully + */ + public GeoJsonLayer(GoogleMap map, int resourceId, Context context) + throws IOException, JSONException { + this(map, createJsonFileObject(context.getResources().openRawResource(resourceId))); + } + + /** + * Takes a character input stream and converts it into a JSONObject + * + * @param stream character input stream representing the GeoJSON file + * @return JSONObject with the GeoJSON data + * @throws IOException if the file cannot be opened for read + * @throws JSONException if the JSON file has poor structure + */ + private static JSONObject createJsonFileObject(InputStream stream) + throws IOException, JSONException { + String line; + StringBuilder result = new StringBuilder(); + // Reads from stream + BufferedReader reader = new BufferedReader(new InputStreamReader(stream)); + try { + // Read each line of the GeoJSON file into a string + while ((line = reader.readLine()) != null) { + result.append(line); + } + } finally { + reader.close(); + } + // Converts the result string into a JSONObject + return new JSONObject(result.toString()); + } + + /** + * Gets an iterable of all GeoJsonFeature elements that have been added to the layer + * + * @return iterable of GeoJsonFeature elements + */ + public Iterable getFeatures() { + return mRenderer.getFeatures(); + } + + /** + * Adds all the GeoJsonFeature objects parsed from the given GeoJSON data onto the map + */ + public void addLayerToMap() { + mRenderer.addLayerToMap(); + } + + /** + * Adds a GeoJsonFeature to the layer. If the point, linestring or polygon style is set to + * null, the relevant default styles are applied. + * + * @param feature GeoJsonFeature to add to the layer + */ + public void addFeature(GeoJsonFeature feature) { + if (feature == null) { + throw new IllegalArgumentException("Feature cannot be null"); + } + mRenderer.addFeature(feature); + } + + /** + * Removes the given GeoJsonFeature from the layer + * + * @param feature feature to remove + */ + public void removeFeature(GeoJsonFeature feature) { + if (feature == null) { + throw new IllegalArgumentException("Feature cannot be null"); + } + mRenderer.removeFeature(feature); + } + + /** + * Gets the map on which the layer is rendered + * + * @return map on which the layer is rendered + */ + public GoogleMap getMap() { + return mRenderer.getMap(); + } + + /** + * Renders the layer on the given map. The layer on the current map is removed and + * added to the given map. + * + * @param map to render the layer on, if null the layer is cleared from the current map + */ + public void setMap(GoogleMap map) { + mRenderer.setMap(map); + } + + /** + * Removes all GeoJsonFeatures on the layer from the map + */ + public void removeLayerFromMap() { + mRenderer.removeLayerFromMap(); + } + + /** + * Get whether the layer is on the map + * + * @return true if the layer is on the map, false otherwise + */ + public boolean isLayerOnMap() { + return mRenderer.isLayerOnMap(); + } + + /** + * Gets the default style used to render GeoJsonPoints. Any changes to this style will be + * reflected in the features that use it. + * + * @return default style used to render GeoJsonPoints + */ + public GeoJsonPointStyle getDefaultPointStyle() { + return mRenderer.getDefaultPointStyle(); + } + + /** + * Gets the default style used to render GeoJsonLineStrings. Any changes to this style will be + * reflected in the features that use it. + * + * @return default style used to render GeoJsonLineStrings + */ + public GeoJsonLineStringStyle getDefaultLineStringStyle() { + return mRenderer.getDefaultLineStringStyle(); + } + + /** + * Gets the default style used to render GeoJsonPolygons. Any changes to this style will be + * reflected in the features that use it. + * + * @return default style used to render GeoJsonPolygons + */ + public GeoJsonPolygonStyle getDefaultPolygonStyle() { + return mRenderer.getDefaultPolygonStyle(); + } + + /** + * Gets the LatLngBounds containing the coordinates of the bounding box for the + * FeatureCollection. If the FeatureCollection did not have a bounding box or if the GeoJSON + * file did not contain a FeatureCollection then null will be returned. + * + * @return LatLngBounds containing bounding box of FeatureCollection, null if no bounding box + */ + public LatLngBounds getBoundingBox() { + return mBoundingBox; + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder("Collection{"); + sb.append("\n Bounding box=").append(mBoundingBox); + sb.append("\n}\n"); + return sb.toString(); + } +} diff --git a/library/src/com/google/maps/android/geojson/GeoJsonLineString.java b/library/src/com/google/maps/android/geojson/GeoJsonLineString.java new file mode 100644 index 000000000..8977d1998 --- /dev/null +++ b/library/src/com/google/maps/android/geojson/GeoJsonLineString.java @@ -0,0 +1,51 @@ +package com.google.maps.android.geojson; + +import com.google.android.gms.maps.model.LatLng; + +import java.util.List; + +/** + * A GeoJsonLineString geometry represents a number of connected {@link + * com.google.android.gms.maps.model.LatLng}s. + */ +public class GeoJsonLineString implements GeoJsonGeometry { + + private final static String GEOMETRY_TYPE = "LineString"; + + private final List mCoordinates; + + /** + * Creates a new GeoJsonLineString object + * + * @param coordinates list of coordinates of GeoJsonLineString to store + */ + public GeoJsonLineString(List coordinates) { + if (coordinates == null) { + throw new IllegalArgumentException("Coordinates cannot be null"); + } + mCoordinates = coordinates; + } + + /** {@inheritDoc} */ + @Override + public String getType() { + return GEOMETRY_TYPE; + } + + /** + * Gets the coordinates of the GeoJsonLineString + * + * @return list of coordinates of the GeoJsonLineString + */ + public List getCoordinates() { + return mCoordinates; + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(GEOMETRY_TYPE).append("{"); + sb.append("\n coordinates=").append(mCoordinates); + sb.append("\n}\n"); + return sb.toString(); + } +} diff --git a/library/src/com/google/maps/android/geojson/GeoJsonLineStringStyle.java b/library/src/com/google/maps/android/geojson/GeoJsonLineStringStyle.java new file mode 100644 index 000000000..1ad125db5 --- /dev/null +++ b/library/src/com/google/maps/android/geojson/GeoJsonLineStringStyle.java @@ -0,0 +1,167 @@ +package com.google.maps.android.geojson; + +import com.google.android.gms.maps.model.PolylineOptions; + +import java.util.Arrays; +import java.util.Observable; + +/** + * A class that allows for GeoJsonLineString objects to be styled and for these styles to be + * translated into a PolylineOptions object. {@see + * + * PolylineOptions docs for more details about the options.} + */ +public class GeoJsonLineStringStyle extends Observable implements GeoJsonStyle { + + private final static String[] GEOMETRY_TYPE = {"LineString", "MultiLineString", + "GeometryCollection"}; + + private final PolylineOptions mPolylineOptions; + + /** + * Creates a new LineStringStyle object + */ + public GeoJsonLineStringStyle() { + mPolylineOptions = new PolylineOptions(); + } + + /** {@inheritDoc} */ + @Override + public String[] getGeometryType() { + return GEOMETRY_TYPE; + } + + /** + * Gets the color of the GeoJsonLineString as a 32-bit ARGB color + * + * @return color of the GeoJsonLineString + */ + public int getColor() { + return mPolylineOptions.getColor(); + } + + /** + * Sets the color of the GeoJsonLineString as a 32-bit ARGB color + * + * @param color color value of the GeoJsonLineString + */ + public void setColor(int color) { + mPolylineOptions.color(color); + styleChanged(); + } + + /** + * Gets whether the GeoJsonLineString is geodesic + * + * @return true if GeoJsonLineString is geodesic, false otherwise + */ + public boolean isGeodesic() { + return mPolylineOptions.isGeodesic(); + } + + /** + * Sets whether the GeoJsonLineString is geodesic + * + * @param geodesic true if GeoJsonLineString is geodesic, false otherwise + */ + public void setGeodesic(boolean geodesic) { + mPolylineOptions.geodesic(geodesic); + styleChanged(); + } + + /** + * Gets the width of the GeoJsonLineString in screen pixels + * + * @return width of the GeoJsonLineString + */ + public float getWidth() { + return mPolylineOptions.getWidth(); + } + + /** + * Sets the width of the GeoJsonLineString in screen pixels + * + * @param width width value of the GeoJsonLineString + */ + public void setWidth(float width) { + mPolylineOptions.width(width); + styleChanged(); + } + + /** + * Gets the z index of the GeoJsonLineString + * + * @return z index of the GeoJsonLineString + */ + public float getZIndex() { + return mPolylineOptions.getZIndex(); + } + + /** + * Sets the z index of the GeoJsonLineString + * + * @param zIndex z index value of the GeoJsonLineString + */ + public void setZIndex(float zIndex) { + mPolylineOptions.zIndex(zIndex); + styleChanged(); + } + + /** + * Gets whether the GeoJsonLineString is visible + * + * @return true if the GeoJsonLineString visible, false if not visible + */ + @Override + public boolean isVisible() { + return mPolylineOptions.isVisible(); + } + + /** + * Sets whether the GeoJsonLineString is visible + * + * @param visible true if the GeoJsonLineString is visible, false if not visible + */ + @Override + public void setVisible(boolean visible) { + mPolylineOptions.visible(visible); + styleChanged(); + } + + /** + * Notifies the observers, GeoJsonFeature objects, that the style has changed. Indicates to the + * GeoJsonFeature that it should check whether a redraw is needed for the feature. + */ + private void styleChanged() { + setChanged(); + notifyObservers(); + } + + /** + * Gets a new PolylineOptions object containing styles for the GeoJsonLineString + * + * @return new PolylineOptions object + */ + public PolylineOptions toPolylineOptions() { + PolylineOptions polylineOptions = new PolylineOptions(); + polylineOptions.color(mPolylineOptions.getColor()); + polylineOptions.geodesic(mPolylineOptions.isGeodesic()); + polylineOptions.visible(mPolylineOptions.isVisible()); + polylineOptions.width(mPolylineOptions.getWidth()); + polylineOptions.zIndex(mPolylineOptions.getZIndex()); + return polylineOptions; + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder("LineStringStyle{"); + sb.append("\n geometry type=").append(Arrays.toString(GEOMETRY_TYPE)); + sb.append(",\n color=").append(getColor()); + sb.append(",\n geodesic=").append(isGeodesic()); + sb.append(",\n visible=").append(isVisible()); + sb.append(",\n width=").append(getWidth()); + sb.append(",\n z index=").append(getZIndex()); + sb.append("\n}\n"); + return sb.toString(); + } +} diff --git a/library/src/com/google/maps/android/geojson/GeoJsonMultiLineString.java b/library/src/com/google/maps/android/geojson/GeoJsonMultiLineString.java new file mode 100644 index 000000000..71d223bb2 --- /dev/null +++ b/library/src/com/google/maps/android/geojson/GeoJsonMultiLineString.java @@ -0,0 +1,48 @@ +package com.google.maps.android.geojson; + +import java.util.List; + +/** + * A GeoJsonMultiLineString geometry contains a number of {@link GeoJsonLineString}s. + */ +public class GeoJsonMultiLineString implements GeoJsonGeometry { + + private final static String GEOMETRY_TYPE = "MultiLineString"; + + private final List mGeoJsonLineStrings; + + /** + * Creates a new GeoJsonMultiLineString object + * + * @param geoJsonLineStrings list of GeoJsonLineStrings to store + */ + public GeoJsonMultiLineString(List geoJsonLineStrings) { + if (geoJsonLineStrings == null) { + throw new IllegalArgumentException("GeoJsonLineStrings cannot be null"); + } + mGeoJsonLineStrings = geoJsonLineStrings; + } + + /** {@inheritDoc} */ + @Override + public String getType() { + return GEOMETRY_TYPE; + } + + /** + * Gets a list of GeoJsonLineStrings + * + * @return list of GeoJsonLineStrings + */ + public List getLineStrings() { + return mGeoJsonLineStrings; + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(GEOMETRY_TYPE).append("{"); + sb.append("\n LineStrings=").append(mGeoJsonLineStrings); + sb.append("\n}\n"); + return sb.toString(); + } +} diff --git a/library/src/com/google/maps/android/geojson/GeoJsonMultiPoint.java b/library/src/com/google/maps/android/geojson/GeoJsonMultiPoint.java new file mode 100644 index 000000000..cb3f2cf27 --- /dev/null +++ b/library/src/com/google/maps/android/geojson/GeoJsonMultiPoint.java @@ -0,0 +1,48 @@ +package com.google.maps.android.geojson; + +import java.util.List; + +/** + * A GeoJsonMultiPoint geometry contains a number of {@link GeoJsonPoint}s. + */ +public class GeoJsonMultiPoint implements GeoJsonGeometry { + + private final static String GEOMETRY_TYPE = "MultiPoint"; + + private final List mGeoJsonPoints; + + /** + * Creates a GeoJsonMultiPoint object + * + * @param geoJsonPoints list of GeoJsonPoints to store + */ + public GeoJsonMultiPoint(List geoJsonPoints) { + if (geoJsonPoints == null) { + throw new IllegalArgumentException("GeoJsonPoints cannot be null"); + } + mGeoJsonPoints = geoJsonPoints; + } + + /** {@inheritDoc} */ + @Override + public String getType() { + return GEOMETRY_TYPE; + } + + /** + * Gets a list of GeoJsonPoints + * + * @return list of GeoJsonPoints + */ + public List getPoints() { + return mGeoJsonPoints; + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(GEOMETRY_TYPE).append("{"); + sb.append("\n points=").append(mGeoJsonPoints); + sb.append("\n}\n"); + return sb.toString(); + } +} diff --git a/library/src/com/google/maps/android/geojson/GeoJsonMultiPolygon.java b/library/src/com/google/maps/android/geojson/GeoJsonMultiPolygon.java new file mode 100644 index 000000000..6d57f5656 --- /dev/null +++ b/library/src/com/google/maps/android/geojson/GeoJsonMultiPolygon.java @@ -0,0 +1,48 @@ +package com.google.maps.android.geojson; + +import java.util.List; + +/** + * A GeoJsonMultiPolygon geometry contains a number of {@link GeoJsonPolygon}s. + */ +public class GeoJsonMultiPolygon implements GeoJsonGeometry { + + private final static String GEOMETRY_TYPE = "MultiPolygon"; + + private final List mGeoJsonPolygons; + + /** + * Creates a new GeoJsonMultiPolygon + * + * @param geoJsonPolygons list of GeoJsonPolygons to store + */ + public GeoJsonMultiPolygon(List geoJsonPolygons) { + if (geoJsonPolygons == null) { + throw new IllegalArgumentException("GeoJsonPolygons cannot be null"); + } + mGeoJsonPolygons = geoJsonPolygons; + } + + /** {@inheritDoc} */ + @Override + public String getType() { + return GEOMETRY_TYPE; + } + + /** + * Gets a list of GeoJsonPolygons + * + * @return list of GeoJsonPolygons + */ + public List getPolygons() { + return mGeoJsonPolygons; + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(GEOMETRY_TYPE).append("{"); + sb.append("\n Polygons=").append(mGeoJsonPolygons); + sb.append("\n}\n"); + return sb.toString(); + } +} diff --git a/library/src/com/google/maps/android/geojson/GeoJsonParser.java b/library/src/com/google/maps/android/geojson/GeoJsonParser.java new file mode 100644 index 000000000..bb9e3143d --- /dev/null +++ b/library/src/com/google/maps/android/geojson/GeoJsonParser.java @@ -0,0 +1,478 @@ +package com.google.maps.android.geojson; + + +import com.google.android.gms.maps.model.LatLng; +import com.google.android.gms.maps.model.LatLngBounds; + +import org.json.JSONArray; +import org.json.JSONException; +import org.json.JSONObject; + +import android.util.Log; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Iterator; + +/** + * Parses a JSONObject and places data into their appropriate GeoJsonFeature objects. Returns an + * array of + * GeoJsonFeature objects parsed from the GeoJSON file. + */ +/* package */ class GeoJsonParser { + + private static final String LOG_TAG = "GeoJsonParser"; + + // Feature object type + private static final String FEATURE = "Feature"; + + // Feature object geometry member + private static final String FEATURE_GEOMETRY = "geometry"; + + // Feature object id member + private static final String FEATURE_ID = "id"; + + // FeatureCollection type + private static final String FEATURE_COLLECTION = "FeatureCollection"; + + // FeatureCollection features array member + private static final String FEATURE_COLLECTION_ARRAY = "features"; + + // Geometry coordinates member + private static final String GEOMETRY_COORDINATES_ARRAY = "coordinates"; + + // GeometryCollection type + private static final String GEOMETRY_COLLECTION = "GeometryCollection"; + + // GeometryCollection geometries array member + private static final String GEOMETRY_COLLECTION_ARRAY = "geometries"; + + // Coordinates for bbox + private static final String BOUNDING_BOX = "bbox"; + + private static final String PROPERTIES = "properties"; + + private static final String POINT = "Point"; + + private static final String MULTIPOINT = "MultiPoint"; + + private static final String LINESTRING = "LineString"; + + private static final String MULTILINESTRING = "MultiLineString"; + + private static final String POLYGON = "Polygon"; + + private static final String MULTIPOLYGON = "MultiPolygon"; + + private final JSONObject mGeoJsonFile; + + private final ArrayList mGeoJsonFeatures; + + private LatLngBounds mBoundingBox; + + + /** + * Creates a new GeoJsonParser + * + * @param geoJsonFile GeoJSON file to parse + */ + /* package */ GeoJsonParser(JSONObject geoJsonFile) { + mGeoJsonFile = geoJsonFile; + mGeoJsonFeatures = new ArrayList(); + mBoundingBox = null; + parseGeoJson(); + } + + private static boolean isGeometry(String type) { + return type.matches(POINT + "|" + MULTIPOINT + "|" + LINESTRING + "|" + MULTILINESTRING + + "|" + POLYGON + "|" + MULTIPOLYGON + "|" + GEOMETRY_COLLECTION); + } + + /** + * Parses a single GeoJSON feature which contains a geometry and properties member both of + * which can be null. Also parses the bounding box and id members of the feature if they exist. + * + * @param geoJsonFeature feature to parse + * @return GeoJsonFeature object + */ + private static GeoJsonFeature parseFeature(JSONObject geoJsonFeature) { + String id = null; + LatLngBounds boundingBox = null; + GeoJsonGeometry geometry = null; + HashMap properties = new HashMap(); + + try { + if (geoJsonFeature.has(FEATURE_ID)) { + id = geoJsonFeature.getString(FEATURE_ID); + } + if (geoJsonFeature.has(BOUNDING_BOX)) { + boundingBox = parseBoundingBox(geoJsonFeature.getJSONArray(BOUNDING_BOX)); + } + if (geoJsonFeature.has(FEATURE_GEOMETRY) && !geoJsonFeature.isNull(FEATURE_GEOMETRY)) { + geometry = parseGeometry(geoJsonFeature.getJSONObject(FEATURE_GEOMETRY)); + } + if (geoJsonFeature.has(PROPERTIES) && !geoJsonFeature.isNull(PROPERTIES)) { + properties = parseProperties(geoJsonFeature.getJSONObject("properties")); + } + } catch (JSONException e) { + Log.w(LOG_TAG, "Feature could not be successfully parsed " + geoJsonFeature.toString()); + return null; + } + return new GeoJsonFeature(geometry, id, properties, boundingBox); + } + + /** + * Parses a bounding box given as a JSONArray of 4 elements in the order of lowest values for + * all axes followed by highest values. Axes order of a bounding box follows the axes order of + * geometries. + * + * @param coordinates array of 4 coordinates + * @return LatLngBounds containing the coordinates of the bounding box + * @throws JSONException if the bounding box could not be parsed + */ + private static LatLngBounds parseBoundingBox(JSONArray coordinates) throws JSONException { + // Lowest values for all axes + LatLng southWestCorner = new LatLng(coordinates.getDouble(1), coordinates.getDouble(0)); + // Highest value for all axes + LatLng northEastCorner = new LatLng(coordinates.getDouble(3), coordinates.getDouble(2)); + return new LatLngBounds(southWestCorner, northEastCorner); + } + + /** + * Parses a single GeoJSON geometry object containing a coordinates array or a geometries array + * if it has type GeometryCollection + * + * @param geoJsonGeometry geometry object to parse + * @return GeoJsonGeometry object + */ + private static GeoJsonGeometry parseGeometry(JSONObject geoJsonGeometry) { + try { + + String geometryType = geoJsonGeometry.getString("type"); + + JSONArray geometryArray; + if (geometryType.equals(GEOMETRY_COLLECTION)) { + // GeometryCollection + geometryArray = geoJsonGeometry.getJSONArray(GEOMETRY_COLLECTION_ARRAY); + } else if (isGeometry(geometryType)) { + geometryArray = geoJsonGeometry.getJSONArray(GEOMETRY_COORDINATES_ARRAY); + } else { + // No geometries or coordinates array + return null; + } + return createGeometry(geometryType, geometryArray); + } catch (JSONException e) { + return null; + } + } + + /** + * Converts a GeoJsonGeometry object into a GeoJsonFeature object. A geometry object has no ID, + * properties or bounding box so it is set to null. + * + * @param geoJsonGeometry Geometry object to convert into a Feature object + * @return new Feature object + */ + private static GeoJsonFeature parseGeometryToFeature(JSONObject geoJsonGeometry) { + GeoJsonGeometry geometry = parseGeometry(geoJsonGeometry); + if (geometry != null) { + return new GeoJsonFeature(geometry, null, new HashMap(), null); + } + Log.w(LOG_TAG, "Geometry could not be parsed"); + return null; + + } + + /** + * Parses the properties of a GeoJSON feature into a hashmap + * + * @param properties GeoJSON properties member + * @return hashmap containing property values + * @throws JSONException if the properties could not be parsed + */ + private static HashMap parseProperties(JSONObject properties) + throws JSONException { + HashMap propertiesMap = new HashMap(); + Iterator propertyKeys = properties.keys(); + while (propertyKeys.hasNext()) { + String key = (String) propertyKeys.next(); + propertiesMap.put(key, properties.getString(key)); + } + return propertiesMap; + } + + /** + * Creates a GeoJsonGeometry object from the given type of geometry and its coordinates or + * geometries array + * + * @param geometryType type of geometry + * @param geometryArray coordinates or geometries of the geometry + * @return GeoJsonGeometry object + * @throws JSONException if the coordinates or geometries could be parsed + */ + private static GeoJsonGeometry createGeometry(String geometryType, JSONArray geometryArray) + throws JSONException { + if (geometryType.equals(POINT)) { + return createPoint(geometryArray); + } else if (geometryType.equals(MULTIPOINT)) { + return createMultiPoint(geometryArray); + } else if (geometryType.equals(LINESTRING)) { + return createLineString(geometryArray); + } else if (geometryType.equals(MULTILINESTRING)) { + return createMultiLineString(geometryArray); + } else if (geometryType.equals(POLYGON)) { + return createPolygon(geometryArray); + } else if (geometryType.equals(MULTIPOLYGON)) { + return createMultiPolygon(geometryArray); + } else if (geometryType.equals(GEOMETRY_COLLECTION)) { + return createGeometryCollection(geometryArray); + } + return null; + } + + /** + * Creates a new GeoJsonPoint object + * + * @param coordinates array containing the coordinates for the GeoJsonPoint + * @return GeoJsonPoint object + * @throws JSONException if coordinates cannot be parsed + */ + private static GeoJsonPoint createPoint(JSONArray coordinates) throws JSONException { + return new GeoJsonPoint(parseCoordinate(coordinates)); + } + + /** + * Creates a new GeoJsonMultiPoint object containing an array of GeoJsonPoint objects + * + * @param coordinates array containing the coordinates for the GeoJsonMultiPoint + * @return GeoJsonMultiPoint object + * @throws JSONException if coordinates cannot be parsed + */ + private static GeoJsonMultiPoint createMultiPoint(JSONArray coordinates) throws JSONException { + ArrayList geoJsonPoints = new ArrayList(); + for (int i = 0; i < coordinates.length(); i++) { + geoJsonPoints.add(createPoint(coordinates.getJSONArray(i))); + } + return new GeoJsonMultiPoint(geoJsonPoints); + } + + /** + * Creates a new GeoJsonLineString object + * + * @param coordinates array containing the coordinates for the GeoJsonLineString + * @return GeoJsonLineString object + * @throws JSONException if coordinates cannot be parsed + */ + private static GeoJsonLineString createLineString(JSONArray coordinates) throws JSONException { + return new GeoJsonLineString(parseCoordinatesArray(coordinates)); + } + + /** + * Creates a new GeoJsonMultiLineString object containing an array of GeoJsonLineString objects + * + * @param coordinates array containing the coordinates for the GeoJsonMultiLineString + * @return GeoJsonMultiLineString object + * @throws JSONException if coordinates cannot be parsed + */ + private static GeoJsonMultiLineString createMultiLineString(JSONArray coordinates) + throws JSONException { + ArrayList geoJsonLineStrings = new ArrayList(); + for (int i = 0; i < coordinates.length(); i++) { + geoJsonLineStrings.add(createLineString(coordinates.getJSONArray(i))); + } + return new GeoJsonMultiLineString(geoJsonLineStrings); + } + + /** + * Creates a new GeoJsonPolygon object + * + * @param coordinates array containing the coordinates for the GeoJsonPolygon + * @return GeoJsonPolygon object + * @throws JSONException if coordinates cannot be parsed + */ + private static GeoJsonPolygon createPolygon(JSONArray coordinates) throws JSONException { + return new GeoJsonPolygon(parseCoordinatesArrays(coordinates)); + } + + /** + * Creates a new GeoJsonMultiPolygon object containing an array of GeoJsonPolygon objects + * + * @param coordinates array containing the coordinates for the GeoJsonMultiPolygon + * @return GeoJsonPolygon object + * @throws JSONException if coordinates cannot be parsed + */ + private static GeoJsonMultiPolygon createMultiPolygon(JSONArray coordinates) + throws JSONException { + ArrayList geoJsonPolygons = new ArrayList(); + for (int i = 0; i < coordinates.length(); i++) { + geoJsonPolygons.add(createPolygon(coordinates.getJSONArray(i))); + } + return new GeoJsonMultiPolygon(geoJsonPolygons); + } + + /** + * Creates a new GeoJsonGeometryCollection object containing an array of GeoJsonGeometry + * objects + * + * @param geometries array containing the geometries for the GeoJsonGeometryCollection + * @return GeoJsonGeometryCollection object + * @throws JSONException if geometries cannot be parsed + */ + private static GeoJsonGeometryCollection createGeometryCollection(JSONArray geometries) + throws JSONException { + ArrayList geometryCollectionElements + = new ArrayList(); + + for (int i = 0; i < geometries.length(); i++) { + JSONObject geometryElement = geometries.getJSONObject(i); + GeoJsonGeometry geometry = parseGeometry(geometryElement); + if (geometry != null) { + // Do not add geometries that could not be parsed + geometryCollectionElements.add(geometry); + } + } + return new GeoJsonGeometryCollection(geometryCollectionElements); + } + + /** + * Parses an array containing a coordinate into a LatLng object + * + * @param coordinates array containing the GeoJSON coordinate + * @return LatLng object + * @throws JSONException if coordinate cannot be parsed + */ + private static LatLng parseCoordinate(JSONArray coordinates) throws JSONException { + // GeoJSON stores coordinates as Lng, Lat so we need to reverse + return new LatLng(coordinates.getDouble(1), coordinates.getDouble(0)); + } + + /** + * Parses an array containing coordinates into an ArrayList of LatLng objects + * + * @param coordinates array containing the GeoJSON coordinates + * @return ArrayList of LatLng objects + * @throws JSONException if coordinates cannot be parsed + */ + private static ArrayList parseCoordinatesArray(JSONArray coordinates) + throws JSONException { + ArrayList coordinatesArray = new ArrayList(); + + for (int i = 0; i < coordinates.length(); i++) { + coordinatesArray.add(parseCoordinate(coordinates.getJSONArray(i))); + } + return coordinatesArray; + } + + /** + * Parses an array of arrays containing coordinates into an ArrayList of an ArrayList of LatLng + * objects + * + * @param coordinates array of an array containing the GeoJSON coordinates + * @return ArrayList of an ArrayList of LatLng objects + * @throws JSONException if coordinates cannot be parsed + */ + private static ArrayList> parseCoordinatesArrays(JSONArray coordinates) + throws JSONException { + ArrayList> coordinatesArray = new ArrayList>(); + + for (int i = 0; i < coordinates.length(); i++) { + coordinatesArray.add(parseCoordinatesArray(coordinates.getJSONArray(i))); + } + return coordinatesArray; + } + + /** + * Parses the GeoJSON file by type and adds the generated GeoJsonFeature objects to the + * mFeatures array. Supported GeoJSON types include feature, feature collection and geometry. + */ + private void parseGeoJson() { + try { + GeoJsonFeature feature; + String type = mGeoJsonFile.getString("type"); + + if (type.equals(FEATURE)) { + feature = parseFeature(mGeoJsonFile); + if (feature != null) { + mGeoJsonFeatures.add(feature); + } + } else if (type.equals(FEATURE_COLLECTION)) { + mGeoJsonFeatures.addAll(parseFeatureCollection(mGeoJsonFile)); + } else if (isGeometry(type)) { + feature = parseGeometryToFeature(mGeoJsonFile); + if (feature != null) { + // Don't add null features + mGeoJsonFeatures.add(feature); + } + } else { + Log.w(LOG_TAG, "GeoJSON file could not be parsed."); + } + } catch (JSONException e) { + Log.w(LOG_TAG, "GeoJSON file could not be parsed."); + } + } + + /** + * Parses the array of GeoJSON features in a given GeoJSON feature collection. Also parses the + * bounding box member of the feature collection if it exists. + * + * @param geoJsonFeatureCollection feature collection to parse + * @return array of GeoJsonFeature objects + */ + private ArrayList parseFeatureCollection(JSONObject geoJsonFeatureCollection) { + JSONArray geoJsonFeatures; + ArrayList features = new ArrayList(); + try { + geoJsonFeatures = geoJsonFeatureCollection.getJSONArray(FEATURE_COLLECTION_ARRAY); + if (geoJsonFeatureCollection.has(BOUNDING_BOX)) { + mBoundingBox = parseBoundingBox( + geoJsonFeatureCollection.getJSONArray(BOUNDING_BOX)); + } + } catch (JSONException e) { + Log.w(LOG_TAG, "Feature Collection could not be created."); + return features; + } + + for (int i = 0; i < geoJsonFeatures.length(); i++) { + try { + JSONObject feature = geoJsonFeatures.getJSONObject(i); + if (feature.getString("type").equals(FEATURE)) { + GeoJsonFeature parsedFeature = parseFeature(feature); + if (parsedFeature != null) { + // Don't add null features + features.add(parsedFeature); + } else { + Log.w(LOG_TAG, + "Index of Feature in Feature Collection that could not be created: " + + i); + } + } + } catch (JSONException e) { + Log.w(LOG_TAG, + "Index of Feature in Feature Collection that could not be created: " + i); + } + } + return features; + } + + /** + * Gets the array of GeoJsonFeature objects + * + * @return array of GeoJsonFeatures + */ + /* package */ ArrayList getFeatures() { + return mGeoJsonFeatures; + } + + /** + * Gets the array containing the coordinates of the bounding box for the FeatureCollection. If + * the FeatureCollection did not have a bounding box or if the GeoJSON file did not contain a + * FeatureCollection then null will be returned. + * + * @return LatLngBounds object containing bounding box of FeatureCollection, null if no bounding + * box + */ + /* package */ LatLngBounds getBoundingBox() { + return mBoundingBox; + } + +} diff --git a/library/src/com/google/maps/android/geojson/GeoJsonPoint.java b/library/src/com/google/maps/android/geojson/GeoJsonPoint.java new file mode 100644 index 000000000..4050cc2df --- /dev/null +++ b/library/src/com/google/maps/android/geojson/GeoJsonPoint.java @@ -0,0 +1,48 @@ +package com.google.maps.android.geojson; + +import com.google.android.gms.maps.model.LatLng; + +/** + * A GeoJsonPoint geometry contains a single {@link com.google.android.gms.maps.model.LatLng}. + */ +public class GeoJsonPoint implements GeoJsonGeometry { + + private final static String GEOMETRY_TYPE = "Point"; + + private final LatLng mCoordinates; + + /** + * Creates a new GeoJsonPoint + * + * @param coordinate coordinate of GeoJsonPoint to store + */ + public GeoJsonPoint(LatLng coordinate) { + if (coordinate == null) { + throw new IllegalArgumentException("Coordinate cannot be null"); + } + mCoordinates = coordinate; + } + + /** {@inheritDoc} */ + @Override + public String getType() { + return GEOMETRY_TYPE; + } + + /** + * Gets the coordinates of the GeoJsonPoint + * + * @return coordinates of the GeoJsonPoint + */ + public LatLng getCoordinates() { + return mCoordinates; + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(GEOMETRY_TYPE).append("{"); + sb.append("\n coordinates=").append(mCoordinates); + sb.append("\n}\n"); + return sb.toString(); + } +} diff --git a/library/src/com/google/maps/android/geojson/GeoJsonPointStyle.java b/library/src/com/google/maps/android/geojson/GeoJsonPointStyle.java new file mode 100644 index 000000000..441134c30 --- /dev/null +++ b/library/src/com/google/maps/android/geojson/GeoJsonPointStyle.java @@ -0,0 +1,314 @@ +package com.google.maps.android.geojson; + +import com.google.android.gms.maps.model.BitmapDescriptor; +import com.google.android.gms.maps.model.MarkerOptions; + +import java.util.Arrays; +import java.util.Observable; + +/** + * A class that allows for GeoJsonPoint objects to be styled and for these styles to be translated + * into a MarkerOptions object. {@see + * + * MarkerOptions docs for more details about the options.} + */ +public class GeoJsonPointStyle extends Observable implements GeoJsonStyle { + + private final static String[] GEOMETRY_TYPE = {"Point", "MultiPoint", "GeometryCollection"}; + + private final MarkerOptions mMarkerOptions; + + + /** + * Creates a new PointStyle object + */ + public GeoJsonPointStyle() { + mMarkerOptions = new MarkerOptions(); + } + + /** {@inheritDoc} */ + @Override + public String[] getGeometryType() { + return GEOMETRY_TYPE; + } + + /** + * Gets the alpha of the GeoJsonPoint. This is a value from 0 to 1, where 0 means the marker is + * completely transparent and 1 means the marker is completely opaque. + * + * @return alpha of the GeoJsonPoint + */ + public float getAlpha() { + return mMarkerOptions.getAlpha(); + } + + /** + * Sets the alpha of the GeoJsonPoint. This is a value from 0 to 1, where 0 means the marker is + * completely transparent and 1 means the marker is completely opaque. + * + * @param alpha alpha value of the GeoJsonPoint + */ + public void setAlpha(float alpha) { + mMarkerOptions.alpha(alpha); + styleChanged(); + } + + /** + * Gets the Anchor U coordinate of the GeoJsonPoint. Normalized to [0, 1], of the anchor from + * the left edge. This is equivalent to the same U value used in {@link + * com.google.android.gms.maps.model.MarkerOptions#getAnchorU()}. + * + * @return Anchor U coordinate of the GeoJsonPoint + */ + public float getAnchorU() { + return mMarkerOptions.getAnchorU(); + } + + /** + * Gets the Anchor V coordinate of the GeoJsonPoint. Normalized to [0, 1], of the anchor from + * the top edge. This is equivalent to the same V value used in {@link + * com.google.android.gms.maps.model.MarkerOptions#getAnchorV()}. + * + * @return Anchor V coordinate of the GeoJsonPoint + */ + public float getAnchorV() { + return mMarkerOptions.getAnchorV(); + } + + /** + * Sets the Anchor U and V coordinates of the GeoJsonPoint. The anchor point is specified in + * the + * continuous space [0.0, 1.0] x [0.0, 1.0], where (0, 0) is the top-left corner of the image, + * and (1, 1) is the bottom-right corner. The U & V values are the same U & V values + * used in + * {@link com.google.android.gms.maps.model.MarkerOptions#anchor(float, float)} ()}. + * + * @param anchorU Anchor U coordinate of the GeoJsonPoint + * @param anchorV Anchor V coordinate of the GeoJsonPoint + */ + public void setAnchor(float anchorU, float anchorV) { + mMarkerOptions.anchor(anchorU, anchorV); + styleChanged(); + } + + /** + * Gets whether the GeoJsonPoint is draggable + * + * @return true if GeoJsonPoint is draggable, false if not draggable + */ + public boolean isDraggable() { + return mMarkerOptions.isDraggable(); + } + + /** + * Sets the GeoJsonPoint to be draggable + * + * @param draggable true if GeoJsonPoint is draggable, false if not draggable + */ + public void setDraggable(boolean draggable) { + mMarkerOptions.draggable(draggable); + styleChanged(); + } + + /** + * Gets whether the GeoJsonPoint is flat + * + * @return true if GeoJsonPoint is flat, false if not flat + */ + public boolean isFlat() { + return mMarkerOptions.isFlat(); + } + + /** + * Sets the GeoJsonPoint to be flat + * + * @param flat true if GeoJsonPoint is flat, false if not flat + */ + public void setFlat(boolean flat) { + mMarkerOptions.flat(flat); + styleChanged(); + } + + /** + * Gets a bitmap image for the GeoJsonPoint + * + * @return bitmap descriptor for the GeoJsonPoint + */ + public BitmapDescriptor getIcon() { + return mMarkerOptions.getIcon(); + } + + /** + * Sets a bitmap image for the GeoJsonPoint + * + * @param bitmap bitmap descriptor for the GeoJsonPoint + */ + public void setIcon(BitmapDescriptor bitmap) { + mMarkerOptions.icon(bitmap); + styleChanged(); + } + + /** + * Gets the info window anchor U coordinate of the GeoJsonPoint. Normalized to [0, 1], of the + * info window anchor from the left edge. This is equivalent to the same U value used in {@link + * com.google.android.gms.maps.model.MarkerOptions#getInfoWindowAnchorU()}. + * + * @return info window anchor U coordinate of the GeoJsonPoint + */ + public float getInfoWindowAnchorU() { + return mMarkerOptions.getInfoWindowAnchorU(); + } + + /** + * Gets the info window anchor V coordinate of the GeoJsonPoint. Normalized to [0, 1], of the + * info window anchor from the top edge. This is equivalent to the same V value used in {@link + * com.google.android.gms.maps.model.MarkerOptions#getInfoWindowAnchorV()}. + * + * @return info window anchor V coordinate of the GeoJsonPoint + */ + public float getInfoWindowAnchorV() { + return mMarkerOptions.getInfoWindowAnchorV(); + } + + /** + * Sets the info window anchor U and V coordinates of the GeoJsonPoint. This is specified in + * the same coordinate system as the anchor. The U & V values are the same U & V values + * used in + * {@link com.google.android.gms.maps.model.MarkerOptions#infoWindowAnchor(float, float)}. + * + * @param infoWindowAnchorU info window anchor U coordinate of the GeoJsonPoint + * @param infoWindowAnchorV info window anchor V coordinate of the GeoJsonPoint + */ + public void setInfoWindowAnchor(float infoWindowAnchorU, float infoWindowAnchorV) { + mMarkerOptions.infoWindowAnchor(infoWindowAnchorU, infoWindowAnchorV); + styleChanged(); + } + + /** + * Gets the rotation of the GeoJsonPoint in degrees clockwise about the marker's anchor point + * + * @return rotation of the GeoJsonPoint + */ + public float getRotation() { + return mMarkerOptions.getRotation(); + } + + + /** + * Sets the rotation of the GeoJsonPoint in degrees clockwise about the marker's anchor point + * + * @param rotation rotation value of the GeoJsonPoint + */ + public void setRotation(float rotation) { + mMarkerOptions.rotation(rotation); + styleChanged(); + } + + /** + * Gets the snippet of the GeoJsonPoint + * + * @return snippet of the GeoJsonPoint + */ + public String getSnippet() { + return mMarkerOptions.getSnippet(); + } + + /** + * Sets the snippet of the GeoJsonPoint + * + * @param snippet sets the snippet value of the GeoJsonPoint + */ + public void setSnippet(String snippet) { + mMarkerOptions.snippet(snippet); + styleChanged(); + } + + /** + * Gets the title of the GeoJsonPoint + * + * @return title of the GeoJsonPoint + */ + public String getTitle() { + return mMarkerOptions.getTitle(); + } + + /** + * Sets the title of the GeoJsonPoint + * + * @param title title value of the GeoJsonPoint + */ + public void setTitle(String title) { + mMarkerOptions.title(title); + styleChanged(); + } + + /** + * Gets whether the GeoJsonPoint is visible + * + * @return true if GeoJsonPoint is visible, false if not visible + */ + @Override + public boolean isVisible() { + return mMarkerOptions.isVisible(); + } + + /** + * Sets whether the GeoJsonPoint is visible + * + * @param visible true if GeoJsonPoint is visible, false if not visible + */ + @Override + public void setVisible(boolean visible) { + mMarkerOptions.visible(visible); + styleChanged(); + } + + /** + * Notifies the observers, GeoJsonFeature objects, that the style has changed. Indicates to the + * GeoJsonFeature that it should check whether a redraw is needed for the feature. + */ + private void styleChanged() { + setChanged(); + notifyObservers(); + } + + /** + * Gets a new MarkerOptions object containing styles for the GeoJsonPoint + * + * @return new MarkerOptions object + */ + public MarkerOptions toMarkerOptions() { + MarkerOptions markerOptions = new MarkerOptions(); + markerOptions.alpha(mMarkerOptions.getAlpha()); + markerOptions.anchor(mMarkerOptions.getAnchorU(), mMarkerOptions.getAnchorV()); + markerOptions.draggable(mMarkerOptions.isDraggable()); + markerOptions.flat(mMarkerOptions.isFlat()); + markerOptions.icon(mMarkerOptions.getIcon()); + markerOptions.infoWindowAnchor(mMarkerOptions.getInfoWindowAnchorU(), + mMarkerOptions.getInfoWindowAnchorV()); + markerOptions.rotation(mMarkerOptions.getRotation()); + markerOptions.snippet(mMarkerOptions.getSnippet()); + markerOptions.title(mMarkerOptions.getTitle()); + markerOptions.visible(mMarkerOptions.isVisible()); + return markerOptions; + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder("PointStyle{"); + sb.append("\n geometry type=").append(Arrays.toString(GEOMETRY_TYPE)); + sb.append(",\n alpha=").append(getAlpha()); + sb.append(",\n anchor U=").append(getAnchorU()); + sb.append(",\n anchor V=").append(getAnchorV()); + sb.append(",\n draggable=").append(isDraggable()); + sb.append(",\n flat=").append(isFlat()); + sb.append(",\n info window anchor U=").append(getInfoWindowAnchorU()); + sb.append(",\n info window anchor V=").append(getInfoWindowAnchorV()); + sb.append(",\n rotation=").append(getRotation()); + sb.append(",\n snippet=").append(getSnippet()); + sb.append(",\n title=").append(getTitle()); + sb.append(",\n visible=").append(isVisible()); + sb.append("\n}\n"); + return sb.toString(); + } +} diff --git a/library/src/com/google/maps/android/geojson/GeoJsonPolygon.java b/library/src/com/google/maps/android/geojson/GeoJsonPolygon.java new file mode 100644 index 000000000..81c9e7bff --- /dev/null +++ b/library/src/com/google/maps/android/geojson/GeoJsonPolygon.java @@ -0,0 +1,53 @@ +package com.google.maps.android.geojson; + +import com.google.android.gms.maps.model.LatLng; + +import java.util.List; + +/** + * A GeoJsonPolygon geometry contains an array of arrays of {@link com.google.android.gms.maps.model.LatLng}s. + * The first array is the polygon exterior boundary. Subsequent arrays are holes. + */ + +public class GeoJsonPolygon implements GeoJsonGeometry { + + private final static String GEOMETRY_TYPE = "Polygon"; + + private final List> mCoordinates; + + /** + * Creates a new GeoJsonPolygon object + * + * @param coordinates list of list of coordinates of GeoJsonPolygon to store + */ + public GeoJsonPolygon( + List> coordinates) { + if (coordinates == null) { + throw new IllegalArgumentException("Coordinates cannot be null"); + } + mCoordinates = coordinates; + } + + /** {@inheritDoc} */ + @Override + public String getType() { + return GEOMETRY_TYPE; + } + + /** + * Gets a list of a list of coordinates of the GeoJsonPolygons + * + * @return list of a list of coordinates of the GeoJsonPolygon + */ + public List> getCoordinates() { + return mCoordinates; + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(GEOMETRY_TYPE).append("{"); + sb.append("\n coordinates=").append(mCoordinates); + sb.append("\n}\n"); + return sb.toString(); + } +} diff --git a/library/src/com/google/maps/android/geojson/GeoJsonPolygonStyle.java b/library/src/com/google/maps/android/geojson/GeoJsonPolygonStyle.java new file mode 100644 index 000000000..89c952a5f --- /dev/null +++ b/library/src/com/google/maps/android/geojson/GeoJsonPolygonStyle.java @@ -0,0 +1,187 @@ +package com.google.maps.android.geojson; + +import com.google.android.gms.maps.model.PolygonOptions; + +import java.util.Arrays; +import java.util.Observable; + +/** + * A class that allows for GeoJsonPolygon objects to be styled and for these styles to be + * translated into a PolygonOptions object. {@see + * + * PolygonOptions docs for more details about the options.} + */ +public class GeoJsonPolygonStyle extends Observable implements GeoJsonStyle { + + private final static String[] GEOMETRY_TYPE = {"Polygon", "MultiPolygon", "GeometryCollection"}; + + private final PolygonOptions mPolygonOptions; + + /** + * Creates a new PolygonStyle object + */ + public GeoJsonPolygonStyle() { + mPolygonOptions = new PolygonOptions(); + } + + /** {@inheritDoc} */ + @Override + public String[] getGeometryType() { + return GEOMETRY_TYPE; + } + + /** + * Gets the fill color of the GeoJsonPolygon as a 32-bit ARGB color + * + * @return fill color of the GeoJsonPolygon + */ + public int getFillColor() { + return mPolygonOptions.getFillColor(); + } + + /** + * Sets the fill color of the GeoJsonPolygon as a 32-bit ARGB color + * + * @param fillColor fill color value of the GeoJsonPolygon + */ + public void setFillColor(int fillColor) { + mPolygonOptions.fillColor(fillColor); + styleChanged(); + } + + /** + * Gets whether the GeoJsonPolygon is geodesic + * + * @return true if GeoJsonPolygon is geodesic, false if not geodesic + */ + public boolean isGeodesic() { + return mPolygonOptions.isGeodesic(); + } + + /** + * Sets whether the GeoJsonPolygon is geodesic + * + * @param geodesic true if GeoJsonPolygon is geodesic, false if not geodesic + */ + public void setGeodesic(boolean geodesic) { + mPolygonOptions.geodesic(geodesic); + styleChanged(); + } + + /** + * Gets the stroke color of the GeoJsonPolygon as a 32-bit ARGB color + * + * @return stroke color of the GeoJsonPolygon + */ + public int getStrokeColor() { + return mPolygonOptions.getStrokeColor(); + } + + /** + * Sets the stroke color of the GeoJsonPolygon as a 32-bit ARGB color + * + * @param strokeColor stroke color value of the GeoJsonPolygon + */ + public void setStrokeColor(int strokeColor) { + mPolygonOptions.strokeColor(strokeColor); + styleChanged(); + } + + /** + * Gets the stroke width of the GeoJsonPolygon in screen pixels + * + * @return stroke width of the GeoJsonPolygon + */ + public float getStrokeWidth() { + return mPolygonOptions.getStrokeWidth(); + } + + /** + * Sets the stroke width of the GeoJsonPolygon in screen pixels + * + * @param strokeWidth stroke width value of the GeoJsonPolygon + */ + public void setStrokeWidth(float strokeWidth) { + mPolygonOptions.strokeWidth(strokeWidth); + styleChanged(); + } + + /** + * Gets the z index of the GeoJsonPolygon + * + * @return z index of the GeoJsonPolygon + */ + public float getZIndex() { + return mPolygonOptions.getZIndex(); + } + + /** + * Sets the z index of the GeoJsonPolygon + * + * @param zIndex z index value of the GeoJsonPolygon + */ + public void setZIndex(float zIndex) { + mPolygonOptions.zIndex(zIndex); + styleChanged(); + } + + /** + * Gets whether the GeoJsonPolygon is visible + * + * @return true if GeoJsonPolygon is visible, false if not visible + */ + @Override + public boolean isVisible() { + return mPolygonOptions.isVisible(); + } + + /** + * Sets whether the GeoJsonPolygon is visible + * + * @param visible true if GeoJsonPolygon is visible, false if not visible + */ + @Override + public void setVisible(boolean visible) { + mPolygonOptions.visible(visible); + styleChanged(); + } + + /** + * Notifies the observers, GeoJsonFeature objects, that the style has changed. Indicates to the + * GeoJsonFeature that it should check whether a redraw is needed for the feature. + */ + private void styleChanged() { + setChanged(); + notifyObservers(); + } + + /** + * Gets a new PolygonOptions object containing styles for the GeoJsonPolygon + * + * @return new PolygonOptions object + */ + public PolygonOptions toPolygonOptions() { + PolygonOptions polygonOptions = new PolygonOptions(); + polygonOptions.fillColor(mPolygonOptions.getFillColor()); + polygonOptions.geodesic(mPolygonOptions.isGeodesic()); + polygonOptions.strokeColor(mPolygonOptions.getStrokeColor()); + polygonOptions.strokeWidth(mPolygonOptions.getStrokeWidth()); + polygonOptions.visible(mPolygonOptions.isVisible()); + polygonOptions.zIndex(mPolygonOptions.getZIndex()); + return polygonOptions; + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder("PolygonStyle{"); + sb.append("\n geometry type=").append(Arrays.toString(GEOMETRY_TYPE)); + sb.append(",\n fill color=").append(getFillColor()); + sb.append(",\n geodesic=").append(isGeodesic()); + sb.append(",\n stroke color=").append(getStrokeColor()); + sb.append(",\n stroke width=").append(getStrokeWidth()); + sb.append(",\n visible=").append(isVisible()); + sb.append(",\n z index=").append(getZIndex()); + sb.append("\n}\n"); + return sb.toString(); + } +} diff --git a/library/src/com/google/maps/android/geojson/GeoJsonRenderer.java b/library/src/com/google/maps/android/geojson/GeoJsonRenderer.java new file mode 100644 index 000000000..d1a82393b --- /dev/null +++ b/library/src/com/google/maps/android/geojson/GeoJsonRenderer.java @@ -0,0 +1,416 @@ +package com.google.maps.android.geojson; + +import com.google.android.gms.maps.GoogleMap; +import com.google.android.gms.maps.model.Marker; +import com.google.android.gms.maps.model.MarkerOptions; +import com.google.android.gms.maps.model.Polygon; +import com.google.android.gms.maps.model.PolygonOptions; +import com.google.android.gms.maps.model.Polyline; +import com.google.android.gms.maps.model.PolylineOptions; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Observable; +import java.util.Observer; +import java.util.Set; + +/** + * Renders GeoJsonFeature objects onto the GoogleMap as Marker, Polyline and Polygon objects. Also + * removes GeoJsonFeature objects and redraws features when updated. + */ +/* package */ class GeoJsonRenderer implements Observer { + + private final static int POLYGON_OUTER_COORDINATE_INDEX = 0; + + private final static int POLYGON_INNER_COORDINATE_INDEX = 1; + + private final static Object FEATURE_NOT_ON_MAP = null; + + /** + * Value is a Marker, Polyline, Polygon or an array of these that have been created from the + * corresponding key + */ + private final HashMap mFeatures; + + private final GeoJsonPointStyle mDefaultPointStyle; + + private final GeoJsonLineStringStyle mDefaultLineStringStyle; + + private final GeoJsonPolygonStyle mDefaultPolygonStyle; + + private boolean mLayerOnMap; + + private GoogleMap mMap; + + /** + * Creates a new GeoJsonRender object + * + * @param map map to place GeoJsonFeature objects on + */ + /* package */ GeoJsonRenderer(GoogleMap map, HashMap features) { + mMap = map; + mFeatures = features; + mLayerOnMap = false; + mDefaultPointStyle = new GeoJsonPointStyle(); + mDefaultLineStringStyle = new GeoJsonLineStringStyle(); + mDefaultPolygonStyle = new GeoJsonPolygonStyle(); + + // Add default styles to features + for (GeoJsonFeature feature : getFeatures()) { + setFeatureDefaultStyles(feature); + } + } + + /** + * Given a Marker, Polyline, Polygon or an array of these and removes it from the map + * + * @param mapObject map object or array of map objects to remove from the map + */ + private static void removeFromMap(Object mapObject) { + if (mapObject instanceof Marker) { + ((Marker) mapObject).remove(); + } else if (mapObject instanceof Polyline) { + ((Polyline) mapObject).remove(); + } else if (mapObject instanceof Polygon) { + ((Polygon) mapObject).remove(); + } else if (mapObject instanceof ArrayList) { + for (Object mapObjectElement : (ArrayList) mapObject) { + removeFromMap(mapObjectElement); + } + } + } + + /* package */ boolean isLayerOnMap() { + return mLayerOnMap; + } + + /** + * Gets the GoogleMap that GeoJsonFeature objects are being placed on + * + * @return GoogleMap + */ + /* package */ GoogleMap getMap() { + return mMap; + } + + /** + * Changes the map that GeoJsonFeature objects are being drawn onto. Existing objects are + * removed from the previous map and drawn onto the new map. + * + * @param map GoogleMap to place GeoJsonFeature objects on + */ + /* package */ void setMap(GoogleMap map) { + for (GeoJsonFeature feature : getFeatures()) { + redrawFeatureToMap(feature, map); + } + } + + /** + * Adds all of the stored features in the layer onto the map if the layer is not already on the + * map. + */ + /* package */ void addLayerToMap() { + if (!mLayerOnMap) { + mLayerOnMap = true; + for (GeoJsonFeature feature : getFeatures()) { + addFeature(feature); + } + } + } + + /** + * Gets a set containing GeoJsonFeatures + * + * @return set containing GeoJsonFeatures + */ + /* package */ Set getFeatures() { + return mFeatures.keySet(); + } + + /** + * Checks for each style in the feature and adds a default style if none is applied + * + * @param feature feature to apply default styles to + */ + private void setFeatureDefaultStyles(GeoJsonFeature feature) { + if (feature.getPointStyle() == null) { + feature.setPointStyle(mDefaultPointStyle); + } + if (feature.getLineStringStyle() == null) { + feature.setLineStringStyle(mDefaultLineStringStyle); + } + if (feature.getPolygonStyle() == null) { + feature.setPolygonStyle(mDefaultPolygonStyle); + } + } + + /** + * Adds a new GeoJsonFeature to the map if its geometry property is not null. + * + * @param feature feature to add to the map + */ + /* package */ void addFeature(GeoJsonFeature feature) { + Object mapObject = FEATURE_NOT_ON_MAP; + setFeatureDefaultStyles(feature); + if (mLayerOnMap) { + feature.addObserver(this); + + if (mFeatures.containsKey(feature)) { + // Remove current map objects before adding new ones + removeFromMap(mFeatures.get(feature)); + } + + if (feature.hasGeometry()) { + // Create new map object + mapObject = addFeatureToMap(feature, feature.getGeometry()); + } + } + mFeatures.put(feature, mapObject); + } + + /** + * Removes all GeoJsonFeature objects stored in the mFeatures hashmap from the map + */ + /* package */ void removeLayerFromMap() { + if (mLayerOnMap) { + for (GeoJsonFeature feature : mFeatures.keySet()) { + removeFromMap(mFeatures.get(feature)); + + feature.deleteObserver(this); + } + mLayerOnMap = false; + } + } + + /** + * Removes a GeoJsonFeature from the map if its geometry property is not null + * + * @param feature feature to remove from map + */ + /* package */ void removeFeature(GeoJsonFeature feature) { + // Check if given feature is stored + if (mFeatures.containsKey(feature)) { + removeFromMap(mFeatures.remove(feature)); + feature.deleteObserver(this); + } + } + + /** + * Gets the default style used to render GeoJsonPoints + * + * @return default style used to render GeoJsonPoints + */ + /* package */ GeoJsonPointStyle getDefaultPointStyle() { + return mDefaultPointStyle; + } + + /** + * Gets the default style used to render GeoJsonLineStrings + * + * @return default style used to render GeoJsonLineStrings + */ + /* package */ GeoJsonLineStringStyle getDefaultLineStringStyle() { + return mDefaultLineStringStyle; + } + + /** + * Gets the default style used to render GeoJsonPolygons + * + * @return default style used to render GeoJsonPolygons + */ + /* package */ GeoJsonPolygonStyle getDefaultPolygonStyle() { + return mDefaultPolygonStyle; + } + + /** + * Adds a new object onto the map using the GeoJsonGeometry for the coordinates and the + * GeoJsonFeature for the styles. + * + * @param feature feature to get geometry style + * @param geometry geometry to add to the map + */ + private Object addFeatureToMap(GeoJsonFeature feature, GeoJsonGeometry geometry) { + String geometryType = geometry.getType(); + if (geometryType.equals("Point")) { + return addPointToMap(feature.getPointStyle(), (GeoJsonPoint) geometry); + } else if (geometryType.equals("LineString")) { + return addLineStringToMap(feature.getLineStringStyle(), + (GeoJsonLineString) geometry); + } else if (geometryType.equals("Polygon")) { + return addPolygonToMap(feature.getPolygonStyle(), + (GeoJsonPolygon) geometry); + } else if (geometryType.equals("MultiPoint")) { + return addMultiPointToMap(feature.getPointStyle(), + (GeoJsonMultiPoint) geometry); + } else if (geometryType.equals("MultiLineString")) { + return addMultiLineStringToMap(feature.getLineStringStyle(), + ((GeoJsonMultiLineString) geometry)); + } else if (geometryType.equals("MultiPolygon")) { + return addMultiPolygonToMap(feature.getPolygonStyle(), + ((GeoJsonMultiPolygon) geometry)); + } else if (geometryType.equals("GeometryCollection")) { + return addGeometryCollectionToMap(feature, + ((GeoJsonGeometryCollection) geometry).getGeometries()); + } + return null; + } + + /** + * Adds a GeoJsonPoint to the map as a Marker + * + * @param pointStyle contains relevant styling properties for the Marker + * @param point contains coordinates for the Marker + * @return Marker object created from the given GeoJsonPoint + */ + private Marker addPointToMap(GeoJsonPointStyle pointStyle, GeoJsonPoint point) { + MarkerOptions markerOptions = pointStyle.toMarkerOptions(); + markerOptions.position(point.getCoordinates()); + return mMap.addMarker(markerOptions); + } + + /** + * Adds all GeoJsonPoint objects in GeoJsonMultiPoint to the map as multiple Markers + * + * @param pointStyle contains relevant styling properties for the Markers + * @param multiPoint contains an array of GeoJsonPoints + * @return array of Markers that have been added to the map + */ + private ArrayList addMultiPointToMap(GeoJsonPointStyle pointStyle, + GeoJsonMultiPoint multiPoint) { + ArrayList markers = new ArrayList(); + for (GeoJsonPoint geoJsonPoint : multiPoint.getPoints()) { + markers.add(addPointToMap(pointStyle, geoJsonPoint)); + } + return markers; + } + + /** + * Adds a GeoJsonLineString to the map as a Polyline + * + * @param lineStringStyle contains relevant styling properties for the Polyline + * @param lineString contains coordinates for the Polyline + * @return Polyline object created from given GeoJsonLineString + */ + private Polyline addLineStringToMap(GeoJsonLineStringStyle lineStringStyle, + GeoJsonLineString lineString) { + PolylineOptions polylineOptions = lineStringStyle.toPolylineOptions(); + // Add coordinates + polylineOptions.addAll(lineString.getCoordinates()); + return mMap.addPolyline(polylineOptions); + } + + /** + * Adds all GeoJsonLineString objects in the GeoJsonMultiLineString to the map as multiple + * Polylines + * + * @param lineStringStyle contains relevant styling properties for the Polylines + * @param multiLineString contains an array of GeoJsonLineStrings + * @return array of Polylines that have been added to the map + */ + private ArrayList addMultiLineStringToMap(GeoJsonLineStringStyle lineStringStyle, + GeoJsonMultiLineString multiLineString) { + ArrayList polylines = new ArrayList(); + for (GeoJsonLineString geoJsonLineString : multiLineString.getLineStrings()) { + polylines.add(addLineStringToMap(lineStringStyle, geoJsonLineString)); + } + return polylines; + } + + /** + * Adds a GeoJsonPolygon to the map as a Polygon + * + * @param polygonStyle contains relevant styling properties for the Polygon + * @param polygon contains coordinates for the Polygon + * @return Polygon object created from given GeoJsonPolygon + */ + private Polygon addPolygonToMap(GeoJsonPolygonStyle polygonStyle, GeoJsonPolygon polygon) { + PolygonOptions polygonOptions = polygonStyle.toPolygonOptions(); + // First array of coordinates are the outline + polygonOptions.addAll(polygon.getCoordinates().get(POLYGON_OUTER_COORDINATE_INDEX)); + // Following arrays are holes + for (int i = POLYGON_INNER_COORDINATE_INDEX; i < polygon.getCoordinates().size(); + i++) { + polygonOptions.addHole(polygon.getCoordinates().get(i)); + } + return mMap.addPolygon(polygonOptions); + } + + /** + * Adds all GeoJsonPolygon in the GeoJsonMultiPolygon to the map as multiple Polygons + * + * @param polygonStyle contains relevant styling properties for the Polygons + * @param multiPolygon contains an array of GeoJsonPolygons + * @return array of Polygons that have been added to the map + */ + private ArrayList addMultiPolygonToMap(GeoJsonPolygonStyle polygonStyle, + GeoJsonMultiPolygon multiPolygon) { + ArrayList polygons = new ArrayList(); + for (GeoJsonPolygon geoJsonPolygon : multiPolygon.getPolygons()) { + polygons.add(addPolygonToMap(polygonStyle, geoJsonPolygon)); + } + return polygons; + } + + /** + * Adds all GeoJsonGeometry objects stored in the GeoJsonGeometryCollection onto the map. + * Supports recursive GeometryCollections. + * + * @param feature contains relevant styling properties for the GeoJsonGeometry inside + * the GeoJsonGeometryCollection + * @param geoJsonGeometries contains an array of GeoJsonGeometry objects + * @return array of Marker, Polyline, Polygons that have been added to the map + */ + private ArrayList addGeometryCollectionToMap(GeoJsonFeature feature, + List geoJsonGeometries) { + ArrayList geometries = new ArrayList(); + for (GeoJsonGeometry geometry : geoJsonGeometries) { + geometries.add(addFeatureToMap(feature, geometry)); + } + return geometries; + } + + /** + * Redraws a given GeoJsonFeature onto the map. The map object is obtained from the mFeatures + * hashmap and it is removed and added. + * + * @param feature feature to redraw onto the map + */ + private void redrawFeatureToMap(GeoJsonFeature feature) { + redrawFeatureToMap(feature, mMap); + } + + private void redrawFeatureToMap(GeoJsonFeature feature, GoogleMap map) { + removeFromMap(mFeatures.get(feature)); + mFeatures.put(feature, FEATURE_NOT_ON_MAP); + mMap = map; + if (map != null && feature.hasGeometry()) { + mFeatures.put(feature, addFeatureToMap(feature, feature.getGeometry())); + } + } + + /** + * Update is called if the developer sets a style or geometry in a GeoJsonFeature object + * + * @param observable GeoJsonFeature object + * @param data null, no extra argument is passed through the notifyObservers method + */ + public void update(Observable observable, Object data) { + if (observable instanceof GeoJsonFeature) { + GeoJsonFeature feature = ((GeoJsonFeature) observable); + boolean featureIsOnMap = mFeatures.get(feature) != FEATURE_NOT_ON_MAP; + if (featureIsOnMap && feature.hasGeometry()) { + // Checks if the feature has been added to the map and its geometry is not null + // TODO: change this so that we don't add and remove + redrawFeatureToMap(feature); + } else if (featureIsOnMap && !feature.hasGeometry()) { + // Checks if feature is on map and geometry is null + removeFromMap(mFeatures.get(feature)); + mFeatures.put(feature, FEATURE_NOT_ON_MAP); + } else if (!featureIsOnMap && feature.hasGeometry()) { + // Checks if the feature isn't on the map and geometry is not null + addFeature(feature); + } + } + } +} diff --git a/library/src/com/google/maps/android/geojson/GeoJsonStyle.java b/library/src/com/google/maps/android/geojson/GeoJsonStyle.java new file mode 100644 index 000000000..77dee5a1b --- /dev/null +++ b/library/src/com/google/maps/android/geojson/GeoJsonStyle.java @@ -0,0 +1,19 @@ +package com.google.maps.android.geojson; + +/** + * Class used to apply styles for the GeoJsonFeature objects + */ +interface GeoJsonStyle { + + /** + * Gets the type of geometries this style can be applied to + * + * @return type of geometries this style can be applied to + */ + public String[] getGeometryType(); + + public boolean isVisible(); + + public void setVisible(boolean visible); + +} diff --git a/library/tests/src/com/google/maps/android/geojson/GeoJsonFeatureTest.java b/library/tests/src/com/google/maps/android/geojson/GeoJsonFeatureTest.java new file mode 100644 index 000000000..3aaecdec3 --- /dev/null +++ b/library/tests/src/com/google/maps/android/geojson/GeoJsonFeatureTest.java @@ -0,0 +1,112 @@ +package com.google.maps.android.geojson; + +import com.google.android.gms.maps.model.LatLng; +import com.google.android.gms.maps.model.LatLngBounds; + +import junit.framework.TestCase; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; + +public class GeoJsonFeatureTest extends TestCase { + + GeoJsonFeature feature; + + public void testGetId() throws Exception { + feature = new GeoJsonFeature(null, "Pirate", null, null); + assertNotNull(feature.getId()); + assertTrue(feature.getId().equals("Pirate")); + feature = new GeoJsonFeature(null, null, null, null); + assertNull(feature.getId()); + } + + public void testProperty() throws Exception { + HashMap properties = new HashMap(); + properties.put("Color", "Yellow"); + properties.put("Width", "5"); + feature = new GeoJsonFeature(null, null, properties, null); + assertFalse(feature.hasProperty("llama")); + assertTrue(feature.hasProperty("Color")); + assertEquals("Yellow", feature.getProperty("Color")); + assertTrue(feature.hasProperty("Width")); + assertEquals("5", feature.getProperty("Width")); + assertNull(feature.removeProperty("banana")); + assertEquals("5", feature.removeProperty("Width")); + assertNull(feature.setProperty("Width", "10")); + assertEquals("10", feature.setProperty("Width", "500")); + } + + public void testPointStyle() { + feature = new GeoJsonFeature(null, null, null, null); + GeoJsonPointStyle pointStyle = new GeoJsonPointStyle(); + feature.setPointStyle(pointStyle); + assertEquals(pointStyle, feature.getPointStyle()); + + try { + feature.setPointStyle(null); + fail(); + } catch (IllegalArgumentException e) { + assertEquals("Point style cannot be null", e.getMessage()); + } + } + + public void testLineStringStyle() { + feature = new GeoJsonFeature(null, null, null, null); + GeoJsonLineStringStyle lineStringStyle = new GeoJsonLineStringStyle(); + feature.setLineStringStyle(lineStringStyle); + assertEquals(lineStringStyle, feature.getLineStringStyle()); + + try { + feature.setLineStringStyle(null); + fail(); + } catch (IllegalArgumentException e) { + assertEquals("Line string style cannot be null", e.getMessage()); + } + } + + public void testPolygonStyle() { + feature = new GeoJsonFeature(null, null, null, null); + GeoJsonPolygonStyle polygonStyle = new GeoJsonPolygonStyle(); + feature.setPolygonStyle(polygonStyle); + assertEquals(polygonStyle, feature.getPolygonStyle()); + + try { + feature.setPolygonStyle(null); + fail(); + } catch (IllegalArgumentException e) { + assertEquals("Polygon style cannot be null", e.getMessage()); + } + } + + public void testGeometry() { + feature = new GeoJsonFeature(null, null, null, null); + assertNull(feature.getGeometry()); + GeoJsonPoint point = new GeoJsonPoint(new LatLng(0, 0)); + feature.setGeometry(point); + assertEquals(point, feature.getGeometry()); + feature.setGeometry(null); + assertNull(feature.getGeometry()); + + GeoJsonLineString lineString = new GeoJsonLineString(new ArrayList(Arrays.asList(new LatLng(0, 0), new LatLng(50, 50)))); + feature = new GeoJsonFeature(lineString, null, null, null); + assertEquals(lineString, feature.getGeometry()); + feature.setGeometry(point); + assertEquals(point, feature.getGeometry()); + feature.setGeometry(null); + assertNull(feature.getGeometry()); + feature.setGeometry(lineString); + assertEquals(lineString, feature.getGeometry()); + } + + public void testGetBoundingBox() { + feature = new GeoJsonFeature(null, null, null, null); + assertNull(feature.getBoundingBox()); + + LatLngBounds boundingBox = new LatLngBounds(new LatLng(-20, -20), new LatLng(50, 50)); + feature = new GeoJsonFeature(null, null, null, boundingBox); + assertEquals(boundingBox, feature.getBoundingBox()); + } + + +} \ No newline at end of file diff --git a/library/tests/src/com/google/maps/android/geojson/GeoJsonLayerTest.java b/library/tests/src/com/google/maps/android/geojson/GeoJsonLayerTest.java new file mode 100644 index 000000000..1950d03e4 --- /dev/null +++ b/library/tests/src/com/google/maps/android/geojson/GeoJsonLayerTest.java @@ -0,0 +1,113 @@ +package com.google.maps.android.geojson; + +import com.google.android.gms.maps.GoogleMap; +import com.google.android.gms.maps.model.LatLng; +import com.google.android.gms.maps.model.LatLngBounds; + +import junit.framework.TestCase; + +import org.json.JSONObject; + +import android.graphics.Color; + +public class GeoJsonLayerTest extends TestCase { + GoogleMap map; + GeoJsonLayer mLayer; + GoogleMap map2; + public void setUp() throws Exception { + super.setUp(); + mLayer = new GeoJsonLayer(map, createFeatureCollection()); + } + + public void testGetFeatures() throws Exception { + int featureCount = 0; + for (GeoJsonFeature feature : mLayer.getFeatures()) { + featureCount++; + } + assertEquals(3, featureCount); + } + + public void testAddFeature() throws Exception { + int featureCount = 0; + mLayer.addFeature(new GeoJsonFeature(null, null, null, null)); + for (GeoJsonFeature feature : mLayer.getFeatures()) { + featureCount++; + } + assertEquals(4, featureCount); + } + + public void testRemoveFeature() throws Exception { + int featureCount = 0; + for (GeoJsonFeature feature : mLayer.getFeatures()) { + featureCount++; + } + assertEquals(3, featureCount); + } + + public void testMap() throws Exception { + assertEquals(map, mLayer.getMap()); + mLayer.setMap(map2); + assertEquals(map2, mLayer.getMap()); + mLayer.setMap(null); + assertEquals(null, mLayer.getMap()); + } + + public void testDefaultPointStyle() throws Exception { + mLayer.getDefaultPointStyle().setTitle("Dolphin"); + assertEquals("Dolphin", mLayer.getDefaultPointStyle().getTitle()); + } + + public void testDefaultLineStringStyle() throws Exception { + mLayer.getDefaultLineStringStyle().setColor(Color.BLUE); + assertEquals(Color.BLUE, mLayer.getDefaultLineStringStyle().getColor()); + } + + public void testDefaultPolygonStyle() throws Exception { + mLayer.getDefaultPolygonStyle().setGeodesic(true); + assertEquals(true, mLayer.getDefaultPolygonStyle().isGeodesic()); + } + + public void testGetBoundingBox() throws Exception { + assertEquals(new LatLngBounds(new LatLng(-80, -150), new LatLng(80, 150)), mLayer.getBoundingBox()); + } + + private JSONObject createFeatureCollection() throws Exception { + return new JSONObject( + "{ \"type\": \"FeatureCollection\",\n" + + "\"bbox\": [-150.0, -80.0, 150.0, 80.0]," + + " \"features\": [\n" + + " { \"type\": \"Feature\",\n" + + " \"id\": \"point\", \n" + + " \"geometry\": {\"type\": \"Point\", \"coordinates\": [102.0, 0.5]},\n" + + " \"properties\": {\"prop0\": \"value0\"}\n" + + " },\n" + + " { \"type\": \"Feature\",\n" + + " \"geometry\": {\n" + + " \"type\": \"LineString\",\n" + + " \"coordinates\": [\n" + + " [102.0, 0.0], [103.0, 1.0], [104.0, 0.0], [105.0, 1.0]\n" + + " ]\n" + + " },\n" + + " \"properties\": {\n" + + " \"prop0\": \"value0\",\n" + + " \"prop1\": 0.0\n" + + " }\n" + + " },\n" + + " { \"type\": \"Feature\",\n" + + " \"geometry\": {\n" + + " \"type\": \"Polygon\",\n" + + " \"coordinates\": [\n" + + " [ [100.0, 0.0], [101.0, 0.0], [101.0, 1.0],\n" + + " [100.0, 1.0], [100.0, 0.0] ]\n" + + " ]\n" + + " },\n" + + " \"properties\": {\n" + + " \"prop0\": \"value0\",\n" + + " \"prop1\": {\"this\": \"that\"}\n" + + " }\n" + + " }\n" + + " ]\n" + + " }" + ); + } +} \ No newline at end of file diff --git a/library/tests/src/com/google/maps/android/geojson/GeoJsonLineStringStyleTest.java b/library/tests/src/com/google/maps/android/geojson/GeoJsonLineStringStyleTest.java new file mode 100644 index 000000000..f4234a9fc --- /dev/null +++ b/library/tests/src/com/google/maps/android/geojson/GeoJsonLineStringStyleTest.java @@ -0,0 +1,78 @@ +package com.google.maps.android.geojson; + +import junit.framework.TestCase; + +import android.graphics.Color; + +import java.util.Arrays; + +public class GeoJsonLineStringStyleTest extends TestCase { + + GeoJsonLineStringStyle lineStringStyle; + + public void setUp() throws Exception { + super.setUp(); + lineStringStyle = new GeoJsonLineStringStyle(); + } + + public void testGetGeometryType() throws Exception { + assertTrue(Arrays.asList(lineStringStyle.getGeometryType()).contains("LineString")); + assertTrue(Arrays.asList(lineStringStyle.getGeometryType()).contains("MultiLineString")); + assertTrue(Arrays.asList(lineStringStyle.getGeometryType()).contains("GeometryCollection")); + assertEquals(3, lineStringStyle.getGeometryType().length); + } + + public void testColor() throws Exception { + lineStringStyle.setColor(Color.YELLOW); + assertEquals(Color.YELLOW, lineStringStyle.getColor()); + assertEquals(Color.YELLOW, lineStringStyle.toPolylineOptions().getColor()); + + lineStringStyle.setColor(0x76543210); + assertEquals(0x76543210, lineStringStyle.getColor()); + assertEquals(0x76543210, lineStringStyle.toPolylineOptions().getColor()); + + lineStringStyle.setColor(Color.parseColor("#000000")); + assertEquals(Color.parseColor("#000000"), lineStringStyle.getColor()); + assertEquals(Color.parseColor("#000000"), lineStringStyle.toPolylineOptions().getColor()); + } + + public void testGeodesic() throws Exception { + lineStringStyle.setGeodesic(true); + assertTrue(lineStringStyle.isGeodesic()); + assertTrue(lineStringStyle.toPolylineOptions().isGeodesic()); + } + + public void testVisible() throws Exception { + lineStringStyle.setVisible(false); + assertFalse(lineStringStyle.isVisible()); + assertFalse(lineStringStyle.toPolylineOptions().isVisible()); + } + + public void testWidth() throws Exception { + lineStringStyle.setWidth(20.2f); + assertEquals(20.2f, lineStringStyle.getWidth()); + assertEquals(20.2f, lineStringStyle.toPolylineOptions().getWidth()); + } + + public void testZIndex() throws Exception { + lineStringStyle.setZIndex(50.78f); + assertEquals(50.78f, lineStringStyle.getZIndex()); + assertEquals(50.78f, lineStringStyle.toPolylineOptions().getZIndex()); + } + + public void testDefaultLineStringStyle() { + assertEquals(Color.BLACK, lineStringStyle.getColor()); + assertFalse(lineStringStyle.isGeodesic()); + assertTrue(lineStringStyle.isVisible()); + assertEquals(10.0f, lineStringStyle.getWidth()); + assertEquals(0.0f, lineStringStyle.getZIndex()); + } + + public void testDefaultGetPolylineOptions() throws Exception { + assertEquals(Color.BLACK, lineStringStyle.toPolylineOptions().getColor()); + assertFalse(lineStringStyle.toPolylineOptions().isGeodesic()); + assertTrue(lineStringStyle.toPolylineOptions().isVisible()); + assertEquals(10.0f, lineStringStyle.toPolylineOptions().getWidth()); + assertEquals(0.0f, lineStringStyle.toPolylineOptions().getZIndex()); + } +} \ No newline at end of file diff --git a/library/tests/src/com/google/maps/android/geojson/GeoJsonLineStringTest.java b/library/tests/src/com/google/maps/android/geojson/GeoJsonLineStringTest.java new file mode 100644 index 000000000..2612c5706 --- /dev/null +++ b/library/tests/src/com/google/maps/android/geojson/GeoJsonLineStringTest.java @@ -0,0 +1,37 @@ +package com.google.maps.android.geojson; + +import com.google.android.gms.maps.model.LatLng; + +import junit.framework.TestCase; + +import java.util.ArrayList; + +public class GeoJsonLineStringTest extends TestCase { + + GeoJsonLineString ls; + + public void testGetType() throws Exception { + ArrayList coordinates = new ArrayList(); + coordinates.add(new LatLng(0, 0)); + coordinates.add(new LatLng(50, 50)); + coordinates.add(new LatLng(100, 100)); + ls = new GeoJsonLineString(coordinates); + assertEquals("LineString", ls.getType()); + } + + public void testGetCoordinates() throws Exception { + ArrayList coordinates = new ArrayList(); + coordinates.add(new LatLng(0, 0)); + coordinates.add(new LatLng(50, 50)); + coordinates.add(new LatLng(100, 100)); + ls = new GeoJsonLineString(coordinates); + assertEquals(coordinates, ls.getCoordinates()); + + try { + ls = new GeoJsonLineString(null); + fail(); + } catch (IllegalArgumentException e) { + assertEquals("Coordinates cannot be null", e.getMessage()); + } + } +} \ No newline at end of file diff --git a/library/tests/src/com/google/maps/android/geojson/GeoJsonMultiLineStringTest.java b/library/tests/src/com/google/maps/android/geojson/GeoJsonMultiLineStringTest.java new file mode 100644 index 000000000..db8bece5a --- /dev/null +++ b/library/tests/src/com/google/maps/android/geojson/GeoJsonMultiLineStringTest.java @@ -0,0 +1,44 @@ +package com.google.maps.android.geojson; + +import com.google.android.gms.maps.model.LatLng; + +import junit.framework.TestCase; + +import java.util.ArrayList; +import java.util.Arrays; + +public class GeoJsonMultiLineStringTest extends TestCase { + + GeoJsonMultiLineString mls; + + public void testGetType() throws Exception { + ArrayList lineStrings = new ArrayList(); + lineStrings.add(new GeoJsonLineString( + new ArrayList(Arrays.asList(new LatLng(0, 0), new LatLng(50, 50))))); + lineStrings.add(new GeoJsonLineString( + new ArrayList(Arrays.asList(new LatLng(80, 10), new LatLng(-54, 12.7))))); + mls = new GeoJsonMultiLineString(lineStrings); + assertEquals("MultiLineString", mls.getType()); + } + + public void testGetLineStrings() throws Exception { + ArrayList lineStrings = new ArrayList(); + lineStrings.add(new GeoJsonLineString( + new ArrayList(Arrays.asList(new LatLng(0, 0), new LatLng(50, 50))))); + lineStrings.add(new GeoJsonLineString( + new ArrayList(Arrays.asList(new LatLng(80, 10), new LatLng(-54, 12.7))))); + mls = new GeoJsonMultiLineString(lineStrings); + assertEquals(lineStrings, mls.getLineStrings()); + + lineStrings = new ArrayList(); + mls = new GeoJsonMultiLineString(lineStrings); + assertEquals(new ArrayList(), mls.getLineStrings()); + + try { + mls = new GeoJsonMultiLineString(null); + fail(); + } catch (IllegalArgumentException e) { + assertEquals("GeoJsonLineStrings cannot be null", e.getMessage()); + } + } +} \ No newline at end of file diff --git a/library/tests/src/com/google/maps/android/geojson/GeoJsonMultiPointTest.java b/library/tests/src/com/google/maps/android/geojson/GeoJsonMultiPointTest.java new file mode 100644 index 000000000..1a2bd220e --- /dev/null +++ b/library/tests/src/com/google/maps/android/geojson/GeoJsonMultiPointTest.java @@ -0,0 +1,41 @@ +package com.google.maps.android.geojson; + +import com.google.android.gms.maps.model.LatLng; + +import junit.framework.TestCase; + +import java.util.ArrayList; + +public class GeoJsonMultiPointTest extends TestCase { + + GeoJsonMultiPoint mp; + + public void testGetType() throws Exception { + ArrayList points = new ArrayList(); + points.add(new GeoJsonPoint(new LatLng(0, 0))); + points.add(new GeoJsonPoint(new LatLng(5, 5))); + points.add(new GeoJsonPoint(new LatLng(10, 10))); + mp = new GeoJsonMultiPoint(points); + assertEquals("MultiPoint", mp.getType()); + } + + public void testGetPoints() throws Exception { + ArrayList points = new ArrayList(); + points.add(new GeoJsonPoint(new LatLng(0, 0))); + points.add(new GeoJsonPoint(new LatLng(5, 5))); + points.add(new GeoJsonPoint(new LatLng(10, 10))); + mp = new GeoJsonMultiPoint(points); + assertEquals(points, mp.getPoints()); + + points = new ArrayList(); + mp = new GeoJsonMultiPoint(points); + assertEquals(new ArrayList(), mp.getPoints()); + + try { + mp = new GeoJsonMultiPoint(null); + fail(); + } catch (IllegalArgumentException e) { + assertEquals("GeoJsonPoints cannot be null", e.getMessage()); + } + } +} \ No newline at end of file diff --git a/library/tests/src/com/google/maps/android/geojson/GeoJsonMultiPolygonTest.java b/library/tests/src/com/google/maps/android/geojson/GeoJsonMultiPolygonTest.java new file mode 100644 index 000000000..d50703a77 --- /dev/null +++ b/library/tests/src/com/google/maps/android/geojson/GeoJsonMultiPolygonTest.java @@ -0,0 +1,62 @@ +package com.google.maps.android.geojson; + +import com.google.android.gms.maps.model.LatLng; + +import junit.framework.TestCase; + +import java.util.ArrayList; +import java.util.Arrays; + +public class GeoJsonMultiPolygonTest extends TestCase { + + GeoJsonMultiPolygon mp; + + public void testGetType() throws Exception { + ArrayList polygons = new ArrayList(); + ArrayList> polygon = new ArrayList>(); + polygon.add(new ArrayList( + Arrays.asList(new LatLng(0, 0), new LatLng(20, 20), new LatLng(60, 60), + new LatLng(0, 0)))); + polygons.add(new GeoJsonPolygon(polygon)); + polygon = new ArrayList>(); + polygon.add(new ArrayList( + Arrays.asList(new LatLng(0, 0), new LatLng(50, 80), new LatLng(10, 15), + new LatLng(0, 0)))); + polygon.add(new ArrayList( + Arrays.asList(new LatLng(0, 0), new LatLng(20, 20), new LatLng(60, 60), + new LatLng(0, 0)))); + polygons.add(new GeoJsonPolygon(polygon)); + mp = new GeoJsonMultiPolygon(polygons); + assertEquals("MultiPolygon", mp.getType()); + } + + public void testGetPolygons() throws Exception { + ArrayList polygons = new ArrayList(); + ArrayList> polygon = new ArrayList>(); + polygon.add(new ArrayList( + Arrays.asList(new LatLng(0, 0), new LatLng(20, 20), new LatLng(60, 60), + new LatLng(0, 0)))); + polygons.add(new GeoJsonPolygon(polygon)); + polygon = new ArrayList>(); + polygon.add(new ArrayList( + Arrays.asList(new LatLng(0, 0), new LatLng(50, 80), new LatLng(10, 15), + new LatLng(0, 0)))); + polygon.add(new ArrayList( + Arrays.asList(new LatLng(0, 0), new LatLng(20, 20), new LatLng(60, 60), + new LatLng(0, 0)))); + polygons.add(new GeoJsonPolygon(polygon)); + mp = new GeoJsonMultiPolygon(polygons); + assertEquals(polygons, mp.getPolygons()); + + polygons = new ArrayList(); + mp = new GeoJsonMultiPolygon(polygons); + assertEquals(new ArrayList(), mp.getPolygons()); + + try { + mp = new GeoJsonMultiPolygon(null); + fail(); + } catch (IllegalArgumentException e) { + assertEquals("GeoJsonPolygons cannot be null", e.getMessage()); + } + } +} \ No newline at end of file diff --git a/library/tests/src/com/google/maps/android/geojson/GeoJsonParserTest.java b/library/tests/src/com/google/maps/android/geojson/GeoJsonParserTest.java new file mode 100644 index 000000000..cd9e598d0 --- /dev/null +++ b/library/tests/src/com/google/maps/android/geojson/GeoJsonParserTest.java @@ -0,0 +1,807 @@ +package com.google.maps.android.geojson; + +import com.google.android.gms.maps.model.LatLng; + +import junit.framework.TestCase; + +import org.json.JSONException; +import org.json.JSONObject; + +import java.util.ArrayList; +import java.util.Arrays; + +public class GeoJsonParserTest extends TestCase { + + public void setUp() throws Exception { + super.setUp(); + } + + public void testParseGeoJson() throws Exception { + JSONObject validGeoJsonObject = new JSONObject("{ \"type\": \"MultiLineString\",\n" + + " \"coordinates\": [\n" + + " [ [100.0, 0.0], [101.0, 1.0] ],\n" + + " [ [102.0, 2.0], [103.0, 3.0] ]\n" + + " ]\n" + + " }"); + + GeoJsonParser parser = new GeoJsonParser(validGeoJsonObject); + GeoJsonLineString ls1 = new GeoJsonLineString( + new ArrayList(Arrays.asList(new LatLng(0, 100), new LatLng(1, 101)))); + GeoJsonLineString ls2 = new GeoJsonLineString( + new ArrayList(Arrays.asList(new LatLng(2, 102), new LatLng(3, 103)))); + GeoJsonMultiLineString geoJsonMultiLineString = new GeoJsonMultiLineString( + new ArrayList(Arrays.asList(ls1, ls2))); + GeoJsonFeature geoJsonFeature = new GeoJsonFeature(geoJsonMultiLineString, null, null, + null); + ArrayList geoJsonFeatures = new ArrayList( + Arrays.asList(geoJsonFeature)); + assertEquals(geoJsonFeatures.get(0).getId(), parser.getFeatures().get(0).getId()); + } + + public void testParseGeometryCollection() throws Exception { + GeoJsonParser parser = new GeoJsonParser(validGeometryCollection()); + assertEquals(1, parser.getFeatures().size()); + for (GeoJsonFeature feature : parser.getFeatures()) { + assertEquals("GeometryCollection", feature.getGeometry().getType()); + int size = 0; + for (String property : feature.getPropertyKeys()) { + size++; + } + assertEquals(2, size); + assertEquals("Popsicles", feature.getId()); + GeoJsonGeometryCollection geometry = ((GeoJsonGeometryCollection) feature + .getGeometry()); + assertEquals(1, geometry.getGeometries().size()); + for (GeoJsonGeometry geoJsonGeometry : geometry.getGeometries()) { + assertEquals("GeometryCollection", geoJsonGeometry.getType()); + } + } + } + + public void testParsePoint() throws Exception { + GeoJsonParser parser = new GeoJsonParser(validPoint()); + assertEquals(1, parser.getFeatures().size()); + assertNull(parser.getFeatures().get(0).getBoundingBox()); + assertNull(parser.getFeatures().get(0).getId()); + int size = 0; + for (String property : parser.getFeatures().get(0).getPropertyKeys()) { + size++; + } + assertEquals(0, size); + assertTrue(parser.getFeatures().get(0).getGeometry() instanceof GeoJsonPoint); + GeoJsonPoint point = (GeoJsonPoint) parser.getFeatures().get(0).getGeometry(); + assertEquals(new LatLng(0.0, 100.0), point.getCoordinates()); + } + + public void testParseLineString() throws Exception { + GeoJsonParser parser = new GeoJsonParser(validLineString()); + assertEquals(1, parser.getFeatures().size()); + assertNull(parser.getFeatures().get(0).getBoundingBox()); + assertNull(parser.getFeatures().get(0).getId()); + int size = 0; + for (String property : parser.getFeatures().get(0).getPropertyKeys()) { + size++; + } + assertEquals(0, size); + assertTrue(parser.getFeatures().get(0).getGeometry() instanceof GeoJsonLineString); + GeoJsonLineString lineString = (GeoJsonLineString) parser.getFeatures().get(0) + .getGeometry(); + assertEquals(2, lineString.getCoordinates().size()); + ArrayList ls = new ArrayList( + Arrays.asList(new LatLng(0, 100), new LatLng(1, 101))); + assertEquals(ls, lineString.getCoordinates()); + } + + public void testParsePolygon() throws Exception { + GeoJsonParser parser = new GeoJsonParser(validPolygon()); + assertEquals(1, parser.getFeatures().size()); + assertNull(parser.getFeatures().get(0).getBoundingBox()); + assertNull(parser.getFeatures().get(0).getId()); + int size = 0; + for (String property : parser.getFeatures().get(0).getPropertyKeys()) { + size++; + } + assertEquals(0, size); + assertTrue(parser.getFeatures().get(0).getGeometry() instanceof GeoJsonPolygon); + GeoJsonPolygon polygon = (GeoJsonPolygon) parser.getFeatures().get(0).getGeometry(); + assertEquals(2, polygon.getCoordinates().size()); + assertEquals(5, polygon.getCoordinates().get(0).size()); + assertEquals(5, polygon.getCoordinates().get(1).size()); + ArrayList> p = new ArrayList>(); + p.add(new ArrayList( + Arrays.asList(new LatLng(0, 100), new LatLng(0, 101), new LatLng(1, 101), + new LatLng(1, 100), new LatLng(0, 100)))); + p.add(new ArrayList(Arrays.asList(new LatLng(0.2, 100.2), new LatLng(0.2, 100.8), + new LatLng(0.8, 100.8), new LatLng(0.8, 100.2), new LatLng(0.2, 100.2)))); + assertEquals(p, polygon.getCoordinates()); + } + + public void testParseMultiPoint() throws Exception { + GeoJsonParser parser = new GeoJsonParser(validMultiPoint()); + assertEquals(1, parser.getFeatures().size()); + assertNull(parser.getFeatures().get(0).getBoundingBox()); + assertNull(parser.getFeatures().get(0).getId()); + int size = 0; + for (String property : parser.getFeatures().get(0).getPropertyKeys()) { + size++; + } + assertEquals(0, size); + assertTrue(parser.getFeatures().get(0).getGeometry() instanceof GeoJsonMultiPoint); + GeoJsonMultiPoint multiPoint = (GeoJsonMultiPoint) parser.getFeatures().get(0) + .getGeometry(); + assertEquals(2, multiPoint.getPoints().size()); + assertEquals(new LatLng(0, 100), multiPoint.getPoints().get(0).getCoordinates()); + assertEquals(new LatLng(1, 101), multiPoint.getPoints().get(1).getCoordinates()); + } + + public void testParseMultiLineString() throws Exception { + GeoJsonParser parser = new GeoJsonParser(validMultiLineString()); + assertEquals(1, parser.getFeatures().size()); + assertNull(parser.getFeatures().get(0).getBoundingBox()); + assertNull(parser.getFeatures().get(0).getId()); + int size = 0; + for (String property : parser.getFeatures().get(0).getPropertyKeys()) { + size++; + } + assertEquals(0, size); + assertTrue(parser.getFeatures().get(0).getGeometry() instanceof GeoJsonMultiLineString); + GeoJsonMultiLineString multiLineString = (GeoJsonMultiLineString) parser.getFeatures() + .get(0).getGeometry(); + assertEquals(2, multiLineString.getLineStrings().size()); + ArrayList ls = new ArrayList( + Arrays.asList(new LatLng(0, 100), new LatLng(1, 101))); + assertEquals(ls, multiLineString.getLineStrings().get(0).getCoordinates()); + ls = new ArrayList( + Arrays.asList(new LatLng(2, 102), new LatLng(3, 103))); + assertEquals(ls, multiLineString.getLineStrings().get(1).getCoordinates()); + } + + public void testParseMultiPolygon() throws Exception { + GeoJsonParser parser = new GeoJsonParser(validMultiPolygon()); + assertEquals(1, parser.getFeatures().size()); + GeoJsonFeature feature = parser.getFeatures().get(0); + GeoJsonMultiPolygon polygon = ((GeoJsonMultiPolygon) feature.getGeometry()); + assertEquals(2, polygon.getPolygons().size()); + assertEquals(1, polygon.getPolygons().get(0).getCoordinates().size()); + ArrayList> p1 = new ArrayList>(); + p1.add(new ArrayList( + Arrays.asList(new LatLng(2, 102), new LatLng(2, 103), new LatLng(3, 103), + new LatLng(3, 102), new LatLng(2, 102)))); + assertEquals(p1, polygon.getPolygons().get(0).getCoordinates()); + assertEquals(2, polygon.getPolygons().get(1).getCoordinates().size()); + ArrayList> p2 = new ArrayList>(); + p2.add(new ArrayList( + Arrays.asList(new LatLng(0, 100), new LatLng(0, 101), new LatLng(1, 101), + new LatLng(1, 100), new LatLng(0, 100)))); + p2.add(new ArrayList(Arrays.asList(new LatLng(0.2, 100.2), new LatLng(0.2, 100.8), + new LatLng(0.8, 100.8), new LatLng(0.8, 100.2), new LatLng(0.2, 100.2)))); + assertEquals(p2, polygon.getPolygons().get(1).getCoordinates()); + } + + public void testEmptyFile() throws Exception { + GeoJsonParser parser = new GeoJsonParser(emptyFile()); + assertNull(parser.getBoundingBox()); + assertEquals(0, parser.getFeatures().size()); + } + + public void testInvalidFeature() throws Exception { + GeoJsonParser parser; + + // Feature exists without geometry + parser = new GeoJsonParser(invalidFeatureNoGeometry()); + assertNull(parser.getBoundingBox()); + assertEquals(1, parser.getFeatures().size()); + assertNull(parser.getFeatures().get(0).getGeometry()); + assertEquals("Dinagat Islands", parser.getFeatures().get(0).getProperty("name")); + + // Feature exists without properties + parser = new GeoJsonParser(invalidFeatureNoProperties()); + assertNull(parser.getBoundingBox()); + assertEquals(1, parser.getFeatures().size()); + int size = 0; + for (String property : parser.getFeatures().get(0).getPropertyKeys()) { + size++; + } + assertEquals(0, size); + + // No features exist due to no type + parser = new GeoJsonParser(invalidFeatureMissingType()); + assertNull(parser.getBoundingBox()); + assertEquals(0, parser.getFeatures().size()); + + // 1 geometry in geometry collection, other geometry was invalid + parser = new GeoJsonParser(invalidFeatureGeometryCollectionInvalidGeometry()); + assertNull(parser.getBoundingBox()); + assertEquals(1, parser.getFeatures().size()); + assertEquals(1, ((GeoJsonGeometryCollection) parser.getFeatures().get(0).getGeometry()) + .getGeometries().size()); + + // No geometry due to no geometries array member + parser = new GeoJsonParser(invalidFeatureGeometryCollectionNoGeometries()); + assertNull(parser.getBoundingBox()); + assertEquals(1, parser.getFeatures().size()); + assertNull(parser.getFeatures().get(0).getGeometry()); + } + + public void testInvalidFeatureCollection() throws Exception { + GeoJsonParser parser; + + // 1 feature without geometry + parser = new GeoJsonParser(invalidFeatureCollectionNoCoordinatesInGeometryInFeature()); + assertNull(parser.getBoundingBox()); + assertEquals(3, parser.getFeatures().size()); + assertNotNull(parser.getFeatures().get(0).getGeometry()); + assertNull(parser.getFeatures().get(1).getGeometry()); + assertNotNull(parser.getFeatures().get(2).getGeometry()); + + // 1 feature without geometry + parser = new GeoJsonParser(invalidFeatureCollectionNoTypeInGeometryInFeature()); + assertNull(parser.getBoundingBox()); + assertEquals(3, parser.getFeatures().size()); + assertNotNull(parser.getFeatures().get(0).getGeometry()); + assertNotNull(parser.getFeatures().get(1).getGeometry()); + assertNull(parser.getFeatures().get(2).getGeometry()); + + // No features due to no features array + parser = new GeoJsonParser(invalidFeatureCollectionNoFeaturesArray()); + assertNull(parser.getBoundingBox()); + assertEquals(0, parser.getFeatures().size()); + + // 1 feature not parsed due to no type indicating it is a feature + parser = new GeoJsonParser(invalidFeatureCollectionNoGeometryTypeInFeature()); + assertNull(parser.getBoundingBox()); + assertEquals(2, parser.getFeatures().size()); + assertTrue(!parser.getFeatures().get(0).getGeometry().getType().equals("Polygon") && !parser + .getFeatures().get(1).getGeometry().getType().equals("Polygon")); + + // Contains 1 feature element with no geometry as it was missing a coordinates member + parser = new GeoJsonParser(invalidFeatureNoCoordinatesInGeometry()); + assertNull(parser.getBoundingBox()); + assertEquals(1, parser.getFeatures().size()); + assertNull(parser.getFeatures().get(0).getGeometry()); + } + + public void testInvalidGeometry() throws Exception { + GeoJsonParser parser; + + // No geometry due to no type member + parser = new GeoJsonParser(invalidGeometryNoType()); + assertNull(parser.getBoundingBox()); + assertEquals(0, parser.getFeatures().size()); + + // No geometry due to no coordinates member + parser = new GeoJsonParser(invalidGeometryNoCoordinates()); + assertNull(parser.getBoundingBox()); + assertEquals(0, parser.getFeatures().size()); + + // Geometry collection has 1 valid and 1 invalid geometry + parser = new GeoJsonParser(invalidGeometryCollectionInvalidGeometry()); + assertNull(parser.getBoundingBox()); + assertEquals(1, parser.getFeatures().size()); + assertEquals(1, ((GeoJsonGeometryCollection) parser.getFeatures().get(0).getGeometry()) + .getGeometries().size()); + + // No geometry due to invalid geometry collection + parser = new GeoJsonParser(invalidGeometryCollectionInvalidGeometries()); + assertNull(parser.getBoundingBox()); + assertEquals(0, parser.getFeatures().size()); + + // No geometry due to only lng provided + parser = new GeoJsonParser(invalidGeometryInvalidCoordinatesPair()); + assertEquals(0, parser.getFeatures().size()); + + // No geometry due to coordinates being strings instead of doubles + parser = new GeoJsonParser(invalidGeometryInvalidCoordinatesString()); + assertEquals(0, parser.getFeatures().size()); + } + + public JSONObject validGeometryCollection() throws Exception { + return new JSONObject( + "{\n" + + " \"type\": \"Feature\",\n" + + " \"id\": \"Popsicles\",\n" + + " \"geometry\": {\n" + + " \"type\": \"GeometryCollection\",\n" + + " \"geometries\": [\n" + + " { \"type\": \"GeometryCollection\",\n" + + " \"geometries\": [\n" + + " { \"type\": \"Point\",\n" + + " \"coordinates\": [103.0, 0.0]\n" + + " }\n" + + " ]\n" + + " }\n" + + " ]\n" + + " },\n" + + " \"properties\": {\n" + + " \"prop0\": \"value0\",\n" + + " \"prop1\": \"value1\"\n" + + " }\n" + + "}"); + } + + public JSONObject validPoint() throws JSONException { + return new JSONObject( + "{ \"type\": \"Point\", \"coordinates\": [100.0, 0.0] }" + ); + } + + public JSONObject validLineString() throws JSONException { + return new JSONObject( + "{ \"type\": \"LineString\",\n" + + " \"coordinates\": [ [100.0, 0.0], [101.0, 1.0] ]\n" + + " }" + ); + } + + public JSONObject validPolygon() throws JSONException { + return new JSONObject( + "{ \"type\": \"Polygon\",\n" + + " \"coordinates\": [\n" + + " [ [100.0, 0.0], [101.0, 0.0], [101.0, 1.0], [100.0, 1.0], [100.0, 0.0] ],\n" + + " [ [100.2, 0.2], [100.8, 0.2], [100.8, 0.8], [100.2, 0.8], [100.2, 0.2] ]\n" + + " ]\n" + + " }" + ); + } + + public JSONObject validMultiPoint() throws JSONException { + return new JSONObject( + "{ \"type\": \"MultiPoint\",\n" + + " \"coordinates\": [ [100.0, 0.0], [101.0, 1.0] ]\n" + + " }" + ); + } + + public JSONObject validMultiLineString() throws JSONException { + return new JSONObject( + "{ \"type\": \"MultiLineString\",\n" + + " \"coordinates\": [\n" + + " [ [100.0, 0.0], [101.0, 1.0] ],\n" + + " [ [102.0, 2.0], [103.0, 3.0] ]\n" + + " ]\n" + + " }" + ); + } + + public JSONObject validMultiPolygon() throws Exception { + return new JSONObject( + "{ \"type\": \"MultiPolygon\",\n" + + " \"coordinates\": [\n" + + " [[[102.0, 2.0], [103.0, 2.0], [103.0, 3.0], [102.0, 3.0], [102.0, 2.0]]],\n" + + " [[[100.0, 0.0], [101.0, 0.0], [101.0, 1.0], [100.0, 1.0], [100.0, 0.0]],\n" + + " [[100.2, 0.2], [100.8, 0.2], [100.8, 0.8], [100.2, 0.8], [100.2, 0.2]]]\n" + + " ]\n" + + " }" + ); + + } + + public JSONObject validEmptyFeatureCollection() throws Exception { + return new JSONObject( + "{ \"type\": \"FeatureCollection\",\n" + + " \"features\": [\n" + + " ]\n" + + "}"); + } + + public JSONObject emptyFile() { + return new JSONObject(); + } + + public JSONObject invalidGeometryNoType() throws Exception { + return new JSONObject( + "{\n" + + " \"coordinates\": [100.0, 0.0] \n" + + "}" + ); + } + + /** + * Geometry has coordinates member which is a single double instead of a pair of doubles + * + * @return geometry with invalid coordinates member + */ + public JSONObject invalidGeometryInvalidCoordinatesPair() throws Exception { + return new JSONObject("{ \"type\": \"Point\", \"coordinates\": [100.0] }"); + } + + /** + * Geometry has coordinates member which is a pair of strings instead of a pair of doubles + * + * @return geometry with invalid coordinates member + */ + public JSONObject invalidGeometryInvalidCoordinatesString() throws Exception { + return new JSONObject("{ \"type\": \"Point\", \"coordinates\": [\"BANANA\", \"BOAT\"] }"); + } + + /** + * Feature missing its geometry member, should be created with null geometry + * + * @return feature missing its geometry + */ + public JSONObject invalidFeatureNoGeometry() throws Exception { + return new JSONObject( + "{\n" + + " \"type\": \"Feature\",\n" + + " \"properties\": {\n" + + " \"name\": \"Dinagat Islands\"\n" + + " }\n" + + "}" + ); + } + + /** + * Geometry collection with a geometry missing the coordinates array member + * + * @return Geometry collection with invalid geometry + */ + public JSONObject invalidGeometryCollectionInvalidGeometry() throws Exception { + return new JSONObject( + "{ \"type\": \"GeometryCollection\",\n" + + " \"geometries\": [\n" + + " { \"type\": \"Point\",\n" + + " \"shark\": [100.0, 0.0]\n" + + " },\n" + + " { \"type\": \"LineString\",\n" + + " \"coordinates\": [ [101.0, 0.0], [102.0, 1.0] ]\n" + + " }\n" + + " ]\n" + + "}" + ); + } + + /** + * Geometry collection with a geometry that is missing the geometries array member + * + * @return Geometry collection with no geometries + */ + public JSONObject invalidGeometryCollectionInvalidGeometries() throws Exception { + return new JSONObject( + "{ \"type\": \"GeometryCollection\",\n" + + " \"doge\": [\n" + + " { \"type\": \"Point\",\n" + + " \"coordinates\": [100.0, 0.0]\n" + + " },\n" + + " { \"type\": \"LineString\",\n" + + " \"coordinates\": [ [101.0, 0.0], [102.0, 1.0] ]\n" + + " }\n" + + " ]\n" + + "}" + ); + } + + /** + * Feature containing a geometry collection with an geometry that is missing the coordinates + * member + * + * @return Feature containing a geometry collection with an invalid geometry + */ + public JSONObject invalidFeatureGeometryCollectionInvalidGeometry() throws Exception { + return new JSONObject( + "{\n" + + " \"type\":\"FeatureCollection\",\n" + + " \"features\":[\n" + + " {\n" + + " \"type\":\"Feature\",\n" + + " \"geometry\":{\n" + + " \"type\":\"GeometryCollection\",\n" + + " \"geometries\":[\n" + + " {\n" + + " \"type\":\"Point\",\n" + + " \"shark\":[\n" + + " 100.0,\n" + + " 0.0\n" + + " ]\n" + + " },\n" + + " {\n" + + " \"type\":\"LineString\",\n" + + " \"coordinates\":[\n" + + " [\n" + + " 101.0,\n" + + " 0.0\n" + + " ],\n" + + " [\n" + + " 102.0,\n" + + " 1.0\n" + + " ]\n" + + " ]\n" + + " }\n" + + " ]\n" + + " },\n" + + " \"properties\":{\n" + + " \"prop0\":\"value0\"\n" + + " }\n" + + " }\n" + + " ]\n" + + "}" + ); + } + + /** + * Feature collection with no geometries array member + * + * @return Feature collection with no geometries array + */ + public JSONObject invalidFeatureGeometryCollectionNoGeometries() throws Exception { + return new JSONObject( + "{\n" + + " \"type\":\"FeatureCollection\",\n" + + " \"features\":[\n" + + " {\n" + + " \"type\":\"Feature\",\n" + + " \"geometry\":{\n" + + " \"type\":\"GeometryCollection\",\n" + + " \"llamas\":[\n" + + " {\n" + + " \"type\":\"Point\",\n" + + " \"coordinates\":[\n" + + " 100.0,\n" + + " 0.0\n" + + " ]\n" + + " },\n" + + " {\n" + + " \"type\":\"LineString\",\n" + + " \"coordinates\":[\n" + + " [\n" + + " 101.0,\n" + + " 0.0\n" + + " ],\n" + + " [\n" + + " 102.0,\n" + + " 1.0\n" + + " ]\n" + + " ]\n" + + " }\n" + + " ]\n" + + " },\n" + + " \"properties\":{\n" + + " \"prop0\":\"value0\"\n" + + " }\n" + + " }\n" + + " ]\n" + + "}" + ); + } + + /** + * Feature missing its properties member, should be created with empty feature hashmap + * + * @return feature missing its properties + */ + public JSONObject invalidFeatureNoProperties() throws Exception { + return new JSONObject( + "{\n" + + " \"type\": \"Feature\",\n" + + " \"geometry\": {\n" + + " \"type\": \"Point\",\n" + + " \"coordinates\": [125.6, 10.1]\n" + + " }\n" + + "}" + ); + } + + /** + * 2 valid features with 1 invalid feature missing its type member indicating that it is a + * feature + * + * @return 2 valid features with 1 invalid feature + */ + public JSONObject invalidFeatureCollectionNoGeometryTypeInFeature() throws Exception { + return new JSONObject( + "{ \"type\": \"FeatureCollection\",\n" + + " \"features\": [\n" + + " { \"type\": \"Feature\",\n" + + " \"geometry\": {\"type\": \"Point\", \"coordinates\": [102.0, 0.5]},\n" + + " \"properties\": {\"prop0\": \"value0\"}\n" + + " },\n" + + " { \"type\": \"Feature\",\n" + + " \"geometry\": {\n" + + " \"type\": \"LineString\",\n" + + " \"coordinates\": [\n" + + " [102.0, 0.0], [103.0, 1.0], [104.0, 0.0], [105.0, 1.0]\n" + + " ]\n" + + " },\n" + + " \"properties\": {\n" + + " \"prop0\": \"value0\",\n" + + " \"prop1\": 0.0\n" + + " }\n" + + " },\n" + + " {\n" + + " \"geometry\": {\n" + + " \"type\": \"Polygon\",\n" + + " \"coordinates\": [\n" + + " [ [100.0, 0.0], [101.0, 0.0], [101.0, 1.0],\n" + + " [100.0, 1.0], [100.0, 0.0] ]\n" + + " ]\n" + + " },\n" + + " \"properties\": {\n" + + " \"prop0\": \"value0\",\n" + + " \"prop1\": {\"this\": \"that\"}\n" + + " }\n" + + " }\n" + + " ]\n" + + " }" + + ); + } + + /** + * FeatureCollection missing its feature array member + * + * @return FeatureCollection missing its feature array + */ + public JSONObject invalidFeatureCollectionNoFeaturesArray() throws JSONException { + return new JSONObject( + "{ \"type\": \"FeatureCollection\",\n" + + " \"INVALID\": [\n" + + " { \"type\": \"Feature\",\n" + + " \"geometry\": {\"type\": \"Point\", \"coordinates\": [102.0, 0.5]},\n" + + " \"properties\": {\"prop0\": \"value0\"}\n" + + " },\n" + + " { \"type\": \"Feature\",\n" + + " \"geometry\": {\n" + + " \"type\": \"LineString\",\n" + + " \"coordinates\": [\n" + + " [102.0, 0.0], [103.0, 1.0], [104.0, 0.0], [105.0, 1.0]\n" + + " ]\n" + + " },\n" + + " \"properties\": {\n" + + " \"prop0\": \"value0\",\n" + + " \"prop1\": 0.0\n" + + " }\n" + + " },\n" + + " { \"type\": \"Feature\",\n" + + " \"geometry\": {\n" + + " \"type\": \"Polygon\",\n" + + " \"coordinates\": [\n" + + " [ [100.0, 0.0], [101.0, 0.0], [101.0, 1.0],\n" + + " [100.0, 1.0], [100.0, 0.0] ]\n" + + " ]\n" + + " },\n" + + " \"properties\": {\n" + + " \"prop0\": \"value0\",\n" + + " \"prop1\": {\"this\": \"that\"}\n" + + " }\n" + + " }\n" + + " ]\n" + + " }" + ); + } + + /** + * Geometry missing its coordinates member + */ + public JSONObject invalidGeometryNoCoordinates() throws JSONException { + return new JSONObject( + "{ \"type\": \"LineString\",\n" + + " \"banana\": [ [100.0, 0.0], [101.0, 1.0] ]\n" + + " }" + ); + } + + /** + * Feature with geometry missing its coordinates member + * + * @return Feature with geometry missing its coordinates + */ + public JSONObject invalidFeatureNoCoordinatesInGeometry() throws JSONException { + return new JSONObject( + "{\n" + + " \"type\": \"Feature\",\n" + + " \"geometry\": {\n" + + " \"type\": \"Point\",\n" + + " \"mango\": [125.6, 10.1]\n" + + " },\n" + + " \"properties\": {\n" + + " \"name\": \"Dinagat Islands\"\n" + + " }\n" + + "}" + ); + } + + /** + * Feature missing its type member + * + * @return Feature missing its type + */ + public JSONObject invalidFeatureMissingType() throws JSONException { + return new JSONObject( + "{\n" + + " \"cow\": \"Feature\",\n" + + " \"geometry\": {\n" + + " \"type\": \"Point\",\n" + + " \"coordinates\": [125.6, 10.1]\n" + + " },\n" + + " \"properties\": {\n" + + " \"name\": \"Dinagat Islands\"\n" + + " }\n" + + "}" + ); + } + + /** + * Feature collection with a feature that contains a geometry missing its coordinates member + * + * @return Feature collection with feature missing its coordinates + */ + public JSONObject invalidFeatureCollectionNoCoordinatesInGeometryInFeature() throws Exception { + return new JSONObject( + "{ \"type\": \"FeatureCollection\",\n" + + " \"features\": [\n" + + " { \"type\": \"Feature\",\n" + + " \"geometry\": {\"type\": \"Point\", \"coordinates\": [102.0, 0.5]},\n" + + " \"properties\": {\"prop0\": \"value0\"}\n" + + " },\n" + + " { \"type\": \"Feature\",\n" + + " \"geometry\": {\n" + + " \"type\": \"LineString\",\n" + + " \"aardvark\": [\n" + + " [102.0, 0.0], [103.0, 1.0], [104.0, 0.0], [105.0, 1.0]\n" + + " ]\n" + + " },\n" + + " \"properties\": {\n" + + " \"prop0\": \"value0\",\n" + + " \"prop1\": 0.0\n" + + " }\n" + + " },\n" + + " { \"type\": \"Feature\",\n" + + " \"geometry\": {\n" + + " \"type\": \"Polygon\",\n" + + " \"coordinates\": [\n" + + " [ [100.0, 0.0], [101.0, 0.0], [101.0, 1.0],\n" + + " [100.0, 1.0], [100.0, 0.0] ]\n" + + " ]\n" + + " },\n" + + " \"properties\": {\n" + + " \"prop0\": \"value0\",\n" + + " \"prop1\": {\"this\": \"that\"}\n" + + " }\n" + + " }\n" + + " ]\n" + + " }" + ); + } + + /** + * Feature collection with a feature that has a geometry missing its type member + * + * @return Feature collection with a feature missing its type + */ + public JSONObject invalidFeatureCollectionNoTypeInGeometryInFeature() throws Exception { + return new JSONObject( + "{ \"type\": \"FeatureCollection\",\n" + + " \"features\": [\n" + + " { \"type\": \"Feature\",\n" + + " \"geometry\": {\"type\": \"Point\", \"coordinates\": [102.0, 0.5]},\n" + + " \"properties\": {\"prop0\": \"value0\"}\n" + + " },\n" + + " { \"type\": \"Feature\",\n" + + " \"geometry\": {\n" + + " \"type\": \"LineString\",\n" + + " \"coordinates\": [\n" + + " [102.0, 0.0], [103.0, 1.0], [104.0, 0.0], [105.0, 1.0]\n" + + " ]\n" + + " },\n" + + " \"properties\": {\n" + + " \"prop0\": \"value0\",\n" + + " \"prop1\": 0.0\n" + + " }\n" + + " },\n" + + " { \"type\": \"Feature\",\n" + + " \"geometry\": {\n" + + " \"crocodile\": \"Polygon\",\n" + + " \"coordinates\": [\n" + + " [ [100.0, 0.0], [101.0, 0.0], [101.0, 1.0],\n" + + " [100.0, 1.0], [100.0, 0.0] ]\n" + + " ]\n" + + " },\n" + + " \"properties\": {\n" + + " \"prop0\": \"value0\",\n" + + " \"prop1\": {\"this\": \"that\"}\n" + + " }\n" + + " }\n" + + " ]\n" + + " }" + ); + } +} diff --git a/library/tests/src/com/google/maps/android/geojson/GeoJsonPointStyleTest.java b/library/tests/src/com/google/maps/android/geojson/GeoJsonPointStyleTest.java new file mode 100644 index 000000000..082d12968 --- /dev/null +++ b/library/tests/src/com/google/maps/android/geojson/GeoJsonPointStyleTest.java @@ -0,0 +1,127 @@ +package com.google.maps.android.geojson; + +import com.google.android.gms.maps.MapsInitializer; +import com.google.android.gms.maps.model.BitmapDescriptor; +import com.google.android.gms.maps.model.BitmapDescriptorFactory; + +import android.test.AndroidTestCase; + +import java.util.Arrays; + +public class GeoJsonPointStyleTest extends AndroidTestCase { + + GeoJsonPointStyle pointStyle; + + public void setUp() throws Exception { + super.setUp(); + MapsInitializer.initialize(getContext()); + pointStyle = new GeoJsonPointStyle(); + } + + public void testGetGeometryType() throws Exception { + assertTrue(Arrays.asList(pointStyle.getGeometryType()).contains("Point")); + assertTrue(Arrays.asList(pointStyle.getGeometryType()).contains("MultiPoint")); + assertTrue(Arrays.asList(pointStyle.getGeometryType()).contains("GeometryCollection")); + assertEquals(3, pointStyle.getGeometryType().length); + } + + public void testAlpha() throws Exception { + pointStyle.setAlpha(0.1234f); + assertEquals(0.1234f, pointStyle.getAlpha()); + assertEquals(0.1234f, pointStyle.toMarkerOptions().getAlpha()); + } + + public void testAnchor() throws Exception { + pointStyle.setAnchor(0.23f, 0.87f); + assertEquals(0.23f, pointStyle.getAnchorU()); + assertEquals(0.87f, pointStyle.getAnchorV()); + assertEquals(0.23f, pointStyle.toMarkerOptions().getAnchorU()); + assertEquals(0.87f, pointStyle.toMarkerOptions().getAnchorV()); + } + + public void testDraggable() throws Exception { + pointStyle.setDraggable(true); + assertTrue(pointStyle.isDraggable()); + assertTrue(pointStyle.toMarkerOptions().isDraggable()); + } + + public void testFlat() throws Exception { + pointStyle.setFlat(true); + assertTrue(pointStyle.isFlat()); + assertTrue(pointStyle.toMarkerOptions().isFlat()); + } + + public void testIcon() throws Exception { + BitmapDescriptor icon = BitmapDescriptorFactory.defaultMarker(BitmapDescriptorFactory.HUE_GREEN); + pointStyle + .setIcon(icon); + assertEquals(icon, + pointStyle.getIcon()); + assertEquals(icon, + pointStyle.toMarkerOptions().getIcon()); + } + + public void testInfoWindowAnchor() throws Exception { + pointStyle.setInfoWindowAnchor(0.12f, 0.98f); + assertEquals(0.12f, pointStyle.getInfoWindowAnchorU()); + assertEquals(0.98f, pointStyle.getInfoWindowAnchorV()); + assertEquals(0.12f, pointStyle.toMarkerOptions().getInfoWindowAnchorU()); + assertEquals(0.98f, pointStyle.toMarkerOptions().getInfoWindowAnchorV()); + } + + public void testRotation() throws Exception { + pointStyle.setRotation(156.24f); + assertEquals(156.24f, pointStyle.getRotation()); + assertEquals(156.24f, pointStyle.toMarkerOptions().getRotation()); + } + + public void testSnippet() throws Exception { + pointStyle.setSnippet("The peaches are in a jar"); + assertEquals("The peaches are in a jar", pointStyle.getSnippet()); + assertEquals("The peaches are in a jar", pointStyle.toMarkerOptions().getSnippet()); + } + + public void testTitle() throws Exception { + pointStyle.setTitle("Peaches"); + assertEquals("Peaches", pointStyle.getTitle()); + assertEquals("Peaches", pointStyle.toMarkerOptions().getTitle()); + } + + public void testVisible() throws Exception { + pointStyle.setVisible(false); + assertFalse(pointStyle.isVisible()); + assertFalse(pointStyle.toMarkerOptions().isVisible()); + + } + + public void testDefaultPointStyle() throws Exception { + assertEquals(1.0f, pointStyle.getAlpha()); + assertEquals(0.5f, pointStyle.getAnchorU()); + assertEquals(1.0f, pointStyle.getAnchorV()); + assertFalse(pointStyle.isDraggable()); + assertFalse(pointStyle.isFlat()); + assertNull(pointStyle.getIcon()); + assertEquals(0.5f, pointStyle.getInfoWindowAnchorU()); + assertEquals(0.0f, pointStyle.getInfoWindowAnchorV()); + assertEquals(0.0f, pointStyle.getRotation()); + assertNull(pointStyle.getSnippet()); + assertNull(pointStyle.getTitle()); + assertTrue(pointStyle.isVisible()); + } + + public void testDefaultGetMarkerOptions() throws Exception { + assertEquals(1.0f, pointStyle.toMarkerOptions().getAlpha()); + assertEquals(0.5f, pointStyle.toMarkerOptions().getAnchorU()); + assertEquals(1.0f, pointStyle.toMarkerOptions().getAnchorV()); + assertFalse(pointStyle.toMarkerOptions().isDraggable()); + assertFalse(pointStyle.toMarkerOptions().isFlat()); + assertNull(pointStyle.toMarkerOptions().getIcon()); + assertEquals(0.5f, pointStyle.toMarkerOptions().getInfoWindowAnchorU()); + assertEquals(0.0f, pointStyle.toMarkerOptions().getInfoWindowAnchorV()); + assertEquals(0.0f, pointStyle.toMarkerOptions().getRotation()); + assertNull(pointStyle.toMarkerOptions().getSnippet()); + assertNull(pointStyle.toMarkerOptions().getTitle()); + assertTrue(pointStyle.toMarkerOptions().isVisible()); + } + +} \ No newline at end of file diff --git a/library/tests/src/com/google/maps/android/geojson/GeoJsonPointTest.java b/library/tests/src/com/google/maps/android/geojson/GeoJsonPointTest.java new file mode 100644 index 000000000..c09af3ee6 --- /dev/null +++ b/library/tests/src/com/google/maps/android/geojson/GeoJsonPointTest.java @@ -0,0 +1,26 @@ +package com.google.maps.android.geojson; + +import com.google.android.gms.maps.model.LatLng; + +import junit.framework.TestCase; + +public class GeoJsonPointTest extends TestCase { + + GeoJsonPoint p; + + public void testGetType() throws Exception { + p = new GeoJsonPoint(new LatLng(0, 0)); + assertEquals("Point", p.getType()); + } + + public void testGetCoordinates() throws Exception { + p = new GeoJsonPoint(new LatLng(0, 0)); + assertEquals(new LatLng(0, 0), p.getCoordinates()); + try { + p = new GeoJsonPoint(null); + fail(); + } catch (IllegalArgumentException e) { + assertEquals("Coordinate cannot be null", e.getMessage()); + } + } +} \ No newline at end of file diff --git a/library/tests/src/com/google/maps/android/geojson/GeoJsonPolygonStyleTest.java b/library/tests/src/com/google/maps/android/geojson/GeoJsonPolygonStyleTest.java new file mode 100644 index 000000000..58db823d1 --- /dev/null +++ b/library/tests/src/com/google/maps/android/geojson/GeoJsonPolygonStyleTest.java @@ -0,0 +1,95 @@ +package com.google.maps.android.geojson; + +import junit.framework.TestCase; + +import android.graphics.Color; + +import java.util.Arrays; + +public class GeoJsonPolygonStyleTest extends TestCase { + + GeoJsonPolygonStyle polygonStyle; + + public void setUp() throws Exception { + super.setUp(); + polygonStyle = new GeoJsonPolygonStyle(); + } + + public void testGetGeometryType() throws Exception { + assertTrue(Arrays.asList(polygonStyle.getGeometryType()).contains("Polygon")); + assertTrue(Arrays.asList(polygonStyle.getGeometryType()).contains("MultiPolygon")); + assertTrue(Arrays.asList(polygonStyle.getGeometryType()).contains("GeometryCollection")); + assertEquals(3, polygonStyle.getGeometryType().length); + } + + public void testFillColor() throws Exception { + polygonStyle.setFillColor(Color.BLACK); + assertEquals(Color.BLACK, polygonStyle.getFillColor()); + assertEquals(Color.BLACK, polygonStyle.toPolygonOptions().getFillColor()); + + polygonStyle.setFillColor(0xFFFFFF00); + assertEquals(0xFFFFFF00, polygonStyle.getFillColor()); + assertEquals(0xFFFFFF00, polygonStyle.toPolygonOptions().getFillColor()); + + polygonStyle.setFillColor(Color.parseColor("#FFFFFF")); + assertEquals(Color.parseColor("#FFFFFF"), polygonStyle.getFillColor()); + assertEquals(Color.parseColor("#FFFFFF"), polygonStyle.toPolygonOptions().getFillColor()); + } + + public void testGeodesic() throws Exception { + polygonStyle.setGeodesic(true); + assertTrue(polygonStyle.isGeodesic()); + assertTrue(polygonStyle.toPolygonOptions().isGeodesic()); + } + + public void testStrokeColor() throws Exception { + polygonStyle.setStrokeColor(Color.RED); + assertEquals(Color.RED, polygonStyle.getStrokeColor()); + assertEquals(Color.RED, polygonStyle.toPolygonOptions().getStrokeColor()); + + polygonStyle.setStrokeColor(0x01234567); + assertEquals(0x01234567, polygonStyle.getStrokeColor()); + assertEquals(0x01234567, polygonStyle.toPolygonOptions().getStrokeColor()); + + polygonStyle.setStrokeColor(Color.parseColor("#000000")); + assertEquals(Color.parseColor("#000000"), polygonStyle.getStrokeColor()); + assertEquals(Color.parseColor("#000000"), + polygonStyle.toPolygonOptions().getStrokeColor()); + } + + public void testStrokeWidth() throws Exception { + polygonStyle.setStrokeWidth(20.0f); + assertEquals(20.0f, polygonStyle.getStrokeWidth()); + assertEquals(20.0f, polygonStyle.toPolygonOptions().getStrokeWidth()); + } + + public void testVisible() throws Exception { + polygonStyle.setVisible(false); + assertFalse(polygonStyle.isVisible()); + assertFalse(polygonStyle.toPolygonOptions().isVisible()); + } + + public void testZIndex() throws Exception { + polygonStyle.setZIndex(3.4f); + assertEquals(3.4f, polygonStyle.getZIndex()); + assertEquals(3.4f, polygonStyle.toPolygonOptions().getZIndex()); + } + + public void testDefaultPolygonStyle() throws Exception { + assertEquals(Color.TRANSPARENT, polygonStyle.getFillColor()); + assertFalse(polygonStyle.isGeodesic()); + assertEquals(Color.BLACK, polygonStyle.getStrokeColor()); + assertEquals(10.0f, polygonStyle.getStrokeWidth()); + assertTrue(polygonStyle.isVisible()); + assertEquals(0.0f, polygonStyle.getZIndex()); + } + + public void testDefaultGetPolygonOptions() throws Exception { + assertEquals(Color.TRANSPARENT, polygonStyle.toPolygonOptions().getFillColor()); + assertFalse(polygonStyle.toPolygonOptions().isGeodesic()); + assertEquals(Color.BLACK, polygonStyle.toPolygonOptions().getStrokeColor()); + assertEquals(10.0f, polygonStyle.toPolygonOptions().getStrokeWidth()); + assertTrue(polygonStyle.isVisible()); + assertEquals(0.0f, polygonStyle.toPolygonOptions().getZIndex()); + } +} \ No newline at end of file diff --git a/library/tests/src/com/google/maps/android/geojson/GeoJsonPolygonTest.java b/library/tests/src/com/google/maps/android/geojson/GeoJsonPolygonTest.java new file mode 100644 index 000000000..c7fbefa16 --- /dev/null +++ b/library/tests/src/com/google/maps/android/geojson/GeoJsonPolygonTest.java @@ -0,0 +1,47 @@ +package com.google.maps.android.geojson; + +import com.google.android.gms.maps.model.LatLng; + +import junit.framework.TestCase; + +import java.util.ArrayList; +import java.util.Arrays; + +public class GeoJsonPolygonTest extends TestCase { + + GeoJsonPolygon p; + + public void testGetType() throws Exception { + ArrayList> coordinates = new ArrayList>(); + coordinates.add(new ArrayList( + Arrays.asList(new LatLng(0, 0), new LatLng(20, 20), new LatLng(60, 60), + new LatLng(0, 0)))); + p = new GeoJsonPolygon(coordinates); + assertEquals("Polygon", p.getType()); + } + + public void testGetCoordinates() throws Exception { + // No holes + ArrayList> coordinates = new ArrayList>(); + coordinates.add(new ArrayList( + Arrays.asList(new LatLng(0, 0), new LatLng(20, 20), new LatLng(60, 60), + new LatLng(0, 0)))); + p = new GeoJsonPolygon(coordinates); + assertEquals(coordinates, p.getCoordinates()); + + // Holes + coordinates.add(new ArrayList( + Arrays.asList(new LatLng(0, 0), new LatLng(20, 20), new LatLng(60, 60), + new LatLng(0, 0)))); + p = new GeoJsonPolygon(coordinates); + + + try { + p = new GeoJsonPolygon(null); + fail(); + } catch (IllegalArgumentException e) { + assertEquals("Coordinates cannot be null", e.getMessage()); + } + + } +} \ No newline at end of file diff --git a/library/tests/src/com/google/maps/android/geojson/GeoJsonRendererTest.java b/library/tests/src/com/google/maps/android/geojson/GeoJsonRendererTest.java new file mode 100644 index 000000000..2eaf61af1 --- /dev/null +++ b/library/tests/src/com/google/maps/android/geojson/GeoJsonRendererTest.java @@ -0,0 +1,39 @@ +package com.google.maps.android.geojson; + +import junit.framework.TestCase; + +public class GeoJsonRendererTest extends TestCase { + + public void setUp() throws Exception { + super.setUp(); + + } + + public void tearDown() throws Exception { + + } + + public void testGetMap() throws Exception { + + } + + public void testSetMap() throws Exception { + + } + + public void testGetFeatures() throws Exception { + + } + + public void testAddFeature() throws Exception { + + } + + public void testRemoveLayerFromMap() throws Exception { + + } + + public void testRemoveFeature() throws Exception { + + } +} \ No newline at end of file