androidgoogle-mapsoverlaygoogle-maps-api-2

Draw a path on maps following the finger motion path on the device screen


1)I want to draw a motion path on google map as per the follow of my finger touch points on the area of map. 2)and get the selected area from the map which lies inside the path.

Any one have an idea how to achieve it.

For reference want to do some thing similar:-

enter image description here


Solution

  • I have implemented the same for one of my Application hope that will help you, I have done this with the help of poly line and polygon.

    activity_main.xml
    
     <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:tools="http://schemas.android.com/tools"
        android:layout_width="match_parent"
        android:layout_height="match_parent" >
    
        <RelativeLayout
            android:layout_width="match_parent"
            android:layout_height="match_parent" >
    
            <fragment
                xmlns:android="http://schemas.android.com/apk/res/android"
                android:id="@+id/map"
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                class="com.google.android.gms.maps.SupportMapFragment" />
    
            <View
                android:id="@+id/drawer_view"
                android:layout_width="wrap_content"
                android:layout_height="match_parent" />
    
            <Button
                android:id="@+id/draw_button"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:onClick="drawZone"
                android:padding="10dp"
                android:text="Draw" />
        </RelativeLayout>
    
    </RelativeLayout>
    

    The below class will cover the full code to draw custom region in Google map v2

    MainActivity.java
    
        import java.util.ArrayList;
        import android.graphics.Color;
        import android.graphics.Point;
        import android.os.Bundle;
        import android.support.v4.app.FragmentActivity;
        import android.util.Log;
        import android.view.GestureDetector;
        import android.view.GestureDetector.SimpleOnGestureListener;
        import android.view.MotionEvent;
        import android.view.View;
        import android.view.View.OnTouchListener;
        import android.widget.Toast;
    
        import com.google.android.gms.common.ConnectionResult;
        import com.google.android.gms.common.GooglePlayServicesUtil;
        import com.google.android.gms.maps.GoogleMap;
        import com.google.android.gms.maps.SupportMapFragment;
        import com.google.android.gms.maps.model.LatLng;
        import com.google.android.gms.maps.model.PolygonOptions;
        import com.google.android.gms.maps.model.PolylineOptions;
    
        public class MainActivity extends FragmentActivity implements OnTouchListener {
    
            private static final String TAG = "polygon";
            private GoogleMap mGoogleMap;
            private View mMapShelterView;
            private GestureDetector mGestureDetector;
            private ArrayList<LatLng> mLatlngs = new ArrayList<LatLng>();
            private PolylineOptions mPolylineOptions;
            private PolygonOptions mPolygonOptions;
            // flag to differentiate whether user is touching to draw or not
            private boolean mDrawFinished = false;
    
            @Override
            protected void onCreate(Bundle savedInstanceState) {
                super.onCreate(savedInstanceState);
                setContentView(R.layout.activity_main);
                mMapShelterView = (View) findViewById(R.id.drawer_view);
                mGestureDetector = new GestureDetector(this, new GestureListener());
                mMapShelterView.setOnTouchListener(this);
                initilizeMap();
            }
    
            private final class GestureListener extends SimpleOnGestureListener {
                @Override
                public boolean onDown(MotionEvent e) {
                    return true;
                }
    
                @Override
                public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX,
                        float velocityY) {
                    return false;
                }
            }
    
            /**
             * Ontouch event will draw poly line along the touch points
             * 
             */
            @Override
            public boolean onTouch(View v, MotionEvent event) {
                int X1 = (int) event.getX();
                int Y1 = (int) event.getY();
                Point point = new Point();
                point.x = X1;
                point.y = Y1;
                LatLng firstGeoPoint = mGoogleMap.getProjection().fromScreenLocation(
                        point);
                switch (event.getAction()) {
    
                case MotionEvent.ACTION_DOWN:
                    break;
    
                case MotionEvent.ACTION_MOVE:
                    if (mDrawFinished) {
                        X1 = (int) event.getX();
                        Y1 = (int) event.getY();
                        point = new Point();
                        point.x = X1;
                        point.y = Y1;
                        LatLng geoPoint = mGoogleMap.getProjection()
                                .fromScreenLocation(point);
                        mLatlngs.add(geoPoint);
                        mPolylineOptions = new PolylineOptions();
                        mPolylineOptions.color(Color.RED);
                        mPolylineOptions.width(3);
                        mPolylineOptions.addAll(mLatlngs);
                        mGoogleMap.addPolyline(mPolylineOptions);
                    }
                    break;
                case MotionEvent.ACTION_UP:
                    Log.d(TAG, "Poinnts array size " + mLatlngs.size());
                    mLatlngs.add(firstGeoPoint);
                    mGoogleMap.clear();
                    mPolylineOptions = null;
                    mMapShelterView.setVisibility(View.GONE);
                    mGoogleMap.getUiSettings().setZoomGesturesEnabled(true);
                    mGoogleMap.getUiSettings().setAllGesturesEnabled(true);
                    mPolygonOptions = new PolygonOptions();
                    mPolygonOptions.fillColor(Color.GRAY);
                    mPolygonOptions.strokeColor(Color.RED);
                    mPolygonOptions.strokeWidth(5);
                    mPolygonOptions.addAll(mLatlngs);
                    mGoogleMap.addPolygon(mPolygonOptions);
                    mDrawFinished = false;
                    break;
                }
                return mGestureDetector.onTouchEvent(event);
            }
    
            /**
             * Setting up map
             * 
             */
    
            private void initilizeMap() {
                int status = GooglePlayServicesUtil
                        .isGooglePlayServicesAvailable(getApplicationContext());
                if (status == ConnectionResult.SUCCESS) {
                    if (mGoogleMap == null) {
                        mGoogleMap = ((SupportMapFragment) getSupportFragmentManager()
                                .findFragmentById(R.id.map)).getMap();
                        mGoogleMap.setMyLocationEnabled(true);
    
                    }
    
                } else if (GooglePlayServicesUtil.isUserRecoverableError(status)) {
                    // showErrorDialog(status);
                } else {
                    Toast.makeText(this, "No Support for Google Play Service",
                            Toast.LENGTH_LONG).show();
                }
            }
    
            /**
             * Method gets called on tap of draw button, It prepares the screen to draw
             * the polygon
             * 
             * @param view
             */
    
            public void drawZone(View view) {
                mGoogleMap.clear();
                mLatlngs.clear();
                mPolylineOptions = null;
                mPolygonOptions = null;
                mDrawFinished = true;
                mMapShelterView.setVisibility(View.VISIBLE);
                mGoogleMap.getUiSettings().setScrollGesturesEnabled(false);
            }
    
        }
    

    Hopefully the above code is pretty enough to draw custom region in map v2. For detecting whether the particular point is inside the custom region or not we can use the below snippet,

    public synchronized boolean Contains(Location location) {
            boolean isInside = false;
            if (mLatlngs.size() > 0) {
                LatLng lastPoint = mLatlngs.get(mLatlngs.size() - 1);
    
                double x = location.getLongitude();
    
                for (LatLng point : mLatlngs) {
                    double x1 = lastPoint.longitude;
                    double x2 = point.longitude;
                    double dx = x2 - x1;
    
                    if (Math.abs(dx) > 180.0) {
                        if (x > 0) {
                            while (x1 < 0)
                                x1 += 360;
                            while (x2 < 0)
                                x2 += 360;
                        } else {
                            while (x1 > 0)
                                x1 -= 360;
                            while (x2 > 0)
                                x2 -= 360;
                        }
                        dx = x2 - x1;
                    }
    
                    if ((x1 <= x && x2 > x) || (x1 >= x && x2 < x)) {
                        double grad = (point.latitude - lastPoint.latitude) / dx;
                        double intersectAtLat = lastPoint.latitude
                                + ((x - x1) * grad);
    
                        if (intersectAtLat > location.getLatitude())
                            isInside = !isInside;
                    }
                    lastPoint = point;
                }
            }
    
            return isInside;
        }
    

    You can pass the location parameter to the method, it will return that whether the location is inside the custom region or not.

    Manifest.xml

    <?xml version="1.0" encoding="utf-8"?>
    <manifest xmlns:android="http://schemas.android.com/apk/res/android"
        package="com.testdraw"
        android:versionCode="1"
        android:versionName="1.0" >
    
        <uses-sdk
            android:minSdkVersion="8"
            android:targetSdkVersion="19" />
    
        <permission
            android:name=".permission.MAPS_RECEIVE"
            android:protectionLevel="signature" />
    
        <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
        <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
        <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
        <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
        <uses-permission android:name="android.permission.INTERNET" />
        <uses-permission android:name="in.wptrafficanalyzer.locationingooglemapv2.permission.MAPS_RECEIVE" />
    
        <application
            android:allowBackup="true"
            android:icon="@drawable/ic_launcher"
            android:label="@string/app_name"
            android:theme="@style/AppTheme" >
            <activity
                android:name=".MainActivity"
                android:label="@string/app_name" >
                <intent-filter>
                    <action android:name="android.intent.action.MAIN" />
    
                    <category android:name="android.intent.category.LAUNCHER" />
                </intent-filter>
            </activity>
    
            <meta-data
                android:name="com.google.android.maps.v2.API_KEY"
                android:value="AIzaSyDkYvXC1pmSiBrt5Ja3F6gk-wBwIMuDNwo" />
            <meta-data
                android:name="com.google.android.gms.version"
                android:value="@integer/google_play_services_version" />
        </application>
    
        <uses-feature
            android:glEsVersion="0x00020000"
            android:required="true" />
    
    </manifest>