如何在Android Studio中用Java解决Google Map多边形重叠问题
在Android Studio中用Java检测Google Map多边形重叠的方案
Google Maps Android SDK没有提供直接的多边形重叠检测接口,我们可以通过几何计算实现,核心思路是验证两个多边形是否存在顶点互斥在对方内部,或者边互相相交。以下是具体实现步骤和代码:
1. 坐标转换:经纬度转平面坐标
直接使用经纬度(球面坐标)计算几何关系会有误差,先将LatLng转换为墨卡托投影的平面坐标(单位:米),保证计算准确性:
// 将LatLng转换为墨卡托投影平面坐标 private PointF latLngToMercator(LatLng latLng) { double mercatorX = latLng.longitude * 20037508.34 / 180; double latRad = Math.toRadians(latLng.latitude); double mercatorY = Math.log(Math.tan((90 + latLng.latitude) * Math.PI / 360)) * 20037508.34 / Math.PI; return new PointF((float) mercatorX, (float) mercatorY); }
2. 点在多边形内的判断(射线法)
用射线法判断一个点是否落在多边形内部,只要任意一个多边形的顶点在另一个多边形内,即可判定重叠:
// 射线法判断点是否在多边形内部 private boolean isPointInPolygon(PointF point, List<PointF> polygonPoints) { int intersectCount = 0; int vertexCount = polygonPoints.size(); for (int i = 0; i < vertexCount; i++) { PointF p1 = polygonPoints.get(i); PointF p2 = polygonPoints.get((i + 1) % vertexCount); // 先判断点是否在多边形边上 if (isPointOnSegment(point, p1, p2)) { return true; } // 检查射线与当前边是否相交 if ((p1.y > point.y) != (p2.y > point.y)) { double xIntersect = (point.y - p1.y) * (p2.x - p1.x) / (p2.y - p1.y) + p1.x; if (point.x <= xIntersect) { intersectCount++; } } } // 交点数为奇数则在内部 return intersectCount % 2 == 1; } // 判断点是否在线段上 private boolean isPointOnSegment(PointF point, PointF p1, PointF p2) { return point.x <= Math.max(p1.x, p2.x) && point.x >= Math.min(p1.x, p2.x) && point.y <= Math.max(p1.y, p2.y) && point.y >= Math.min(p1.y, p2.y) && crossProduct(p1, point, p2) == 0; } // 计算叉积,用于判断点与线段的位置关系 private float crossProduct(PointF a, PointF b, PointF c) { return (b.x - a.x) * (c.y - a.y) - (b.y - a.y) * (c.x - a.x); }
3. 线段相交判断
检查两个多边形的所有边是否存在相交情况,只要有一组边相交,即可判定重叠:
// 判断两条线段是否相交(包含端点在对方线段上的情况) private boolean doSegmentsIntersect(PointF a1, PointF a2, PointF b1, PointF b2) { float cross1 = crossProduct(a1, a2, b1); float cross2 = crossProduct(a1, a2, b2); float cross3 = crossProduct(b1, b2, a1); float cross4 = crossProduct(b1, b2, a2); // 跨立实验:两条线段互相跨立对方 boolean segmentsCross = (cross1 * cross2 < 0) && (cross3 * cross4 < 0); // 检查端点是否在对方线段上 boolean pointOnSegment = isPointOnSegment(b1, a1, a2) || isPointOnSegment(b2, a1, a2) || isPointOnSegment(a1, b1, b2) || isPointOnSegment(a2, b1, b2); return segmentsCross || pointOnSegment; }
4. 综合判断多边形重叠
整合上述方法,完成两个Google Map多边形的重叠检测:
// 对外暴露的方法:判断两个Polygon是否重叠 public boolean doPolygonsOverlap(Polygon polygon1, Polygon polygon2) { // 转换两个多边形的顶点为平面坐标 List<PointF> poly1Points = new ArrayList<>(); for (LatLng latLng : polygon1.getPoints()) { poly1Points.add(latLngToMercator(latLng)); } List<PointF> poly2Points = new ArrayList<>(); for (LatLng latLng : polygon2.getPoints()) { poly2Points.add(latLngToMercator(latLng)); } // 检查多边形1的顶点是否在多边形2内 for (PointF point : poly1Points) { if (isPointInPolygon(point, poly2Points)) { return true; } } // 检查多边形2的顶点是否在多边形1内 for (PointF point : poly2Points) { if (isPointInPolygon(point, poly1Points)) { return true; } } // 检查两个多边形的边是否相交 int poly1VertexCount = poly1Points.size(); int poly2VertexCount = poly2Points.size(); for (int i = 0; i < poly1VertexCount; i++) { PointF a1 = poly1Points.get(i); PointF a2 = poly1Points.get((i + 1) % poly1VertexCount); for (int j = 0; j < poly2VertexCount; j++) { PointF b1 = poly2Points.get(j); PointF b2 = poly2Points.get((j + 1) % poly2VertexCount); if (doSegmentsIntersect(a1, a2, b1, b2)) { return true; } } } // 所有检查都不满足则不重叠 return false; }
注意事项
- 性能优化:如果需要批量检测多边形重叠,建议先通过
getBounds()获取多边形的边界框,快速排除明显不重叠的多边形,再进行精确计算。 - 凹多边形支持:上述算法对凸、凹多边形都有效,无需额外处理。
- 边界场景:完全包含、共享边/顶点等场景都会被正确判定为重叠。
内容的提问来源于stack exchange,提问作者Pooja Wagh
相关产品推荐
相关产品推荐

