gis-distance-tool 0.1.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,43 @@
1
+ Metadata-Version: 2.4
2
+ Name: gis-distance-tool
3
+ Version: 0.1.0
4
+ Summary: GIS距离分析工具-基于Haversine公式计算大圆距离
5
+ Author-email: belywe-spec <belywe79@gmail.com>
6
+ License: MIT
7
+ Classifier: Development Status :: 3 - Alpha
8
+ Classifier: Intended Audience :: Science/Research
9
+ Classifier: License :: OSI Approved :: MIT License
10
+ Classifier: Programming Language :: Python :: 3
11
+ Classifier: Programming Language :: Python :: 3.8
12
+ Classifier: Programming Language :: Python :: 3.9
13
+ Classifier: Programming Language :: Python :: 3.10
14
+ Classifier: Programming Language :: Python :: 3.11
15
+ Classifier: Programming Language :: Python :: 3.12
16
+ Classifier: Topic :: Scientific/Engineering :: GIS
17
+ Requires-Python: >=3.8
18
+ Description-Content-Type: text/markdown
19
+ Provides-Extra: numpy
20
+ Requires-Dist: numpy>=1.20.0; extra == "numpy"
21
+ Provides-Extra: scipy
22
+ Requires-Dist: scipy>=1.7.0; extra == "scipy"
23
+ Provides-Extra: full
24
+ Requires-Dist: numpy>=1.20.0; extra == "full"
25
+ Requires-Dist: scipy>=1.7.0; extra == "full"
26
+ Provides-Extra: dev
27
+ Requires-Dist: pytest>=7.0.0; extra == "dev"
28
+ Requires-Dist: black>=22.0.0; extra == "dev"
29
+ Requires-Dist: flake8>=5.0.0; extra == "dev"
30
+ Requires-Dist: mypy>=0.990; extra == "dev"
31
+
32
+ # GIS Distance Tool
33
+
34
+ 一个基于 Haversine 公式的 GIS 距离计算工具,支持单点和批量计算。
35
+
36
+ # 安装
37
+
38
+ # 基础安装(无依赖)
39
+ pip install .
40
+
41
+ # 安装 NumPy 支持
42
+ pip install .[numpy]
43
+
@@ -0,0 +1,12 @@
1
+ # GIS Distance Tool
2
+
3
+ 一个基于 Haversine 公式的 GIS 距离计算工具,支持单点和批量计算。
4
+
5
+ # 安装
6
+
7
+ # 基础安装(无依赖)
8
+ pip install .
9
+
10
+ # 安装 NumPy 支持
11
+ pip install .[numpy]
12
+
@@ -0,0 +1,80 @@
1
+ [build-system]
2
+ # 指定构建工具
3
+ requires = ["setuptools>=61.0", "wheel"]
4
+ build-backend = "setuptools.build_meta"
5
+
6
+ [project]
7
+ # 项目基本信息
8
+ name = "gis-distance-tool"
9
+ version = "0.1.0"
10
+ description = "GIS距离分析工具-基于Haversine公式计算大圆距离"
11
+ readme = "README.md"
12
+ authors = [
13
+ {name = "belywe-spec", email = "belywe79@gmail.com"}
14
+ ]
15
+ license = {text = "MIT"}
16
+ requires-python = ">=3.8"
17
+ classifiers = [
18
+ "Development Status :: 3 - Alpha",
19
+ "Intended Audience :: Science/Research",
20
+ "License :: OSI Approved :: MIT License",
21
+ "Programming Language :: Python :: 3",
22
+ "Programming Language :: Python :: 3.8",
23
+ "Programming Language :: Python :: 3.9",
24
+ "Programming Language :: Python :: 3.10",
25
+ "Programming Language :: Python :: 3.11",
26
+ "Programming Language :: Python :: 3.12",
27
+ "Topic :: Scientific/Engineering :: GIS",
28
+ ]
29
+
30
+ # 核心依赖
31
+ dependencies = [
32
+ # 基础版无需第三方库
33
+ ]
34
+
35
+ # 可选依赖(按功能分组,用户用 pip install .[extra] 安装)
36
+ [project.optional-dependencies]
37
+ numpy = ["numpy>=1.20.0",]
38
+ scipy = ["scipy>=1.7.0",]
39
+ full = [
40
+ "numpy>=1.20.0",
41
+ "scipy>=1.7.0",
42
+ ]
43
+ dev = [
44
+ "pytest>=7.0.0",
45
+ "black>=22.0.0",
46
+ "flake8>=5.0.0",
47
+ "mypy>=0.990",
48
+ ]
49
+
50
+ # 命令行入口点
51
+ [project.scripts]
52
+ gis-distance = "gis_tool.cli:main"
53
+
54
+ # 包目录结构配置
55
+ [tool.setuptools.packages.find]
56
+ where = ["src"]
57
+ include = ["gis_tool*"]
58
+ exclude = ["tests*", "docs*"]
59
+
60
+ # 工具配置(可选,用于代码质量检查)
61
+ [tool.black]
62
+ line-length = 100
63
+ target-version = ['py38', 'py39', 'py310', 'py311']
64
+
65
+ [tool.isort]
66
+ profile = "black"
67
+ line_length = 100
68
+
69
+ [tool.mypy]
70
+ python_version = "3.8"
71
+ warn_return_any = true
72
+ warn_unused_configs = true
73
+ ignore_missing_imports = true
74
+
75
+ [tool.pytest.ini_options]
76
+ minversion = "7.0"
77
+ testpaths = ["tests"]
78
+ python_files = "test_*.py"
79
+ python_classes = "Test*"
80
+ python_functions = "test_*"
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+
@@ -0,0 +1,43 @@
1
+ Metadata-Version: 2.4
2
+ Name: gis-distance-tool
3
+ Version: 0.1.0
4
+ Summary: GIS距离分析工具-基于Haversine公式计算大圆距离
5
+ Author-email: belywe-spec <belywe79@gmail.com>
6
+ License: MIT
7
+ Classifier: Development Status :: 3 - Alpha
8
+ Classifier: Intended Audience :: Science/Research
9
+ Classifier: License :: OSI Approved :: MIT License
10
+ Classifier: Programming Language :: Python :: 3
11
+ Classifier: Programming Language :: Python :: 3.8
12
+ Classifier: Programming Language :: Python :: 3.9
13
+ Classifier: Programming Language :: Python :: 3.10
14
+ Classifier: Programming Language :: Python :: 3.11
15
+ Classifier: Programming Language :: Python :: 3.12
16
+ Classifier: Topic :: Scientific/Engineering :: GIS
17
+ Requires-Python: >=3.8
18
+ Description-Content-Type: text/markdown
19
+ Provides-Extra: numpy
20
+ Requires-Dist: numpy>=1.20.0; extra == "numpy"
21
+ Provides-Extra: scipy
22
+ Requires-Dist: scipy>=1.7.0; extra == "scipy"
23
+ Provides-Extra: full
24
+ Requires-Dist: numpy>=1.20.0; extra == "full"
25
+ Requires-Dist: scipy>=1.7.0; extra == "full"
26
+ Provides-Extra: dev
27
+ Requires-Dist: pytest>=7.0.0; extra == "dev"
28
+ Requires-Dist: black>=22.0.0; extra == "dev"
29
+ Requires-Dist: flake8>=5.0.0; extra == "dev"
30
+ Requires-Dist: mypy>=0.990; extra == "dev"
31
+
32
+ # GIS Distance Tool
33
+
34
+ 一个基于 Haversine 公式的 GIS 距离计算工具,支持单点和批量计算。
35
+
36
+ # 安装
37
+
38
+ # 基础安装(无依赖)
39
+ pip install .
40
+
41
+ # 安装 NumPy 支持
42
+ pip install .[numpy]
43
+
@@ -0,0 +1,13 @@
1
+ README.md
2
+ pyproject.toml
3
+ src/gis_distance_tool.egg-info/PKG-INFO
4
+ src/gis_distance_tool.egg-info/SOURCES.txt
5
+ src/gis_distance_tool.egg-info/dependency_links.txt
6
+ src/gis_distance_tool.egg-info/entry_points.txt
7
+ src/gis_distance_tool.egg-info/requires.txt
8
+ src/gis_distance_tool.egg-info/top_level.txt
9
+ src/gis_tool/__init__.py
10
+ src/gis_tool/cli.py
11
+ src/gis_tool/core/__init__.py
12
+ src/gis_tool/core/processor.py
13
+ src/gis_tool/core/utils.py
@@ -0,0 +1,2 @@
1
+ [console_scripts]
2
+ gis-distance = gis_tool.cli:main
@@ -0,0 +1,16 @@
1
+
2
+ [dev]
3
+ pytest>=7.0.0
4
+ black>=22.0.0
5
+ flake8>=5.0.0
6
+ mypy>=0.990
7
+
8
+ [full]
9
+ numpy>=1.20.0
10
+ scipy>=1.7.0
11
+
12
+ [numpy]
13
+ numpy>=1.20.0
14
+
15
+ [scipy]
16
+ scipy>=1.7.0
File without changes
@@ -0,0 +1,142 @@
1
+ #!/usr/bin/env python3
2
+ """
3
+ GIS 距离分析工具 - 命令行入口
4
+ 使用示例:
5
+ # 单点距离计算
6
+ python cli.py single --lat1 31.23 --lon1 121.47 --lat2 39.90 --lon2 116.40
7
+
8
+ # 批量距离计算(需安装 NumPy)
9
+ python cli.py batch --coords1 31.23 121.47 39.90 116.40 --coords2 31.23 121.47 35.68 139.76
10
+ """
11
+
12
+ import argparse
13
+ import sys
14
+ from gis_tool.core.processor import haversine_distance, haversine_distance_batch
15
+
16
+
17
+ def parse_coordinates(flat_list):
18
+ """
19
+ 将扁平的坐标列表转为 [(lat, lon), ...] 格式
20
+ 例如: [31.23, 121.47, 39.90, 116.40] -> [(31.23, 121.47), (39.90, 116.40)]
21
+ """
22
+ if len(flat_list) % 2 != 0:
23
+ raise ValueError("坐标个数必须为偶数(每两个数为一组经纬度)")
24
+
25
+ coords = []
26
+ for i in range(0, len(flat_list), 2):
27
+ coords.append((flat_list[i], flat_list[i+1]))
28
+ return coords
29
+
30
+
31
+ def main():
32
+ # 创建主解析器
33
+ parser = argparse.ArgumentParser(
34
+ description="GIS 距离分析工具 - 基于 Haversine 公式计算大圆距离",
35
+ formatter_class=argparse.RawDescriptionHelpFormatter,
36
+ epilog="""
37
+ 示例:
38
+ # 单点距离(无依赖)
39
+ python cli.py single --lat1 31.2304 --lon1 121.4737 --lat2 39.9042 --lon2 116.4074
40
+
41
+ # 单点距离(输出米)
42
+ python cli.py single --lat1 31.2304 --lon1 121.4737 --lat2 39.9042 --lon2 116.4074 --unit m
43
+
44
+ # 批量距离(需安装 NumPy)
45
+ python cli.py batch --coords1 31.23 121.47 39.90 116.40 --coords2 31.23 121.47 35.68 139.76
46
+ """
47
+ )
48
+
49
+ # 添加子命令
50
+ subparsers = parser.add_subparsers(dest="command", required=True, help="计算模式")
51
+
52
+ # ---------- 子命令1: single(单点距离) ----------
53
+ parser_single = subparsers.add_parser(
54
+ "single",
55
+ help="计算两个单点之间的大圆距离(无第三方依赖)"
56
+ )
57
+ parser_single.add_argument("--lat1", type=float, required=True, help="起点纬度 (-90 ~ 90)")
58
+ parser_single.add_argument("--lon1", type=float, required=True, help="起点经度 (-180 ~ 180)")
59
+ parser_single.add_argument("--lat2", type=float, required=True, help="终点纬度 (-90 ~ 90)")
60
+ parser_single.add_argument("--lon2", type=float, required=True, help="终点经度 (-180 ~ 180)")
61
+ parser_single.add_argument(
62
+ "--unit",
63
+ type=str,
64
+ default="km",
65
+ choices=["km", "m"],
66
+ help="距离单位,默认 km"
67
+ )
68
+
69
+ # ---------- 子命令2: batch(批量距离) ----------
70
+ parser_batch = subparsers.add_parser(
71
+ "batch",
72
+ help="批量计算两组坐标间的距离(需安装 NumPy)"
73
+ )
74
+ parser_batch.add_argument(
75
+ "--coords1",
76
+ type=float,
77
+ nargs="+",
78
+ required=True,
79
+ help="第一组坐标,格式: lat1 lon1 lat2 lon2 ... (必须为偶数个)"
80
+ )
81
+ parser_batch.add_argument(
82
+ "--coords2",
83
+ type=float,
84
+ nargs="+",
85
+ required=True,
86
+ help="第二组坐标,格式: lat1 lon1 lat2 lon2 ... (必须为偶数个)"
87
+ )
88
+ parser_batch.add_argument(
89
+ "--unit",
90
+ type=str,
91
+ default="km",
92
+ choices=["km", "m"],
93
+ help="距离单位,默认 km"
94
+ )
95
+
96
+ # 解析参数
97
+ args = parser.parse_args()
98
+
99
+ try:
100
+ if args.command == "single":
101
+ # 调用基础版距离计算
102
+ result = haversine_distance(
103
+ args.lat1, args.lon1,
104
+ args.lat2, args.lon2,
105
+ args.unit
106
+ )
107
+ print(f"✅ 两点之间的大圆距离: {result:.4f} {args.unit}")
108
+
109
+ elif args.command == "batch":
110
+ # 解析坐标列表
111
+ coords1 = parse_coordinates(args.coords1)
112
+ coords2 = parse_coordinates(args.coords2)
113
+
114
+ # 调用 NumPy 版批量计算
115
+ result = haversine_distance_batch(coords1, coords2, args.unit)
116
+
117
+ # 打印结果(格式化输出)
118
+ import numpy as np
119
+ if isinstance(result, np.ndarray):
120
+ if result.ndim == 1:
121
+ print(f"✅ 逐点距离向量 (长度={len(result)}):")
122
+ for i, d in enumerate(result):
123
+ print(f" 点{i}: {d:.4f} {args.unit}")
124
+ else:
125
+ print(f"✅ 距离矩阵 (形状={result.shape}):")
126
+ print(result)
127
+ else:
128
+ print(f"✅ 距离计算结果: {result}")
129
+
130
+ except ImportError as e:
131
+ print(f"❌ 缺少依赖库: {e}", file=sys.stderr)
132
+ sys.exit(1)
133
+ except ValueError as e:
134
+ print(f"❌ 输入错误: {e}", file=sys.stderr)
135
+ sys.exit(1)
136
+ except Exception as e:
137
+ print(f"❌ 运行错误: {e}", file=sys.stderr)
138
+ sys.exit(1)
139
+
140
+
141
+ if __name__ == "__main__":
142
+ main()
File without changes
@@ -0,0 +1,101 @@
1
+ import math
2
+ from gis_tool.core.utils import validate_coordinates
3
+
4
+ # 基础版:纯 Python 实现 Haversine 距离计算
5
+ def haversine_distance(lat1: float, lon1: float, lat2: float, lon2: float, unit: str = "km") -> float:
6
+ """
7
+ 使用 Haversine 公式计算地球表面两点间的大圆距离
8
+
9
+ 参数:
10
+ lat1, lon1: 起点坐标(度)
11
+ lat2, lon2: 终点坐标(度)
12
+ unit: 输出单位,'km' 或 'm'
13
+
14
+ 返回:
15
+ 距离值(浮点数)
16
+ """
17
+ # 1. 校验坐标合法性
18
+ validate_coordinates(lat1, lon1)
19
+ validate_coordinates(lat2, lon2)
20
+
21
+ # 2. 地球平均半径(公里)
22
+ R = 6371.0
23
+
24
+ # 3. 角度转弧度
25
+ phi1 = math.radians(lat1)
26
+ phi2 = math.radians(lat2)
27
+ delta_phi = math.radians(lat2 - lat1)
28
+ delta_lambda = math.radians(lon2 - lon1)
29
+
30
+ # 4. Haversine 公式
31
+ a = math.sin(delta_phi / 2) ** 2 + \
32
+ math.cos(phi1) * math.cos(phi2) * math.sin(delta_lambda / 2) ** 2
33
+ c = 2 * math.atan2(math.sqrt(a), math.sqrt(1 - a))
34
+ distance_km = R * c
35
+
36
+ # 5. 按单位返回
37
+ return distance_km if unit == "km" else distance_km * 1000.0
38
+
39
+
40
+ # 进阶版:使用 NumPy 实现批量距离计算
41
+ def haversine_distance_batch(coords1, coords2, unit: str = "km"):
42
+ """
43
+ 使用 NumPy 批量计算两组坐标间的距离
44
+
45
+ 参数:
46
+ coords1: 第一组坐标,形状为 (N, 2),每行 [lat, lon]
47
+ coords2: 第二组坐标,形状为 (M, 2),每行 [lat, lon]
48
+ unit: 输出单位,'km' 或 'm'
49
+
50
+ 返回:
51
+ 如果 N == M: 返回长度为 N 的距离向量
52
+ 如果 N != M: 返回 N x M 的距离矩阵
53
+
54
+ 注意:
55
+ 此函数需要安装 NumPy,否则会抛出 ImportError
56
+ """
57
+ try:
58
+ import numpy as np
59
+ except ImportError:
60
+ raise ImportError(
61
+ "NumPy 未安装,请运行 'pip install numpy' 后使用此功能"
62
+ )
63
+
64
+ # 转换为 numpy 数组
65
+ arr1 = np.asarray(coords1, dtype=np.float64)
66
+ arr2 = np.asarray(coords2, dtype=np.float64)
67
+
68
+ # 检查形状
69
+ if arr1.shape[1] != 2 or arr2.shape[1] != 2:
70
+ raise ValueError("坐标数组必须为 (N, 2) 形状,每行 [lat, lon]")
71
+
72
+ # 校验所有坐标
73
+ for lat, lon in arr1:
74
+ validate_coordinates(lat, lon)
75
+ for lat, lon in arr2:
76
+ validate_coordinates(lat, lon)
77
+
78
+ # 角度转弧度
79
+ lat1 = np.radians(arr1[:, 0])
80
+ lon1 = np.radians(arr1[:, 1])
81
+ lat2 = np.radians(arr2[:, 0])
82
+ lon2 = np.radians(arr2[:, 1])
83
+
84
+ # 根据坐标数量决定计算方式
85
+ if len(arr1) == len(arr2):
86
+ # 逐点计算(一对一)
87
+ dlat = lat2 - lat1
88
+ dlon = lon2 - lon1
89
+ a = np.sin(dlat / 2) ** 2 + np.cos(lat1) * np.cos(lat2) * np.sin(dlon / 2) ** 2
90
+ c = 2 * np.arcsin(np.sqrt(np.clip(a, 0, 1))) # 防止浮点误差导致 >1
91
+ distance_km = 6371.0 * c
92
+ else:
93
+ # 计算距离矩阵(广播机制)
94
+ # 扩展维度: (N, 1) 和 (1, M) 进行广播
95
+ dlat = lat2[np.newaxis, :] - lat1[:, np.newaxis]
96
+ dlon = lon2[np.newaxis, :] - lon1[:, np.newaxis]
97
+ a = np.sin(dlat / 2) ** 2 + np.cos(lat1[:, np.newaxis]) * np.cos(lat2[np.newaxis, :]) * np.sin(dlon / 2) ** 2
98
+ c = 2 * np.arcsin(np.sqrt(np.clip(a, 0, 1)))
99
+ distance_km = 6371.0 * c
100
+
101
+ return distance_km if unit == "km" else distance_km * 1000.0
@@ -0,0 +1,8 @@
1
+ def validate_coordinates(lat: float, lon: float) -> bool:
2
+
3
+ # 校验经纬度是否在合法范围内
4
+ if not (-90 <= lat <= 90):
5
+ raise ValueError(f"纬度 {lat} 超出有效范围 [-90, 90]")
6
+ if not (-180 <= lon <= 180):
7
+ raise ValueError(f"经度 {lon} 超出有效范围 [-180, 180]")
8
+ return True