项目中需要判断是否中国区,通过经纬度来判断

写了一个方法, 划定一个矩形框区域来判断是否在中国区域。

简单判断-矩形区域

1
2
3
4
5
6
7
8
9
10
11
12
type Point struct {
Lat float64
Lng float64
}

func CorrectInChina(loc Point) bool {
if loc.Lng >= 72.004 && loc.Lng <= 137.8347 &&
loc.Lat >= 0.8293 && loc.Lat <= 55.8271 {
return true
}
return false
}

但这样精度太差,误差太大。俄罗斯边界等区域都会被划分进来。

射线法

射线法(Ray Casting Algorithm)是一种用于判断点是否在多边形内的常用算法。其基本原理是:从该点向任意一个方向发出一条射线,计算这条射线与多边形各边相交的次数。如果相交次数为奇数,则该点在多边形内;如果相交次数为偶数,则该点在多边形外。

原理解释

  1. 射线发射:从要测试的点(称为测试点)向任意一个方向发射一条射线。
  2. 计算相交次数:遍历多边形的每一条边,判断射线与这条边是否相交。如果相交,记录一次相交。
  3. 判断奇偶性:计算射线与多边形边的相交总次数。如果总次数为奇数,则测试点在多边形内部;如果为偶数,则测试点在多边形外部。

具体步骤

  1. 确定射线的方向:一般来说,可以选择从测试点向右水平发射一条射线。
  2. 遍历多边形的每一条边:判断射线是否与每条边相交。
  3. 计算相交点:通过计算射线与多边形边的交点来确定相交次数。

多边形区域

为了更加准确地判断某个经纬度是否在中国境内,可以使用多边形的方法。中国的国境线可以近似为一个多边形,通过判断某个点是否在这个多边形内来确定经纬度是否在中国境内。

以下是一个示例代码,使用了点在多边形内的算法来判断某个点是否在中国境内:

准备中国国境线数据

首先,你需要准备中国国境线的数据,可以通过查找中国国境线的经纬度数据(可以通过 GeoJSON 文件获取)。

实现点在多边形内的算法

这里我们使用射线法(Ray Casting Algorithm)来判断点是否在多边形内。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
package main

import (
"fmt"
)

type Point struct {
Lat float64
Lng float64
}

// 中国国境线多边形数据(简化版)
var chinaPolygon = []Point{
{53.55, 73.66},
{53.55, 134.77},
{18.17, 134.77},
{18.17, 73.66},
}

// 判断点是否在多边形内
func isPointInPolygon(point Point, polygon []Point) bool {
intersections := 0
for i := 0; i < len(polygon); i++ {
j := (i + 1) % len(polygon)
if isLineIntersect(point, polygon[i], polygon[j]) {
intersections++
}
}
return intersections%2 == 1
}

// 判断射线与多边形边是否相交
func isLineIntersect(point, p1, p2 Point) bool {
if p1.Lat == p2.Lat {
return false
}
if point.Lat < min(p1.Lat, p2.Lat) || point.Lat >= max(p1.Lat, p2.Lat) {
return false
}
intersectLng := (point.Lat-p1.Lat)*(p2.Lng-p1.Lng)/(p2.Lat-p1.Lat) + p1.Lng
return intersectLng > point.Lng
}

func min(a, b float64) float64 {
if a < b {
return a
}
return b
}

func max(a, b float64) float64 {
if a > b {
return a
}
return b
}

func main() {
point := Point{Lat: 39.90, Lng: 116.40} // 北京的经纬度
if isPointInPolygon(point, chinaPolygon) {
fmt.Println("Point is inside China.")
} else {
fmt.Println("Point is outside China.")
}
}

其中边境经纬度可以完善

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
// 简化版中国国境线多边形数据
var chinaPolygon = []Point{
{53.560711, 73.588409}, // 黑龙江省漠河县
{49.17342, 87.41581}, // 新疆维吾尔自治区塔城市
{44.995882, 94.660484}, // 新疆维吾尔自治区哈密市
{43.505416, 97.396881}, // 甘肃省酒泉市
{39.665668, 98.341694}, // 甘肃省敦煌市
{37.302718, 100.122482}, // 青海省海西州
{34.234513, 108.947021}, // 陕西省西安市
{31.571692, 120.428528}, // 江苏省苏州市
{28.456635, 121.451378}, // 浙江省温州市
{24.396308, 118.072083}, // 福建省厦门市
{22.5293, 114.137039}, // 广东省深圳市
{21.54238, 110.856775}, // 广东省湛江市
{18.253769, 109.511116}, // 海南省三亚市
{21.035755, 107.975853}, // 广西壮族自治区北海市
{23.69781, 100.20874}, // 云南省普洱市
{26.86252, 98.859886}, // 云南省香格里拉市
{27.60802, 88.916092}, // 西藏自治区日喀则市
{34.543896, 78.437439}, // 新疆维吾尔自治区喀什地区
{39.76686, 73.507141}, // 新疆维吾尔自治区和田地区
}

或者自己通过地区获取边境经纬度点,点位越多,越精确

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
var chinaPolygon = []Point{
// 添加 东北
{53.291134, 121.289282},
{53.505846, 123.639992},
{50.293961, 127.591589},
{47.803978, 130.877017},
{53.549749, 123.499943},
{50.181304, 127.575420},
{47.940529, 130.923134},
{48.329083, 134.561953},
{44.829236, 131.141463},
{42.567141, 130.486475},
{41.542478, 127.269264},
{40.113521, 124.271293},

//东部
{30.332926, 123.802167},
{28.793856, 122.600638},

//南部
{18.333032, 110.218087},
{19.555954, 108.580304},
{21.651859, 107.985147},
{21.213037, 101.776268},
{24.216747, 97.810662},

// 西南
{28.066999, 88.048385},
//西部
{39.419108, 73.683423},
{45.015674, 80.126125},

// 北部
{49.111617, 87.094934},
{42.991898, 96.350016},
{43.762155, 111.716277},
{49.503154, 117.968756},
{49.130541, 87.629520},
}