短距离场景下Marker是否在Circle内的检测代码失效问题
解决短距离下Marker是否在Circle内的检测问题
原代码的问题出在短距离场景下的浮点精度误差:你用的球面距离公式依赖acos函数,当两点距离极近时,math.sin(lat1)*math.sin(lat2)+math.cos(lat1)*math.cos(lat2)*math.cos(lon2-lon1)的计算结果可能会因为浮点运算的微小误差超出[-1, 1]的有效范围(比如变成1.0000000001),导致acos返回NaN,最终距离计算错误,判断逻辑失效。
下面是两种可行的修复方案:
方案一:限制acos输入的有效范围
在计算前把acos的输入值钳制在[-1, 1]区间内,避免NaN问题:
import 'dart:math' as math; double calculateDistance(double lat1, double lon1, double lat2, double lon2) { double cosTheta = math.sin(lat1)*math.sin(lat2)+math.cos(lat1)*math.cos(lat2)*math.cos(lon2-lon1); // 处理浮点精度误差,确保值在acos的有效输入范围内 cosTheta = math.max(-1.0, math.min(1.0, cosTheta)); double distance = math.acos(cosTheta)*6371; return distance; } bool isMarkerInsideCircle(Marker marker, Circle circle) { double distanceBetweenPoints = calculateDistance( marker.position.latitude, marker.position.longitude, circle.center.latitude, circle.center.longitude, ); // 注意检查单位一致性:如果circle.radius是米,这里要把distance转换成米(乘以1000) return distanceBetweenPoints <= circle.radius; }
方案二:使用Haversine公式(短距离精度更稳定)
Haversine公式在短距离场景下的浮点精度表现更出色,不容易出现超出范围的问题:
import 'dart:math' as math; double calculateDistance(double lat1, double lon1, double lat2, double lon2) { final dLat = lat2 - lat1; final dLon = lon2 - lon1; final a = math.sin(dLat / 2) * math.sin(dLat / 2) + math.cos(lat1) * math.cos(lat2) * math.sin(dLon / 2) * math.sin(dLon / 2); final c = 2 * math.atan2(math.sqrt(a), math.sqrt(1 - a)); // 6371是地球半径(公里),如果circle.radius单位是米,替换为6371000 final distance = 6371 * c; return distance; } bool isMarkerInsideCircle(Marker marker, Circle circle) { double distanceBetweenPoints = calculateDistance( marker.position.latitude, marker.position.longitude, circle.center.latitude, circle.center.longitude, ); return distanceBetweenPoints <= circle.radius; }
额外注意:务必确认circle.radius的单位和距离计算的单位一致——比如代码里默认计算的是公里,若你的Circle半径用的是米,需要把地球半径改成6371000,或者将计算出的距离乘以1000转换成米。
内容的提问来源于stack exchange,提问作者Burak Eren
相关产品推荐
相关产品推荐

