1. 程式人生 > >Android 百度地圖 動態畫多邊形,並判斷一個點是否在多邊形內部

Android 百度地圖 動態畫多邊形,並判斷一個點是否在多邊形內部

由於專案的需求,需要動態的在地圖上畫出多邊形,並且需要判斷一個點是否在多邊形的範圍內,根據官方的demo,結合網上的查的資料,做出的效果如下圖所示:

這裡寫圖片描述 這裡寫圖片描述
這裡寫圖片描述

思路就是:

1.點選地圖增加marker;
2.拿到marker,根據marker來畫線(判斷點的個數,大於 1 時);
3.點選marker可以進行刪除,長按可以進行拖拽操作;
4.當點選確定時,清除線,把多邊形畫出來(當點大於 2 時);
5.在地圖上點選一點,並判斷該點是否在多邊形區域內

第一步:初始化地圖,並增加監聽事件

  • 宣告和初始化需要用到的變數
    //marker 相關
    private
Marker marker; List<Marker> markers = new ArrayList<>(); //算是map的索引,通過此id 來按順序取出座標點 private List<String> ids = new ArrayList<>(); //用來儲存座標點 private Map<String, LatLng> latlngs = new HashMap<>(); private InfoWindow mInfoWindow; //線 private
Polyline mPolyline; //多邊形 private Polygon polygon; //private List<Polygon> polygons = new ArrayList<>(); private double latitude; private double longitude; //是座標點的多少,用來判斷是畫線,還是畫多邊形 private int size; //根據別名來儲存畫好的多邊形 private Map<String, Polygon> polygonMap = new
HashMap<>(); //多邊形的別名 private List<String> aliasname = new ArrayList<>(); // private boolean polygonContainsPoint; //用來儲存一個點所在的所有的區域 List<String> areas = new ArrayList<>();
        map = (MapView) findViewById(R.id.map);
        baidumap = map.getMap();
        //給marker設定點選事件,用來刪除marker
        baidumap.setOnMarkerClickListener(this);
        //給map設定監聽事件,用來拿到點選地圖的點的座標
        baidumap.setOnMapClickListener(this);
        //給marker設定拖拽監聽事件,用來獲取拖拽完成後的座標
        baidumap.setOnMarkerDragListener(this);
  • 點選地圖的監聽事件:
    /**
     * 通過點選地圖,來獲取座標
     *
     * @param latLng
     */
    @Override
    public void onMapClick(LatLng latLng) {
        Toast.makeText(this, "座標是:" + latLng.latitude + ",,," + latLng.longitude, Toast.LENGTH_SHORT).show();
        Log.e("aaa", "ditu d zuobiao is -->" + latLng.latitude + ",,," + latLng.longitude);
        //拿到座標,方便以後查詢
        latitude = latLng.latitude;
        longitude = latLng.longitude;
        //向地圖新增marker
        addMarler(latitude, longitude);
        if (ids.size() >= 2) {
            drawLine();
        }
    }
  • 地圖上marker的點選事件
    /**
     * 用來刪除marker
     * @param marker
     * @return
     */
    @Override
    public boolean onMarkerClick(final Marker marker) {
        Button button = new Button(getApplicationContext());
        button.setBackgroundResource(R.drawable.popup);
        button.setText("刪除");
        button.setTextColor(Color.BLACK);
        //button.setWidth(300);
        button.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                marker.remove();
                String id1 = marker.getId();
                ids.remove(id1);
                latlngs.remove(id1);
                Log.e("aaa", "刪除後map的size--》" + latlngs.size());
                baidumap.hideInfoWindow();
                if (ids.size() < 2) {
                    if (mPolyline != null) {
                        mPolyline.remove();
                    }
                    return;
                }
                drawLine();
            }
        });
        LatLng ll = marker.getPosition();
        mInfoWindow = new InfoWindow(button, ll, -50);
        baidumap.showInfoWindow(mInfoWindow);
        return true;
    }
  • 地圖上marker的拖拽的監聽事件
    @Override
    public void onMarkerDragEnd(Marker marker) {
        String id = marker.getId();
        Log.e("aaa", "id-->" + id);
        double latitude1 = marker.getPosition().latitude;
        double longitude1 = marker.getPosition().longitude;
        //當拖拽完成後,需要把原來儲存的座標給替換掉
        latlngs.remove(id);
        latlngs.put(id, new LatLng(latitude1, longitude1));
        Toast.makeText(Main2Activity.this, "拖拽結束,新位置:" + latitude1 + ", " + longitude1, Toast.LENGTH_LONG).show();

        Log.e("aaa", ids.size() + "---拖拽結束後map 的 " + latlngs.size());
       /* for (int i = 0; i < ids.size(); i++) {
            String s = ids.get(i);
            Log.e("aaa", "key= " + s + " and value= " + latlngs.get(s).toString());
        }*/
        //當拖拽完成後,重新畫線
        drawLine();
    }

    @Override
    public boolean onMapPoiClick(MapPoi mapPoi) {
        return false;
    }

    @Override
    public void onMarkerDrag(Marker marker) {

    }
  • 向地圖上增加marker的程式碼如下:
 /**
     * 根據座標來新增marker
     *
     * @param latitude
     * @param longitude
     */
    private void addMarler(double latitude, double longitude) {
        //定義Maker座標點
        LatLng point = new LatLng(latitude, longitude);
        //構建Marker圖示
        BitmapDescriptor bitmap = BitmapDescriptorFactory
                .fromResource(R.drawable.point);
        //構建MarkerOption,用於在地圖上新增Marker
        OverlayOptions option = new MarkerOptions()
                .position(point)
                .icon(bitmap)
                //.zIndex(9)
                .draggable(true);
        //在地圖上新增Marker,並顯示
        marker = (Marker) baidumap.addOverlay(option);
        markers.add(marker);
        //並把marker的相關資訊儲存起來
        String id = marker.getId();
        latlngs.put(id, new LatLng(latitude, longitude));
        ids.add(id);
    }

