eu.iescities.pilot.rovereto.roveretoexplorer.map.MapManager.java Source code

Java tutorial

Introduction

Here is the source code for eu.iescities.pilot.rovereto.roveretoexplorer.map.MapManager.java

Source

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

import java.util.ArrayList;
import java.util.Collection;
import java.util.ConcurrentModificationException;
import java.util.List;

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Paint.Align;
import android.graphics.Rect;
import android.location.Location;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentTransaction;
import android.util.Log;
import android.util.SparseArray;

import com.google.android.gms.maps.CameraUpdateFactory;
import com.google.android.gms.maps.GoogleMap;
import com.google.android.gms.maps.model.BitmapDescriptor;
import com.google.android.gms.maps.model.BitmapDescriptorFactory;
import com.google.android.gms.maps.model.LatLng;
import com.google.android.gms.maps.model.LatLngBounds;
import com.google.android.gms.maps.model.Marker;
import com.google.android.gms.maps.model.MarkerOptions;
import com.google.android.gms.maps.model.Polyline;
import com.google.android.gms.maps.model.PolylineOptions;
import com.google.android.maps.GeoPoint;
import com.google.android.maps.MapView;

import eu.iescities.pilot.rovereto.roveretoexplorer.R;
import eu.iescities.pilot.rovereto.roveretoexplorer.custom.CategoryHelper;
import eu.iescities.pilot.rovereto.roveretoexplorer.custom.DTParamsHelper;
import eu.iescities.pilot.rovereto.roveretoexplorer.custom.data.DTHelper;
import eu.iescities.pilot.rovereto.roveretoexplorer.custom.data.model.BaseDTObject;

public class MapManager {

    private static MapView mapView;
    private static List<Marker> myMarkers = null;
    public static int ZOOM_DEFAULT = 15;
    public static LatLng DEFAULT_POINT = new LatLng(45.89096, 11.04014); // Rovereto

    public static void initWithParam() {
        int zoom = DTParamsHelper.getZoomLevelMap();
        if (zoom != 0) {
            ZOOM_DEFAULT = zoom;
        }

        List<Double> centerMap = DTParamsHelper.getCenterMap();
        if (centerMap != null) {
            Double latitute = centerMap.get(0);
            Double longitude = centerMap.get(1);
            DEFAULT_POINT = new LatLng(latitute, longitude);
        }
    }

    public static MapView getMapView() {
        return mapView;
    }

    public static void setMapView(MapView mapView) {
        MapManager.mapView = mapView;
        MapManager.mapView.setClickable(true);
        MapManager.mapView.setBuiltInZoomControls(true);
    }

    public static GeoPoint requestMyLocation(Context ctx) {
        return DTHelper.getLocationHelper().getLocation();
    }

    public static void fitMapWithOverlays(Collection<? extends BaseDTObject> objects, GoogleMap map) {
        double[] llrr = null;
        if (objects != null && !objects.isEmpty()) {
            for (BaseDTObject o : objects) {

                llrr = fit(llrr, o.getLocation());

            }
        }
        if (llrr != null) {
            fit(map, new double[] { llrr[0], llrr[1] }, new double[] { llrr[2], llrr[3] },
                    objects != null && objects.size() > 1);
        } else {
            fit(map, null, null, objects != null && objects.size() > 1);
        }
    }

    /**
     * @param llrr
     * @param location
     * @return
     */
    private static double[] fit(double[] llrr, double[] location) {
        if (llrr == null) {
            llrr = new double[4];
            llrr[0] = location[0];
            llrr[1] = location[1];
            llrr[2] = location[0];
            llrr[3] = location[1];
        } else {
            llrr[0] = Math.min(llrr[0], location[0]);
            llrr[1] = Math.max(llrr[1], location[1]);

            llrr[2] = Math.max(llrr[2], location[0]);
            llrr[3] = Math.min(llrr[3], location[1]);
        }
        return llrr;
    }

    private static void fit(GoogleMap map, double[] ll, double[] rr, boolean zoomIn) {
        if (ll != null && rr != null) {
            LatLngBounds bounds = LatLngBounds.builder().include(new LatLng(rr[0], rr[1]))
                    .include(new LatLng(ll[0], ll[1])).build();
            map.animateCamera(CameraUpdateFactory.newLatLngBounds(bounds, 64));
        }
    }

    // public static MarkerOptions createStoryStepMarker(Context ctx,
    // BaseDTObject obj, int pos, boolean selected) {
    // LatLng latLng = getLatLngFromBasicObject(obj);
    //
    // int markerIcon = selected ? R.drawable.selected_step : R.drawable.step;
    //
    // BitmapDescriptor bd =
    // BitmapDescriptorFactory.fromBitmap(writeOnStoryMarker(ctx, markerIcon,
    // Integer.toString(pos)));
    // MarkerOptions marker = new MarkerOptions().anchor(0.5f,
    // 0.5f).position(latLng).icon(bd).title("" + pos);
    // return marker;
    // }
    //
    // public static PolylineOptions createStoryStepLine(Context ctx,
    // BaseDTObject from, BaseDTObject to) {
    // LatLng latLngFrom = getLatLngFromBasicObject(from);
    // LatLng latLngTo = getLatLngFromBasicObject(to);
    // PolylineOptions line = new PolylineOptions().add(latLngFrom, latLngTo)
    // .color(Color.parseColor(ctx.getString(R.color.dtappcolor))).width(6);
    // return line;
    // }

    /*
     * CLUSTERING
     */
    public static class ClusteringHelper {
        private static final String TAG = "MapManager.ClusteringHelper";

        private static final int DENSITY_X = 5;
        private static final int DENSITY_Y = 5;

        private static List<List<List<BaseDTObject>>> grid = new ArrayList<List<List<BaseDTObject>>>();
        private static SparseArray<int[]> item2group = new SparseArray<int[]>();

        public synchronized static <T extends BaseDTObject> List<MarkerOptions> cluster(Context mContext,
                GoogleMap map, Collection<T> objects) {
            item2group.clear();
            // 2D array with some configurable, fixed density
            grid.clear();

            for (int i = 0; i <= DENSITY_X; i++) {
                ArrayList<List<BaseDTObject>> column = new ArrayList<List<BaseDTObject>>(DENSITY_Y + 1);
                for (int j = 0; j <= DENSITY_Y; j++) {
                    column.add(new ArrayList<BaseDTObject>());
                }
                grid.add(column);
            }

            LatLng lu = map.getProjection().getVisibleRegion().farLeft;
            LatLng rd = map.getProjection().getVisibleRegion().nearRight;
            int step = (int) (Math.abs((lu.longitude * 1E6) - (rd.longitude * 1E6)) / DENSITY_X);

            // compute leftmost bound of the affected grid:
            // this is the bound of the leftmost grid cell that intersects
            // with the visible part
            int startX = (int) ((lu.longitude * 1E6) - ((lu.longitude * 1E6) % step));
            if (lu.longitude < 0) {
                startX -= step;
            }
            // compute bottom bound of the affected grid
            int startY = (int) ((rd.latitude * 1E6) - ((rd.latitude * 1E6) % step));
            if (lu.latitude < 0) {
                startY -= step;
            }
            int endX = startX + (DENSITY_X + 1) * step;
            int endY = startY + (DENSITY_Y + 1) * step;

            int idx = 0;
            try {
                for (BaseDTObject basicObject : objects) {
                    LatLng objLatLng = getLatLngFromBasicObject(basicObject);

                    if (objLatLng != null && (objLatLng.longitude * 1E6) >= startX
                            && (objLatLng.longitude * 1E6) <= endX && (objLatLng.latitude * 1E6) >= startY
                            && (objLatLng.latitude * 1E6) <= endY) {
                        int binX = (int) (Math.abs((objLatLng.longitude * 1E6) - startX) / step);
                        int binY = (int) (Math.abs((objLatLng.latitude * 1E6) - startY) / step);

                        item2group.put(idx, new int[] { binX, binY });
                        // just push the reference
                        grid.get(binX).get(binY).add(basicObject);
                    }
                    idx++;
                }
            } catch (ConcurrentModificationException ex) {
                Log.e(TAG, ex.toString());
            }

            // if (mapView.getZoomLevel() == mapView.getMaxZoomLevel()) {
            if (map.getCameraPosition().zoom == map.getMaxZoomLevel()) {
                for (int i = 0; i < grid.size(); i++) {
                    for (int j = 0; j < grid.get(0).size(); j++) {
                        List<BaseDTObject> curr = grid.get(i).get(j);
                        if (curr.size() == 0)
                            continue;

                        if (i > 0) {
                            if (checkDistanceAndMerge(i - 1, j, curr))
                                continue;
                        }
                        if (j > 0) {
                            if (checkDistanceAndMerge(i, j - 1, curr))
                                continue;
                        }
                        if (i > 0 && j > 0) {
                            if (checkDistanceAndMerge(i - 1, j - 1, curr))
                                continue;
                        }
                    }
                }
            }

            // generate markers
            List<MarkerOptions> markers = new ArrayList<MarkerOptions>();

            for (int i = 0; i < grid.size(); i++) {
                for (int j = 0; j < grid.get(i).size(); j++) {
                    List<BaseDTObject> markerList = grid.get(i).get(j);
                    if (markerList.size() > 1) {
                        markers.add(createGroupMarker(mContext, map, markerList, i, j));
                    } else if (markerList.size() == 1) {
                        // draw single marker
                        markers.add(createSingleMarker(markerList.get(0), i, j));
                    }
                }
            }

            return markers;
        }

