由于项目的需求,需要动态的在地图上画出多边形,并且需要判断一个点是否在多边形的范围内,根据官方的demo,结合网上的查的资料,做出的效果如下图所示:
思路就是:
1.点击地图增加marker;
2.拿到marker,根据marker来画线(判断点的个数,大于 1 时);
3.点击marker可以进行删除,长按可以进行拖拽操作;
4.当点击确定时,清除线,把多边形画出来(当点大于 2 时);
5.在地图上点击一点,并判断该点是否在多边形区域内
//marker 相关
private Marker marker;
List markers = new ArrayList<>();
//算是map的索引,通过此id 来按顺序取出坐标点
private List ids = new ArrayList<>();
//用来存储坐标点
private Map latlngs = new HashMap<>();
private InfoWindow mInfoWindow;
//线
private Polyline mPolyline;
//多边形
private Polygon polygon;
//private List polygons = new ArrayList<>();
private double latitude;
private double longitude;
//是坐标点的多少,用来判断是画线,还是画多边形
private int size;
//根据别名来存储画好的多边形
private Map polygonMap = new HashMap<>();
//多边形的别名
private List aliasname = new ArrayList<>();
//
private boolean polygonContainsPoint;
//用来存储一个点所在的所有的区域
List 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
* @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;
}
@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
*
* @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 points = new ArrayList();
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 pts = new ArrayList();
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: