geokdtree 1.0.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,67 @@
1
+ Metadata-Version: 2.4
2
+ Name: geokdtree
3
+ Version: 1.0.0
4
+ Summary: Given a coordinate point, find a very close point given a set of coordinate points.
5
+ Author-email: Connor Makowski <conmak@mit.edu>
6
+ License-Expression: MIT
7
+ Project-URL: Homepage, https://github.com/connor-makowski/geokdtree
8
+ Project-URL: Bug Tracker, https://github.com/connor-makowski/geokdtree/issues
9
+ Project-URL: Documentation, https://connor-makowski.github.io/geokdtree/geokdtree.html
10
+ Classifier: Programming Language :: Python :: 3
11
+ Classifier: Programming Language :: C++
12
+ Classifier: Operating System :: OS Independent
13
+ Requires-Python: >=3.10
14
+ Description-Content-Type: text/markdown
15
+
16
+ # GeoKDTree
17
+ [![PyPI version](https://badge.fury.io/py/geokdtree.svg)](https://badge.fury.io/py/geokdtree)
18
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
19
+ [![PyPI Downloads](https://pepy.tech/badge/geokdtree)](https://pypi.org/project/geokdtree/)
20
+ <!-- [![PyPI Downloads](https://img.shields.io/pypi/dm/geokdtree.svg?label=PyPI%20downloads)](https://pypi.org/project/geokdtree/) -->
21
+
22
+
23
+ ### A Geo KD Tree package for Python
24
+
25
+
26
+ ![geokdtree](https://raw.githubusercontent.com/connor-makowski/geokdtree/main/static/geokdtree.png)
27
+
28
+ ## Quick Start:
29
+ ```py
30
+ from geokdtree import GeoKDTree
31
+
32
+ example_points = [
33
+ (34.0522, -118.2437), # Los Angeles
34
+ (40.7128, -74.0060), # New York
35
+ (37.7749, -122.4194), # San Francisco
36
+ (51.5074, -0.1278), # London
37
+ (48.8566, 2.3522), # Paris
38
+ ]
39
+
40
+ geo_kd_tree = GeoKDTree(points = example_points)
41
+ test_point = (47.6062, -122.3321) # Seattle
42
+
43
+ closest_idx = geo_kd_tree.closest_idx(test_point) # Expect San Francisco to be closest
44
+ print(f"Closest point to {test_point} is {example_points[closest_idx] }")
45
+ ```
46
+
47
+ ### Documentation
48
+
49
+ - Docs: https://connor-makowski.github.io/geokdtree/geokdtree.html
50
+ - Git Repo: https://github.com/connor-makowski/geokdtree
51
+
52
+ # Development
53
+ ## Running Tests, Prettifying Code, and Updating Docs
54
+
55
+ Make sure Docker is installed and running on a Unix system (Linux, MacOS, WSL2).
56
+
57
+ - Create a docker container and drop into a shell
58
+ - `./run.sh`
59
+ - Run all tests (see ./utils/test.sh)
60
+ - `./run.sh test`
61
+ - Prettify the code (see ./utils/prettify.sh)
62
+ - `./run.sh prettify`
63
+ - Update the docs (see ./utils/docs.sh)
64
+ - `./run.sh docs`
65
+
66
+ - Note: You can and should modify the `Dockerfile` to test different python versions.
67
+
@@ -0,0 +1,52 @@
1
+ # GeoKDTree
2
+ [![PyPI version](https://badge.fury.io/py/geokdtree.svg)](https://badge.fury.io/py/geokdtree)
3
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
4
+ [![PyPI Downloads](https://pepy.tech/badge/geokdtree)](https://pypi.org/project/geokdtree/)
5
+ <!-- [![PyPI Downloads](https://img.shields.io/pypi/dm/geokdtree.svg?label=PyPI%20downloads)](https://pypi.org/project/geokdtree/) -->
6
+
7
+
8
+ ### A Geo KD Tree package for Python
9
+
10
+
11
+ ![geokdtree](https://raw.githubusercontent.com/connor-makowski/geokdtree/main/static/geokdtree.png)
12
+
13
+ ## Quick Start:
14
+ ```py
15
+ from geokdtree import GeoKDTree
16
+
17
+ example_points = [
18
+ (34.0522, -118.2437), # Los Angeles
19
+ (40.7128, -74.0060), # New York
20
+ (37.7749, -122.4194), # San Francisco
21
+ (51.5074, -0.1278), # London
22
+ (48.8566, 2.3522), # Paris
23
+ ]
24
+
25
+ geo_kd_tree = GeoKDTree(points = example_points)
26
+ test_point = (47.6062, -122.3321) # Seattle
27
+
28
+ closest_idx = geo_kd_tree.closest_idx(test_point) # Expect San Francisco to be closest
29
+ print(f"Closest point to {test_point} is {example_points[closest_idx] }")
30
+ ```
31
+
32
+ ### Documentation
33
+
34
+ - Docs: https://connor-makowski.github.io/geokdtree/geokdtree.html
35
+ - Git Repo: https://github.com/connor-makowski/geokdtree
36
+
37
+ # Development
38
+ ## Running Tests, Prettifying Code, and Updating Docs
39
+
40
+ Make sure Docker is installed and running on a Unix system (Linux, MacOS, WSL2).
41
+
42
+ - Create a docker container and drop into a shell
43
+ - `./run.sh`
44
+ - Run all tests (see ./utils/test.sh)
45
+ - `./run.sh test`
46
+ - Prettify the code (see ./utils/prettify.sh)
47
+ - `./run.sh prettify`
48
+ - Update the docs (see ./utils/docs.sh)
49
+ - `./run.sh docs`
50
+
51
+ - Note: You can and should modify the `Dockerfile` to test different python versions.
52
+
@@ -0,0 +1,56 @@
1
+ """
2
+ # GeoKDTree
3
+ [![PyPI version](https://badge.fury.io/py/geokdtree.svg)](https://badge.fury.io/py/geokdtree)
4
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
5
+ [![PyPI Downloads](https://pepy.tech/badge/geokdtree)](https://pypi.org/project/geokdtree/)
6
+ <!-- [![PyPI Downloads](https://img.shields.io/pypi/dm/geokdtree.svg?label=PyPI%20downloads)](https://pypi.org/project/geokdtree/) -->
7
+
8
+
9
+ ### A Geo KD Tree package for Python
10
+
11
+
12
+ ![geokdtree](https://raw.githubusercontent.com/connor-makowski/geokdtree/main/static/geokdtree.png)
13
+
14
+ ## Quick Start:
15
+ ```py
16
+ from geokdtree import GeoKDTree
17
+
18
+ example_points = [
19
+ (34.0522, -118.2437), # Los Angeles
20
+ (40.7128, -74.0060), # New York
21
+ (37.7749, -122.4194), # San Francisco
22
+ (51.5074, -0.1278), # London
23
+ (48.8566, 2.3522), # Paris
24
+ ]
25
+
26
+ geo_kd_tree = GeoKDTree(points = example_points)
27
+ test_point = (47.6062, -122.3321) # Seattle
28
+
29
+ closest_idx = geo_kd_tree.closest_idx(test_point) # Expect San Francisco to be closest
30
+ print(f"Closest point to {test_point} is {example_points[closest_idx] }")
31
+ ```
32
+
33
+ ### Documentation
34
+
35
+ - Docs: https://connor-makowski.github.io/geokdtree/geokdtree.html
36
+ - Git Repo: https://github.com/connor-makowski/geokdtree
37
+
38
+ # Development
39
+ ## Running Tests, Prettifying Code, and Updating Docs
40
+
41
+ Make sure Docker is installed and running on a Unix system (Linux, MacOS, WSL2).
42
+
43
+ - Create a docker container and drop into a shell
44
+ - `./run.sh`
45
+ - Run all tests (see ./utils/test.sh)
46
+ - `./run.sh test`
47
+ - Prettify the code (see ./utils/prettify.sh)
48
+ - `./run.sh prettify`
49
+ - Update the docs (see ./utils/docs.sh)
50
+ - `./run.sh docs`
51
+
52
+ - Note: You can and should modify the `Dockerfile` to test different python versions.
53
+
54
+ """
55
+
56
+ from .core import KDTree, GeoKDTree
File without changes
@@ -0,0 +1,345 @@
1
+ from math import pi, cos, sin
2
+
3
+
4
+ def kdtree(points, depth=0, axis_count=2):
5
+ """
6
+ Function:
7
+
8
+ - Build a KDTree from a list of points.
9
+
10
+ Required Arguments:
11
+
12
+ - `points`
13
+ - Type: list of tuples
14
+ - What: A list of points to build the KDTree from
15
+
16
+ Optional Arguments:
17
+
18
+ - `depth`
19
+ - Type: int
20
+ - What: The current depth in the tree (used for axis selection)
21
+ - `axis_count`
22
+ - Type: int
23
+ - What: The number of dimensions in the points (default is 2 for 2D points)
24
+
25
+ Returns:
26
+
27
+ - The constructed KDTree as a tuple in the format (point, axis, left, right).
28
+ - Where left and right are subtrees.
29
+ """
30
+ if not points:
31
+ return 0
32
+ axis = depth % axis_count
33
+ points.sort(key=lambda p: p[axis])
34
+ median = len(points) // 2
35
+ return (
36
+ points[median],
37
+ axis,
38
+ kdtree(points[:median], depth + 1),
39
+ kdtree(points[median + 1 :], depth + 1),
40
+ )
41
+
42
+
43
+ def squared_distance(p1, p2, axis_count=2):
44
+ """
45
+ Function:
46
+
47
+ - Calculate the squared distance between two points.
48
+
49
+ Required Arguments:
50
+
51
+ - `p1`
52
+ - Type: tuple
53
+ - What: The first point
54
+ - `p2`
55
+ - Type: tuple
56
+ - What: The second point
57
+
58
+ Optional Arguments:
59
+
60
+ - `axis_count`
61
+ - Type: int
62
+ - What: The number of dimensions in the points
63
+ - Default: 2 (for 2D points)
64
+
65
+ Returns:
66
+
67
+ - The squared distance between the two points.
68
+ """
69
+ return sum([(p1[i] - p2[i]) ** 2 for i in range(axis_count)])
70
+
71
+
72
+ def closest_point(
73
+ node, point, depth=0, best=None, axis_count=2, best_dist=float("inf")
74
+ ):
75
+ """
76
+ Function:
77
+
78
+ - Find the closest point in the KDTree to a given point.
79
+
80
+ Required Arguments:
81
+
82
+ - `node`
83
+ - Type: tuple
84
+ - What: The node of the KDTree
85
+ - `point`
86
+ - Type: tuple
87
+ - What: The point to find the closest point to
88
+
89
+ Optional Arguments:
90
+
91
+ - `depth`
92
+ - Type: int
93
+ - What: The current depth in the tree (used for axis selection)
94
+ - `best`
95
+ - Type: tuple or None
96
+ - What: The best point found so far (default is None)
97
+ - `axis_count`
98
+ - Type: int
99
+ - What: The number of dimensions in the points (default is 2 for 2D points)
100
+ - `best_dist`
101
+ - Type: float
102
+ - What: The best distance found so far (default is infinity)
103
+
104
+ Returns:
105
+
106
+ - The closest point found in the KDTree to the given point.
107
+ """
108
+ if node == 0:
109
+ return best, best_dist
110
+ # Get the median node and its distance
111
+ median_node = node[0]
112
+ median_node_dist = squared_distance(
113
+ point, median_node, axis_count=axis_count
114
+ )
115
+ # Update the best point and distance if necessary
116
+ if best is None or median_node_dist < best_dist:
117
+ best = median_node
118
+ best_dist = median_node_dist
119
+ # Calculate the difference for node selection given the current axis
120
+ axis = node[1]
121
+ diff = point[axis] - median_node[axis]
122
+ # Choose side to search
123
+ close, away = (node[2], node[3]) if diff < 0 else (node[3], node[2])
124
+ # Search the close side first
125
+ best, best_dist = closest_point(
126
+ close,
127
+ point,
128
+ depth + 1,
129
+ best,
130
+ axis_count=axis_count,
131
+ best_dist=best_dist,
132
+ )
133
+ # Check the other side if needed
134
+ if diff**2 < best_dist:
135
+ best, best_dist = closest_point(
136
+ away,
137
+ point,
138
+ depth + 1,
139
+ best,
140
+ axis_count=axis_count,
141
+ best_dist=best_dist,
142
+ )
143
+ return best, best_dist
144
+
145
+
146
+ def squared_distance_3d(p1, p2):
147
+ """
148
+ Function:
149
+
150
+ - Calculate the squared distance between two 3D points.
151
+
152
+ Required Arguments:
153
+
154
+ - `p1`
155
+ - Type: tuple
156
+ - What: The first point in 3D space
157
+ - `p2`
158
+ - Type: tuple
159
+ - What: The second point in 3D space
160
+
161
+ Returns:
162
+
163
+ - The squared distance between the two 3D points.
164
+ """
165
+ return sum(
166
+ [(p1[0] - p2[0]) ** 2, (p1[1] - p2[1]) ** 2, (p1[2] - p2[2]) ** 2]
167
+ )
168
+
169
+
170
+ def closest_point_3d(node, point, depth=0, best=None, best_dist=float("inf")):
171
+ """
172
+ Function:
173
+
174
+ - Find the closest point in the KDTree to a given point.
175
+
176
+ Required Arguments:
177
+
178
+ - `node`
179
+ - Type: tuple
180
+ - What: The node of the KDTree
181
+ - `point`
182
+ - Type: tuple
183
+ - What: The point to find the closest point to
184
+
185
+ Optional Arguments:
186
+
187
+ - `depth`
188
+ - Type: int
189
+ - What: The current depth in the tree (used for axis selection)
190
+ - `best`
191
+ - Type: tuple or None
192
+ - What: The best point found so far (default is None)
193
+ - `best_dist`
194
+ - Type: float
195
+ - What: The best distance found so far (default is infinity)
196
+
197
+ Returns:
198
+
199
+ - The closest point found in the KDTree to the given point.
200
+ """
201
+ if node == 0:
202
+ return best, best_dist
203
+ # Get the median node and its distance
204
+ median_node = node[0]
205
+ median_node_dist = squared_distance_3d(point, median_node)
206
+ # Update the best point and distance if necessary
207
+ if best is None or median_node_dist < best_dist:
208
+ best = median_node
209
+ best_dist = median_node_dist
210
+ # Calculate the difference for node selection given the current axis
211
+ axis = node[1]
212
+ diff = point[axis] - median_node[axis]
213
+ # Choose side to search
214
+ close, away = (node[2], node[3]) if diff < 0 else (node[3], node[2])
215
+ # Search the close side first
216
+ best, best_dist = closest_point_3d(close, point, depth + 1, best, best_dist)
217
+ # Check the other side if needed
218
+ if diff**2 < best_dist:
219
+ best, best_dist = closest_point_3d(
220
+ away, point, depth + 1, best, best_dist
221
+ )
222
+ return best, best_dist
223
+
224
+
225
+ class KDTree:
226
+ def __init__(self, points):
227
+ """
228
+ Function:
229
+
230
+ - Build a KDTree from a list of points.
231
+
232
+ Required Arguments:
233
+
234
+ - `points`
235
+ - Type: list of tuples
236
+ - What: A list of points to build the KDTree from
237
+
238
+ Returns:
239
+
240
+ - A KDTree object that can be used to find the closest point to a given point.
241
+ """
242
+ self.tree = kdtree(points, axis_count=len(points[0]))
243
+
244
+ def closest_point(self, point):
245
+ """
246
+ Function:
247
+
248
+ - Find the closest point in the KDTree to a given point.
249
+
250
+ Required Arguments:
251
+
252
+ - `point`
253
+ - Type: tuple
254
+ - What: The point to find the closest point to
255
+
256
+ Returns:
257
+
258
+ - The closest point found in the KDTree to the given point.
259
+ """
260
+ return closest_point(self.tree, point)[
261
+ 0
262
+ ] # Return only the point, not the distance
263
+
264
+
265
+ class GeoKDTree:
266
+ def __init__(self, points: list[tuple]):
267
+ """
268
+ Function:
269
+
270
+ - Build a GeoKDTree from a list of latitude and longitude points or an existing KDTree.
271
+
272
+ Required Arguments:
273
+
274
+ - `points`
275
+ - Type: list of tuples
276
+ - What: A list of latitude and longitude points to build the GeoKDTree from
277
+ - The points should be in the format [(lat1, lon1), (lat2, lon2), ...].
278
+
279
+ Returns:
280
+
281
+ - A GeoKDTree object that can be used to find the closest point to a given latitude and longitude.
282
+ - The points should be in the format [(lat1, lon1), (lat2, lon2), ...].
283
+ """
284
+ self.tree = kdtree(
285
+ [
286
+ GeoKDTree.lat_lon_idx_to_xyz_idx(point[0], point[1], idx)
287
+ for idx, point in enumerate(points)
288
+ ],
289
+ axis_count=3,
290
+ )
291
+
292
+ def closest_idx(self, point: tuple):
293
+ """
294
+ Function:
295
+
296
+ - Find the index of the closest point in the GeoKDTree to a given latitude and longitude point.
297
+
298
+ Required Arguments:
299
+
300
+ - `point`
301
+ - Type: tuple
302
+ - What: The latitude and longitude point to find the closest point to
303
+
304
+ Returns:
305
+
306
+ - The index of the closest point found in the GeoKDTree to the given latitude and longitude point.
307
+ """
308
+ return closest_point_3d(
309
+ self.tree,
310
+ GeoKDTree.lat_lon_idx_to_xyz_idx(point[0], point[1]),
311
+ )[0][
312
+ 3
313
+ ] # Return the point [0] and the index of the point [3]
314
+
315
+ @staticmethod
316
+ def lat_lon_idx_to_xyz_idx(
317
+ lat: int | float, lon: int | float, idx: int = 0
318
+ ):
319
+ """
320
+ Function:
321
+
322
+ - Convert latitude and longitude to Cartesian coordinates (x, y, z) and include an index.
323
+
324
+ Required Arguments:
325
+
326
+ - `lat`
327
+ - Type: int or float
328
+ - What: The latitude in degrees
329
+ - `lon`
330
+ - Type: int or float
331
+ - What: The longitude in degrees
332
+
333
+ Optional Arguments:
334
+
335
+ - `idx`
336
+ - Type: int
337
+ - What: An index to include with the coordinates (default is 0)
338
+ """
339
+ lat_rad = lat * pi / 180
340
+ lon_rad = lon * pi / 180
341
+ cos_lat = cos(lat_rad)
342
+ x = cos_lat * cos(lon_rad)
343
+ y = cos_lat * sin(lon_rad)
344
+ z = sin(lat_rad)
345
+ return (x, y, z, idx)
@@ -0,0 +1,67 @@
1
+ Metadata-Version: 2.4
2
+ Name: geokdtree
3
+ Version: 1.0.0
4
+ Summary: Given a coordinate point, find a very close point given a set of coordinate points.
5
+ Author-email: Connor Makowski <conmak@mit.edu>
6
+ License-Expression: MIT
7
+ Project-URL: Homepage, https://github.com/connor-makowski/geokdtree
8
+ Project-URL: Bug Tracker, https://github.com/connor-makowski/geokdtree/issues
9
+ Project-URL: Documentation, https://connor-makowski.github.io/geokdtree/geokdtree.html
10
+ Classifier: Programming Language :: Python :: 3
11
+ Classifier: Programming Language :: C++
12
+ Classifier: Operating System :: OS Independent
13
+ Requires-Python: >=3.10
14
+ Description-Content-Type: text/markdown
15
+
16
+ # GeoKDTree
17
+ [![PyPI version](https://badge.fury.io/py/geokdtree.svg)](https://badge.fury.io/py/geokdtree)
18
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
19
+ [![PyPI Downloads](https://pepy.tech/badge/geokdtree)](https://pypi.org/project/geokdtree/)
20
+ <!-- [![PyPI Downloads](https://img.shields.io/pypi/dm/geokdtree.svg?label=PyPI%20downloads)](https://pypi.org/project/geokdtree/) -->
21
+
22
+
23
+ ### A Geo KD Tree package for Python
24
+
25
+
26
+ ![geokdtree](https://raw.githubusercontent.com/connor-makowski/geokdtree/main/static/geokdtree.png)
27
+
28
+ ## Quick Start:
29
+ ```py
30
+ from geokdtree import GeoKDTree
31
+
32
+ example_points = [
33
+ (34.0522, -118.2437), # Los Angeles
34
+ (40.7128, -74.0060), # New York
35
+ (37.7749, -122.4194), # San Francisco
36
+ (51.5074, -0.1278), # London
37
+ (48.8566, 2.3522), # Paris
38
+ ]
39
+
40
+ geo_kd_tree = GeoKDTree(points = example_points)
41
+ test_point = (47.6062, -122.3321) # Seattle
42
+
43
+ closest_idx = geo_kd_tree.closest_idx(test_point) # Expect San Francisco to be closest
44
+ print(f"Closest point to {test_point} is {example_points[closest_idx] }")
45
+ ```
46
+
47
+ ### Documentation
48
+
49
+ - Docs: https://connor-makowski.github.io/geokdtree/geokdtree.html
50
+ - Git Repo: https://github.com/connor-makowski/geokdtree
51
+
52
+ # Development
53
+ ## Running Tests, Prettifying Code, and Updating Docs
54
+
55
+ Make sure Docker is installed and running on a Unix system (Linux, MacOS, WSL2).
56
+
57
+ - Create a docker container and drop into a shell
58
+ - `./run.sh`
59
+ - Run all tests (see ./utils/test.sh)
60
+ - `./run.sh test`
61
+ - Prettify the code (see ./utils/prettify.sh)
62
+ - `./run.sh prettify`
63
+ - Update the docs (see ./utils/docs.sh)
64
+ - `./run.sh docs`
65
+
66
+ - Note: You can and should modify the `Dockerfile` to test different python versions.
67
+
@@ -0,0 +1,10 @@
1
+ README.md
2
+ pyproject.toml
3
+ setup.cfg
4
+ geokdtree/__init__.py
5
+ geokdtree/core.py
6
+ geokdtree.egg-info/PKG-INFO
7
+ geokdtree.egg-info/SOURCES.txt
8
+ geokdtree.egg-info/dependency_links.txt
9
+ geokdtree.egg-info/top_level.txt
10
+ geokdtree/bin/__init__.py
@@ -0,0 +1 @@
1
+ geokdtree
@@ -0,0 +1,33 @@
1
+ [tool.black]
2
+ line-length = 80
3
+ target-version = ['py312']
4
+ exclude = '/.*(migrations|__pycache__).*/'
5
+
6
+ [tool.setuptools]
7
+ py-modules = ["geokdtree"]
8
+
9
+ [build-system]
10
+ requires = ["setuptools>=61.0"]
11
+ build-backend = "setuptools.build_meta"
12
+
13
+ [project]
14
+ name = "geokdtree"
15
+ version = "1.0.0"
16
+ description = "Given a coordinate point, find a very close point given a set of coordinate points."
17
+ authors = [
18
+ {name="Connor Makowski", email="conmak@mit.edu"}
19
+ ]
20
+ readme = "README.md"
21
+ requires-python = ">=3.10"
22
+ license="MIT"
23
+ classifiers = [
24
+ "Programming Language :: Python :: 3",
25
+ "Programming Language :: C++",
26
+ "Operating System :: OS Independent",
27
+ ]
28
+ dependencies = []
29
+
30
+ [project.urls]
31
+ "Homepage" = "https://github.com/connor-makowski/geokdtree"
32
+ "Bug Tracker" = "https://github.com/connor-makowski/geokdtree/issues"
33
+ "Documentation" = "https://connor-makowski.github.io/geokdtree/geokdtree.html"
@@ -0,0 +1,12 @@
1
+ [metadata]
2
+ name = geokdtree
3
+ version = 2.15.0
4
+ description_file = README.md
5
+
6
+ [options]
7
+ packages = find:
8
+
9
+ [egg_info]
10
+ tag_build =
11
+ tag_date = 0
12
+