Android 百度地圖 動態畫多邊形,並判斷一個點是否在多邊形內部
阿新 • • 發佈:2019-02-05
由於專案的需求,需要動態的在地圖上畫出多邊形,並且需要判斷一個點是否在多邊形的範圍內,根據官方的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: