Android 百度地图画多边形

  最近在研究百度地图的sdk,而且项目中也需要实现一个在地图上画多边形,并且可以拖拽,还要计算周长和面积,还要判断线段是否相交。当时我一看需求,感觉问题并不简单,但是还是先默默地打开了百度。。。嘿嘿,下面说说思路:

1.点击地图的时候创建Marker点;

2.当大于1个marker的时候,可以画线;

3.监听地图上marker的点击和拖拽事件,如果最后一个点击的marker的位置和第一个marker的位置重合,可以画矩形;

4.拖拽marker,更新位置,并更新线和矩形,判断线段是否相交。

  No code No BB,下面上代码:


import android.graphics.Color
import android.os.Bundle
import android.support.v7.app.AppCompatActivity
import com.baidu.mapapi.map.*
import com.baidu.mapapi.model.LatLng
import com.baidu.mapapi.utils.AreaUtil
import com.baidu.mapapi.utils.DistanceUtil
import kotlinx.android.synthetic.main.activity_draw_map.*
import java.util.*

/**
 * Created by yuan7016 on 2020/04/02 15:15. 
* desc : 绘制地图 */ class DrawMapActivity : AppCompatActivity() { companion object { private const val TAG = "MAP" } private lateinit var baiduMap: BaiduMap private var hasDrawFinished = false//是否已经画完 private var mPolyline: Polyline? = null//折线对象 private var mPolygon: Polygon? = null//多边形对象 private var currentDragMarkerIndex = 0//当前拖拽的marker index /** * 所有的位置点 */ private val allPositionList = ArrayList() /** * 全部marker集合 */ private val allMarkersList = ArrayList() override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_draw_map) //返回 iv_back.setOnClickListener { finish() } rl_delete_map.setOnClickListener { //清除地图上的所有覆盖物 baiduMap.clear() allPositionList.clear() allMarkersList.clear() hasDrawFinished = false mPolyline?.remove() mPolygon?.remove() mPolyline = null mPolygon = null tvMapPerimeter.text = "周长: 0米" tvMapArea.text = "面积: 0亩" } baiduMap = mapView.map val uiSettings = baiduMap.uiSettings baiduMap.setViewPadding(0, 0, 0, 150) baiduMap.showMapIndoorPoi(false)//设置是否显示室内图标注 //地图点击 baiduMap.setOnMapClickListener(object : BaiduMap.OnMapClickListener { override fun onMapClick(latLng: LatLng) { Log.e(TAG, "===onMapClick==经度=" + latLng.longitude + "==纬度=" + latLng.latitude) if (!hasDrawFinished) { addMarkers(latLng) } } //单击地图中的POI点 override fun onMapPoiClick(mapPoi: MapPoi) { val position = mapPoi.position Log.e(TAG, "===onMapPoiClick==经度=" + position.longitude + "==纬度=" + position.latitude) if (!hasDrawFinished) { addMarkers(position) } } }) //marker点击 baiduMap.setOnMarkerClickListener(BaiduMap.OnMarkerClickListener { marker -> val position = marker.position if (hasDrawFinished) { Log.e(TAG, "====setOnMarkerClickListener======已经封闭了=======") } else { Log.e(TAG, "====setOnMarkerClickListener======2======") if (allMarkersList[0] == marker) { //如果当前点击的marker是第一个marker 可以封闭多边形了 //封闭图形 hasDrawFinished = true //添加marker addMarkers(position) //画多边形 drawPolygon() return@OnMarkerClickListener true } } false }) //marker拖拽 baiduMap.setOnMarkerDragListener(object : BaiduMap.OnMarkerDragListener { override fun onMarkerDrag(marker: Marker) { val position = marker.position if (allPositionList.size > 1) {//改变线 //获取线上的位置点 更新位置 mPolyline?.points?.let { it[currentDragMarkerIndex] = position //更新数据 allPositionList[currentDragMarkerIndex] = position mPolyline?.setPoints(it) } //计算周长 calculatePerimeter() if (hasDrawFinished) { //改变多边形 drawPolygon() } } else { //如果只有一个marker 改变第一个marker的位置 allMarkersList[0] = marker allPositionList[0] = position } } override fun onMarkerDragEnd(marker: Marker) { val position = marker.position Log.w(TAG, "===onMarkerDragEnd==经度=" + position.longitude + "==纬度=" + position.latitude) } override fun onMarkerDragStart(marker: Marker) { currentDragMarkerIndex = allMarkersList.indexOf(marker) Log.w(TAG, "===onMarkerDragStart=$currentDragMarkerIndex") } }) } /** * 添加marker */ private fun addMarkers(latLng: LatLng) { if (allPositionList.size == 0) { //创建新marker val bitmapDescriptor = CommonUtil.getBitmapDescriptor(this, R.drawable.layer_list_bg_shape_green_marker) //构建MarkerOption,用于在地图上添加Marker val option = MarkerOptions() .position(latLng) .alpha(0.8f) .anchor(0.5f,0.5f) .draggable(true)//可以拖拽 .icon(bitmapDescriptor) val marker = baiduMap.addOverlay(option) as Marker allMarkersList.add(marker) allPositionList.add(latLng) } else { if (hasDrawFinished) { //已经画完了 把当前marker和第一个marker相连接 drawLine(allPositionList[allPositionList.size - 1], allPositionList[0]) } else { //大于2 开始划线 Log.w(TAG, "===addMarker===大于2 开始划线") val bitmapDescriptor = CommonUtil.getBitmapDescriptor(this, R.drawable.layer_list_bg_shape_green_marker) //构建MarkerOption,用于在地图上添加Marker val option = MarkerOptions() .position(latLng) .alpha(0.8f) .anchor(0.5f,0.5f) .draggable(true)//可以拖拽 .icon(bitmapDescriptor) val marker = baiduMap.addOverlay(option) as Marker allMarkersList.add(marker) allPositionList.add(latLng) val currentPointIndex = allPositionList.indexOf(latLng) drawLine(allPositionList[currentPointIndex - 1], latLng) } } } /** * 画线 * * @param startPoint * @param endPoint */ private fun drawLine(startPoint: LatLng, endPoint: LatLng) { if (mPolyline == null) { val points = ArrayList() if (!points.contains(startPoint)) { points.add(startPoint) } if (!points.contains(endPoint)) { points.add(endPoint) } //设置折线的属性 val polylineOptions = PolylineOptions() .width(5) //线的宽度 .color(resources.getColor(R.color.green_right_line_color)) .points(points)//points count can not less than 2 //创建折线对象 mPolyline = baiduMap.addOverlay(polylineOptions) as Polyline? } else { //获取折线上原来的数据 val linePoints = mPolyline?.points //添加新的数据 linePoints?.let { //判断一下是否已经包含这个位置点了 if (!it.contains(startPoint)) { linePoints.add(startPoint) } if (!it.contains(endPoint)) { linePoints.add(endPoint) } } //更新线数据 mPolyline?.points = linePoints } Log.e(TAG, "===drawLine==折线上的数据个数=" + mPolyline?.points?.size) //计算周长 calculatePerimeter() } /** * 画多边形,并判断是否相交,改变颜色 */ private fun drawPolygon() { if (mPolygon == null) { //创建多边形 val polygonOptions = PolygonOptions() .points(allPositionList) .fillColor(resources.getColor(R.color.green_right_map_color)) .stroke(Stroke(5, resources.getColor(R.color.green_right_line_color)))//边框宽度和颜色 //判断是否相交 if (allPositionList.size > 3) { val approvedPolygon = CommonUtil.isApprovedPolygon(allPositionList) if (approvedPolygon) { polygonOptions.fillColor(resources.getColor(R.color.green_right_map_color)) polygonOptions.stroke(Stroke(5, resources.getColor(R.color.green_right_line_color))) } else { //改变颜色 polygonOptions.fillColor(resources.getColor(R.color.red_error_map_color)) polygonOptions.stroke(Stroke(5, resources.getColor(R.color.red_error_line_color))) } } //创建多边形 mPolygon = baiduMap.addOverlay(polygonOptions) as Polygon? } else { //更新多边形 if (allPositionList.size > 3) { val approvedPolygon = CommonUtil.isApprovedPolygon(allPositionList) if (approvedPolygon) { mPolygon?.fillColor = resources.getColor(R.color.green_right_map_color) mPolygon?.stroke = (Stroke(5, resources.getColor(R.color.green_right_line_color))) } else { //改变颜色 mPolygon?.fillColor = resources.getColor(R.color.red_error_map_color) mPolygon?.stroke = (Stroke(5, resources.getColor(R.color.red_error_line_color))) } } mPolygon?.points = allPositionList } //计算面积 calculateArea() } /** * 计算周长 */ private fun calculatePerimeter() { val points = mPolyline?.points var length = 0.0 points?.let { for (i in 0 until it.size - 1) { length += DistanceUtil.getDistance(it[i], it[i + 1]) } val format = String.format("%.2f", length) tvMapPerimeter.text = "周长:" + format + "米" } } /** * 计算面积 */ private fun calculateArea() { mPolygon?.points?.let { // 计算多边形面积,返回单位:平方米 val polygonArea = AreaUtil.calculateArea(it) // 转换成亩 1平方米(㎡)=0.0015亩 val mu = 0.0015f val area = polygonArea * mu tvMapArea.text = "面积:" + String.format("%.2f", area) + "亩" } } override fun onResume() { super.onResume() mapView.onResume() } override fun onPause() { super.onPause() mapView.onPause() } override fun onDestroy() { baiduMap.clear() mapView.onDestroy() super.onDestroy() } }

 其他工具类:

public class CommonUtil {

    /**
     * 判断多边形是否相交
     * @param list
     * @return  true 不相交,  false 相交
     */
    public static boolean isApprovedPolygon(List list) {
        //当多边形的边大于3个的时候才需要判断是否相交,取一个边,和它不相邻的边比较是否相交
        for (int i = 1; i < list.size(); i++) {
            //基线
            LatLng latLngA = list.get(i-1);
            LatLng latLngB = list.get(i);

            //需要对比的线段
            for (int j = i+2;j<=list.size();j++){
                if ( j==list.size()){
                    if (i !=1 ) {
                        LatLng latLngC = list.get(list.size() - 1);
                        LatLng latLngD = list.get(0);
                        if (intersection(latLngA.longitude, latLngA.latitude, latLngB.longitude, latLngB.latitude, latLngC.longitude, latLngC.latitude, latLngD.longitude, latLngD.latitude)) {
                            return false;
                        }
                    }
                }else {
                    LatLng latLngC = list.get(j - 1);
                    LatLng latLngD = list.get(j);
                    if (intersection(latLngA.longitude, latLngA.latitude, latLngB.longitude, latLngB.latitude, latLngC.longitude, latLngC.latitude, latLngD.longitude, latLngD.latitude)) {
                        return false;
                    }
                }
            }
        }
        return true;
    }



    /**两【线段】是否相交
     * @param l1x1 线段1的x1
     * @param l1y1 线段1的y1
     * @param l1x2 线段1的x2
     * @param l1y2 线段1的y2
     * @param l2x1 线段2的x1
     * @param l2y1 线段2的y1
     * @param l2x2 线段2的x2
     * @param l2y2 线段2的y2
     * @return 是否相交
     */
    public static boolean intersection(double l1x1, double l1y1, double l1x2, double l1y2,
                                       double l2x1, double l2y1, double l2x2, double l2y2)
    {

        // 快速排斥实验 首先判断两条线段在 x 以及 y 坐标的投影是否有重合。 有一个为真,则代表两线段必不可交。
        if (Math.max(l1x1,l1x2) < Math.min(l2x1 ,l2x2)
                || Math.max(l1y1,l1y2) < Math.min(l2y1,l2y2)
                || Math.max(l2x1,l2x2) < Math.min(l1x1,l1x2)
                || Math.max(l2y1,l2y2) < Math.min(l1y1,l1y2))
        {
            return false;
        }

        // 跨立实验  如果相交则矢量叉积异号或为零,大于零则不相交
        if ((((l1x1 - l2x1) * (l2y2 - l2y1) - (l1y1 - l2y1) * (l2x2 - l2x1))
                * ((l1x2 - l2x1) * (l2y2 - l2y1) - (l1y2 - l2y1) * (l2x2 - l2x1))) > 0
                || (((l2x1 - l1x1) * (l1y2 - l1y1) - (l2y1 - l1y1) * (l1x2 - l1x1))
                * ((l2x2 - l1x1) * (l1y2 - l1y1) - (l2y2 - l1y1) * (l1x2 - l1x1))) > 0)
        {
            return false;
        }

        return true;
    }
}

这样画线,画多边形的demo就做好了,看看效果图吧!

Android 百度地图画多边形_第1张图片

 

 

//===============================================================================================

参考文章:https://www.jianshu.com/p/f48d72a61459 

你可能感兴趣的:(第三方框架,android自定义View)