第二步:畫線

我的思路是,每增加一個點,就把原來的線清除掉,重新畫線。
    /**
     * 如果此時有兩個點,就畫線
     */
    private void drawLine() {
        //在每次畫線之前,需要先清除以前畫的
        if (mPolyline != null) {
            mPolyline.remove();
        }
        List<LatLng> points = new ArrayList<LatLng>();
        LatLng l = null;
        for (int i = 0; i < ids.size(); i++) {
            l = latlngs.get(ids.get(i));
            points.add(l);
        }
        OverlayOptions ooPolyline = new PolylineOptions().width(10)
                .color(0xAAFF0000).points(points);
        mPolyline = (Polyline) baidumap.addOverlay(ooPolyline);
    }

第三步:畫多邊形,並在多邊形的中心新增文字

  • 首先要判斷座標點的個數是否符合
size = ids.size();
if (size <= 2) {
    Toast.makeText(this, "點必須大於2", Toast.LENGTH_SHORT).show();
    return;
}
  • 然後要把畫的線清除
   if (mPolyline!=null){
      mPolyline.remove();
   }
  • 開始畫多邊形
    /**
     * 如果有大於兩個點,就畫多邊形
     */
    private void drawPolygon() {
        if (polygon != null) {
            polygon.remove();
        }
        LatLng ll = null;
        List<LatLng> pts = new ArrayList<LatLng>();
        for (int i = 0; i < ids.size(); i++) {
            String s = ids.get(i);
            Log.e("aaa", "key= " + s + " and value= " + latlngs.get(s).toString());
            ll = latlngs.get(s);
            pts.add(ll);
        }
        OverlayOptions ooPolygon = new PolygonOptions().points(pts)
                .stroke(new Stroke(5, 0xAA00FF00)).fillColor(0xAAFFFF00);
        polygon = (Polygon) baidumap.addOverlay(ooPolygon);
    }
  • 求出多邊形的中心點,並在此點覆蓋文字資訊
for (int i = 0; i < size; i++) {
    l = latlngs.get(ids.get(i));
    la = la + l.latitude;
    lo = lo + l.longitude;
}
        AlertDialog.Builder builder = new AlertDialog.Builder(this);
        builder.setTitle("請輸入名字:");
        View inflate = View.inflate(this, R.layout.dialog_aliasname, null);
        final EditText edt_alias = inflate.findViewById(R.id.edt_alias);
        builder.setView(inflate);
        builder.setPositiveButton("確定", new DialogInterface.OnClickListener() {
            @Override
            public void onClick(DialogInterface dialogInterface, int i) {
                String trim = edt_alias.getText().toString().trim();
                if (trim.equals("")) {
                    Toast.makeText(Main2Activity.this, "別名不能為空!", Toast.LENGTH_SHORT).show();
                    return;
                }

                drawPolygon();
                // 新增文字,求出多邊形的中心點向中心點新增文字
                LatLng llText = new LatLng(la / size, lo / size);
                OverlayOptions ooText = new TextOptions()
                        .fontSize(24).fontColor(0xFFFF00FF).text(trim + "")
                        .position(llText);
                baidumap.addOverlay(ooText);
                polygonMap.put(trim, polygon);
                aliasname.add(trim);
                polygon = null;
                Log.e("aaa", "多邊形有幾個:" + polygonMap.size());
                Log.e("aaa", "別名有:" + aliasname.toString());
                for (int j = 0; j < markers.size(); j++) {
                    markers.get(j).remove();
                }
                //polygons.add(polygon);
                //polygon = null;
                latlngs.clear();
                ids.clear();
            }
        });
        builder.setNegativeButton("取消", new DialogInterface.OnClickListener() {
            @Override
            public void onClick(DialogInterface dialogInterface, int i) {

            }
        });
        builder.create().show();

第四步:判斷一個點是否在多邊形內

在這裡我們需要一個類 SpatialRelationUtil 在這個類中有一個方法,isPolygonContainsPoint,非常方便的就可以判斷一個點在不在多邊形內。程式碼如下:
            for (int i = 0; i < aliasname.size(); i++) {
                name = aliasname.get(i);
                Log.e("aaa", "檢查的別名是:" + name);
                polygon = polygonMap.get(name);
                String s = polygon.getPoints().toString();
                Log.e("aaa", "sssss---->" + s);
                //判斷一個點是否在多邊形中
                polygonContainsPoint = SpatialRelationUtil.isPolygonContainsPoint(polygon.getPoints(), new LatLng(latitude, longitude));
                if (polygonContainsPoint) {
                    Toast.makeText(this, "該點在 " + name + " 區域內。", Toast.LENGTH_SHORT).show();
                    areas.add(name);
                }
            }
            Log.e("aaa","areas"+areas.toString());
            if (areas.size() > 0) {
                String message = areas.toString();
                showDialog("所在的區域有:"+message);
            } else {
                showDialog("該點不在任何區域內。");
            }
        }

showDialog(String mess)的程式碼如下:

    private void showDialog(String message) {
        AlertDialog.Builder builder = new AlertDialog.Builder(this);
        builder.setTitle("百度地圖");

        builder.setMessage(message);
        builder.setPositiveButton("確定", new DialogInterface.OnClickListener() {
            @Override
            public void onClick(DialogInterface dialogInterface, int i) {

            }
        });
        builder.create().show();
    }
好了,到這裡就已經基本完成了以上的功能了

最後,奉上demo: