Android 百度地图 动态画多边形,并判断一个点是否在多边形内部

881 阅读2分钟

本文已参与「新人创作礼」活动,一起开启掘金创作之路。

由于项目的需求,需要动态的在地图上画出多边形,并且需要判断一个点是否在多边形的范围内,根据官方的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:

demo下载地址