指的就是地图API收费这件事, 自己做了一些替代方案,分享如下
**主要是用到两个功能
- 1:距离计算 (我离xxx有xxx米)
- 2:逆地理位置解析(我当前处于xx城市)**
针对1距离计算
直接使用极坐标函数即可 AI搜“极坐标函数计算经纬度距离”,AI写这种东西得心应手
这是php的函数示例
public static function getDistance($ulon, $ulat, $slon, $slat)
{
// 地球半径
$R = 6378137;
// 将角度转为狐度
$radLat1 = deg2rad($ulat);
$radLat2 = deg2rad($slat);
$radLng1 = deg2rad($ulon);
$radLng2 = deg2rad($slon);
// 结果
$s = acos(cos($radLat1) * cos($radLat2) * cos($radLng1 - $radLng2) + sin($radLat1) * sin($radLat2)) * $R;
// 精度
$s = round($s * 10000) / 10000;
return round($s);
}
注意:
(1)可能需要坐标系的转换,比如腾讯系坐标转为GPS系坐标,同样AI搜“腾讯系坐标转为GPS系坐标”让它给个函数即可
(2)腾讯api等 可以求出步行距离,这个函数求的是直线距离,肯定没步行距离好,但为了5w块钱,将就下
针对2逆地理位置解析
大体思路就是拉取省市的坐标边缘数据,判断当前坐标是否在这个城市区域内
这个数据,叫geojson数据,这个网站有
geojson.hxkj.vip/ ---我下载的是这个
还有个官方网站也有
geojson.cn/
下载后的数据,大概格式如下
"coordinates": [
[
[
[
113.540624,
22.201871
],
[
113.540515,
22.203771
],
[
113.539782,
22.204445
],
[
113.5391,
22.206724
],
]
我们要做的,就是判断自己经纬度,是否在这么个区域内,上面4个坐标,就是一个四边形,判断当前经纬度是否在这个四边形即可(实际应用中是多边形) 这个也可以问AI “直接将geojson数据发送一小段给AI,问,根据上面geojson数据,如何逆推出城市数据,如上海即可” 下面是php的,仅供参考
<?php
namespace app\common\library\geo;
class GeoLocationFinder
{
private $dataDirectory = './data';//数据放在类的当前data目录下
private $loadedFiles = [];
private $featuresCache = [];
private $province = "浙江省";//我这浙江的坐标多,所以默认查浙江的这个文件
private $provinceArray = array(
110000 => '北京市',
120000 => '天津市',
130000 => '河北省',
140000 => '山西省',
150000 => '内蒙古自治区',
210000 => '辽宁省',
220000 => '吉林省',
230000 => '黑龙江省',
310000 => '上海市',
320000 => '江苏省',
330000 => '浙江省',
340000 => '安徽省',
350000 => '福建省',
360000 => '江西省',
370000 => '山东省',
410000 => '河南省',
420000 => '湖北省',
430000 => '湖南省',
440000 => '广东省',
450000 => '广西壮族自治区',
460000 => '海南省',
500000 => '重庆市',
510000 => '四川省',
520000 => '贵州省',
530000 => '云南省',
540000 => '西藏自治区',
610000 => '陕西省',
620000 => '甘肃省',
630000 => '青海省',
640000 => '宁夏回族自治区',
650000 => '新疆维吾尔自治区',
710000 => '台湾省', // 注意:此条目在实际应用中可能需特别处理
810000 => '香港特别行政区',
820000 => '澳门特别行政区',
);
public function __construct()
{
// 构造函数中初始化,可以加载特定文件或做其他预处理
// 优先查浙江的
$this->loadSpecificFile('330000.geoJson.default');
}
private function loadGeoJSONFiles($filename)
{
$filePath = __DIR__."/".$this->dataDirectory . '/' . $filename;
if (file_exists($filePath) && is_readable($filePath)) {
$content = file_get_contents($filePath);
$geojsonData = json_decode($content);
if ($geojsonData && isset($geojsonData->features)) {
$this->featuresCache[$filename] = $geojsonData->features;
$this->loadedFiles[] = $filename;
} else {
echo "Error: Invalid GeoJSON format in file $filename\n";
}
} else {
echo "Error: File $filename not found or not readable\n";
}
}
private function loadSpecificFile($filename)
{
$this->loadGeoJSONFiles($filename);
}
public function findLocationByCoordinates($longitude, $latitude)
{
// 首先尝试从已加载的特定文件中查找
foreach ($this->featuresCache as $features) {
$result = $this->searchFeatures($features, $longitude, $latitude);
if ($result !== null) {
return $result;
}
}
// 如果特定文件中没有找到,遍历所有文件查找
$files = glob(__DIR__."/".$this->dataDirectory . '/*.geoJson');
foreach ($files as $file) {
$filename = basename($file);
if (!in_array($filename, $this->loadedFiles)) {
$this->loadGeoJSONFiles($filename);
$result = $this->searchFeatures($this->featuresCache[$filename], $longitude, $latitude);
if ($result !== null) {
return $result;
}
}
}
return null;
}
private function searchFeatures($features, $longitude, $latitude)
{
foreach ($features as $feature) {
if ($this->isPointInPolygon([$longitude, $latitude], $feature->geometry->coordinates)) {
$provinceCode =$feature->properties->acroutes[1] ?? "";
$this->province =$this->provinceArray[$provinceCode] ?? "";
return $this->formatLocationInfo($feature->properties);
}
}
return null;
}
private function isPointInPolygon($point, $polygon)
{
$x = $point[0]; // 经度
$y = $point[1]; // 纬度
$isInside = false;
$rings = $polygon; // GeoJSON中的"coordinates"可能包含多个环,直接使用
foreach ($rings as $v) { // 遍历所有环
//这里就是多了一层
$ring =$v[0];
$numVertices = count($ring);
$j = $numVertices - 1; // 初始化前一个顶点的索引
for ($i = 0; $i < $numVertices; ++$i) { // 遍历环上的顶点
$xi = $ring[$i][0]; // 当前顶点经度
$yi = $ring[$i][1]; // 当前顶点纬度
$xj = $ring[$j][0]; // 前一个顶点经度
$yj = $ring[$j][1]; // 前一个顶点纬度
// 应用射线交叉法判断
$crossProduct = (($yi > $y) != ($yj > $y)) && ($x < ($xj - $xi) * ($y - $yi) / ($yj - $yi) + $xi);
if ($crossProduct) {
$isInside = !$isInside;
}
$j = $i; // 更新前一个顶点的索引
}
}
return $isInside;
}
private function formatLocationInfo($properties)
{
//110000 => '北京市'
//120000 => '天津市'
//310000 => '上海市'
//500000 => '重庆市' 这几个是直辖市 降一级
$city =$properties->name;
$province = $this->province;
$district = "";
if(in_array($this->province,['上海市','天津市','重庆市','北京市'])){
$district =$city;
$city =$province;
}
return ['province'=>$province,'city'=>$city,'district'=>$district];
}
}
//// 使用示例
//$finder = new GeoLocationFinder();
//$longitude = 120.1833; // 经度
//$latitude = 30.2500; // 纬度
//echo $finder->findLocationByCoordinates($longitude, $latitude);
github上还有个例子,可以参考,应该比较全 看着可以用mysql来实现,包括更详细的数据 github.com/xiangyuecn/…