前言
需要在百度地图上划定一片矩形区域为限行区域,当车辆即将越过上边界以及左边界时需要在百度地图上进行语音以及图片弹窗的提示。学习了百度地图SDK地理围栏的源码,官方支持多种围栏的创建,但是貌似新版的SDK不支持fence类了,所以只好参考源码进行DIY。
实现方式
首先在百度地图上通过四角的坐标绘画矩形区域,如下,需要注意的是,点的添加顺序需要按照逆时针方向进行,
// 设置限行区域
MarkerOptions markerOption = new MarkerOptions().draggable(true);
List<LatLng> polygonPoints = new ArrayList<>();
polygonPoints.add(topLeft);
polygonPoints.add(bottomLeft);
polygonPoints.add(bottomRight);
polygonPoints.add(topRight);
mBaiduMap.addOverlay(new PolygonOptions()
.points(polygonPoints)
.fillColor(0x666495ED) // 填充颜色
.stroke(new Stroke(5, 0xE66495ED)));
其次将矩形区域添加至LatLngBounds中,这样可通过bounds的contains函数直接判断车辆是否在区域内,如下:
private LatLngBounds.Builder boundsBuilder = new LatLngBounds.Builder();
boundsBuilder.include(polygonPoints);
bounds = boundsBuilder.build();
if (bounds.contains(vehPos))
{
...
}
在判断车辆是否发生越界行为时,我是用了向量乘积的方法进行了判断,将上边界和左边界抽象为向量,而后将车辆位置和边界起点组成的新向量进行乘积,若res > 0,则车辆在该边界的逆时针方向,若res < 0,则车辆在该边界的顺时针方向,若res = 0,则车辆在该边界上,如下:
/**
* @Description 通过将两点的经纬度抽象为线段,进而判断当前点与线段间的关系,线段外/内/上
* @Author Wp
* @Time 2023/5/31 16:35
* @Param LatLng startPoint
* @Param LatLng endPoint
* @Param LatLng currentPoint
* @Param boolean isTop
* @Return int 1:未越界 -1:越界 0:on
*/
public static int checkPointLine(LatLng startPoint, LatLng endPoint, LatLng currentPoint, boolean isTop) {
CoordinateXY startPos = new CoordinateXY();
if (startPoint.latitude != centerLat || startPoint.longitude != centerLon)
startPos = GPSToXYZ(startPoint);
else{
startPos.setX(0.0);
startPos.setY(0.0);
}
CoordinateXY endPos = GPSToXYZ(endPoint);
CoordinateXY currentPos = GPSToXYZ(currentPoint);
double crossProduct = (currentPos.getY() - startPos.getY()) * (endPos.getX() - startPos.getX()) - (currentPos.getX() - startPos.getX()) * (endPos.getY() - startPos.getY());
System.out.println("crossProduct " + crossProduct);
if (crossProduct > 0) {
if (!isTop){
double distance = pointLineDistance(startPos.getX(), startPos.getY(), endPos.getX(), endPos.getY(), currentPos.getX(), currentPos.getY());
System.out.println("距离左边界 " + distance + "m");
if (distance < permitDis)
return -1;
else
return 1;
}
return -1; // point is inside
}
else if (crossProduct < 0) {
if (isTop)
{
double distance = pointLineDistance(startPos.getX(), startPos.getY(), endPos.getX(), endPos.getY(), currentPos.getX(), currentPos.getY());
System.out.println("距离上边界 " + distance + "m");
if (distance < permitDis)
return -1;
else
return 1;
}
return -1; // point is outside
}
else {
return 0; // point is on the line
}
}
因为存在车辆即将越界的可能,所以在以上的代码里,我还增加了与边界间距离的判断,计算距离的函数如下,其实就是点到线的距离公式,同时这里所有的计算坐标均由经纬度转成了直角坐标,至于如何进行转换,我之前的博客中有写过,
public static double pointLineDistance(double x1, double y1, double x2, double y2, double x, double y) {
double A = x - x1;
double B = y - y1;
double C = x2 - x1;
double D = y2 - y1;
double dot = A * C + B * D;
double len_sq = C * C + D * D;
double param = dot / len_sq;
double xx, yy;
if (param < 0) {
xx = x1;
yy = y1;
} else if (param > 1) {
xx = x2;
yy = y2;
} else {
xx = x1 + param * C;
yy = y1 + param * D;
}
double dx = x - xx;
double dy = y - yy;
return Math.sqrt(dx * dx + dy * dy);
}
至此完成了简单的矩形区域上边界以及左边界的越界判断