        public static void clearGrid() {
            grid.clear();
        }

        /**
         * Render markers on the map
         * 
         * @param map
         * @param markers
         */
        public static void render(GoogleMap map, List<MarkerOptions> markers) {
            if (myMarkers == null)
                myMarkers = new ArrayList<Marker>();
            else
                myMarkers.clear();
            for (MarkerOptions mo : markers) {
                myMarkers.add(map.addMarker(mo));

            }
        }

        /**
         * Render clustered object markers
         * 
         * @param map
         * @param markers
         * @param objects
         */
        public static void render(Context ctx, GoogleMap map, List<MarkerOptions> markers,
                Collection<? extends BaseDTObject> objects) {
            if (myMarkers == null)
                myMarkers = new ArrayList<Marker>();
            for (MarkerOptions mo : markers) {
                myMarkers.add(map.addMarker(mo));
                ;
            }

        }

        public static void removeAllMarkers() {
            if (myMarkers != null && myMarkers.size() > 0)
                for (Marker marker : myMarkers)
                    marker.remove();
        }

        private static MarkerOptions createSingleMarker(BaseDTObject item, int x, int y) {
            LatLng latLng = getLatLngFromBasicObject(item);

            int markerIcon = CategoryHelper.getMapIconByType(item.getType());
            // if (CategoryHelper.FAMILY_CATEGORY_POI.equals(item.getType())
            // || (CategoryHelper.FAMILY_CATEGORY_EVENT.equals(item.getType())))
            // markerIcon = objectCertified(item);

            MarkerOptions marker = new MarkerOptions().position(latLng)
                    .icon(BitmapDescriptorFactory.fromResource(markerIcon)).title(x + ":" + y);
            return marker;
        }

        private static MarkerOptions createGroupMarker(Context mContext, GoogleMap map,
                List<BaseDTObject> markerList, int x, int y) {
            BaseDTObject item = markerList.get(0);
            LatLng latLng = getLatLngFromBasicObject(item);

            int markerIcon = R.drawable.ic_marker_p_generic;

            BitmapDescriptor bd = BitmapDescriptorFactory
                    .fromBitmap(writeOnMarker(mContext, markerIcon, Integer.toString(markerList.size())));
            MarkerOptions marker = new MarkerOptions().position(latLng).icon(bd).title(x + ":" + y);
            return marker;
        }

        public static List<BaseDTObject> getFromGridId(String id) {
            try {
                String[] parsed = id.split(":");
                int x = Integer.parseInt(parsed[0]);
                int y = Integer.parseInt(parsed[1]);

                return grid.get(x).get(y);
            } catch (Exception e) {
                return null;
            }
        }

        private static boolean checkDistanceAndMerge(int i, int j, List<BaseDTObject> curr) {
            List<BaseDTObject> src = grid.get(i).get(j);
            if (src.size() == 0) {
                return false;
            }

            LatLng srcLatLng = getLatLngFromBasicObject(src.get(0));
            LatLng currLatLng = getLatLngFromBasicObject(curr.get(0));

            if (srcLatLng != null && currLatLng != null) {
                float[] dist = new float[3];

                Location.distanceBetween(srcLatLng.latitude, srcLatLng.longitude, currLatLng.latitude,
                        currLatLng.longitude, dist);

                if (dist[0] < 20) {
                    src.addAll(curr);
                    curr.clear();
                    return true;
                }
            }
            return false;
        }

    }

    public static void switchToMapView(ArrayList<BaseDTObject> list, Fragment src) {
        FragmentTransaction fragmentTransaction = src.getActivity().getSupportFragmentManager().beginTransaction();
        MapFragment fragment = new MapFragment();
        Bundle args = new Bundle();
        args.putSerializable(MapFragment.ARG_OBJECTS, list);
        fragment.setArguments(args);
        fragmentTransaction.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_FADE);
        // fragmentTransaction.detach(src);
        fragmentTransaction.replace(R.id.content_frame, fragment, src.getTag());
        fragmentTransaction.addToBackStack(fragment.getTag());
        fragmentTransaction.commit();

    }

    public static void switchToMapView(String category, String argType, Fragment src) {
        FragmentTransaction fragmentTransaction = src.getActivity().getSupportFragmentManager().beginTransaction();
        MapFragment fragment = new MapFragment();
        Bundle args = new Bundle();
        args.putString(argType, category);
        fragment.setArguments(args);
        fragmentTransaction.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_FADE);
        // fragmentTransaction.detach(src);
        fragmentTransaction.replace(R.id.content_frame, fragment, src.getTag());
        fragmentTransaction.addToBackStack(fragment.getTag());
        fragmentTransaction.commit();

    }

    // private static int objectCertified(BaseDTObject o) {
    // if (o.getCustomData() != null) {
    // if ((o instanceof LocalEventObject) && ((Boolean)
    // o.getCustomData().get("certified"))) {
    // /* se ceretificato e evento */
    // return R.drawable.ic_marker_e_family_certified;
    // }
    //
    // /* se certificato e poi */
    // String status = (String) o.getCustomData().get("status");
    // if ((o instanceof POIObject)
    // && (("Certificato finale").equals(status) ||
    // ("Certificato base").equals(status))) {
    // return R.drawable.ic_marker_p_family_certified;
    // }
    // }
    //
    // return CategoryHelper.getMapIconByType(o.getType());
    // }

    private static Bitmap writeOnMarker(Context mContext, int drawableId, String text) {
        float scale = mContext.getResources().getDisplayMetrics().density;

        Bitmap bitmap = BitmapFactory.decodeResource(mContext.getResources(), drawableId)
                .copy(Bitmap.Config.ARGB_8888, true);

        Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
        paint.setTextAlign(Align.CENTER);
        paint.setTextSize(scale * 14);
        paint.setAntiAlias(true);
        paint.setARGB(255, 255, 255, 255);

        Canvas canvas = new Canvas(bitmap);
        Rect bounds = new Rect();
        paint.getTextBounds(text, 0, text.length(), bounds);
        float x = bitmap.getWidth() / 2;
        float y = bitmap.getHeight() / 2;
        canvas.drawText(text, x, y, paint);

        return bitmap;
    }

    private static Bitmap writeOnStoryMarker(Context mContext, int drawableId, String text) {
        float scale = mContext.getResources().getDisplayMetrics().density;

        Bitmap bitmap = BitmapFactory.decodeResource(mContext.getResources(), drawableId)
                .copy(Bitmap.Config.ARGB_8888, true);
        Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
        paint.setTextAlign(Align.CENTER);
        paint.setTextSize(scale * 14);
        paint.setAntiAlias(true);
        paint.setARGB(255, 255, 255, 255);

        Canvas canvas = new Canvas(bitmap);
        Rect bounds = new Rect();
        paint.getTextBounds(text, 0, text.length(), bounds);
        float x = bitmap.getWidth() / 2;
        float y = bitmap.getHeight() / 2 - ((paint.descent() + paint.ascent()) / 2);

        canvas.drawText(text, x, y, paint);

        return bitmap;
    }

    private static LatLng getLatLngFromBasicObject(BaseDTObject object) {
        LatLng latLng = new LatLng(object.getLocation()[0], object.getLocation()[1]);
        return latLng;
    }

    private static boolean draw(GoogleMap map, List<List<LatLng>> legsPoints, Context ctx) {
        for (int i = 0; i < legsPoints.size(); i++) {
            // default
            int color = ctx.getResources().getColor(R.color.path);
            List<LatLng> legPoints = legsPoints.get(i);
            drawPath(map, legPoints, color);
        }
        return true;
    }

    private static void drawPath(GoogleMap map, List<LatLng> points, int color) {
        // int x1 = -1, y1 = -1, x2 = -1, y2 = -1;
        Paint paint = new Paint();
        paint.setColor(color);
        paint.setStyle(Paint.Style.FILL_AND_STROKE);
        paint.setStrokeWidth(6);

        PolylineOptions po = new PolylineOptions().addAll(points).width(6).color(color);
        Polyline pl = map.addPolyline(po);
        pl.setVisible(true);
    }

}