togo 0.2.6__cp314-cp314-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl
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,339 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: togo
|
|
3
|
+
Version: 0.2.6
|
|
4
|
+
Summary: Lightweight Python bindings for the TG geometry library
|
|
5
|
+
Author-email: Giorgio Salluzzo <giorgio.salluzzo@gmail.com>
|
|
6
|
+
License: MIT
|
|
7
|
+
Project-URL: Homepage, https://github.com/mindflayer/togo
|
|
8
|
+
Project-URL: Source, https://github.com/mindflayer/togo
|
|
9
|
+
Project-URL: Tracker, https://github.com/mindflayer/togo/issues
|
|
10
|
+
Classifier: Programming Language :: Python :: 3
|
|
11
|
+
Classifier: Programming Language :: C
|
|
12
|
+
Classifier: Operating System :: POSIX :: Linux
|
|
13
|
+
Classifier: Intended Audience :: Developers
|
|
14
|
+
Classifier: Topic :: Scientific/Engineering :: GIS
|
|
15
|
+
Requires-Python: >=3.8
|
|
16
|
+
Description-Content-Type: text/markdown
|
|
17
|
+
License-File: LICENSE
|
|
18
|
+
Dynamic: license
|
|
19
|
+
Dynamic: license-file
|
|
20
|
+
|
|
21
|
+
<img src="togo.png" width="256px">
|
|
22
|
+
|
|
23
|
+
Python bindings for [TG](https://github.com/tidwall/tg)
|
|
24
|
+
(Geometry library for C - Fast point-in-polygon)
|
|
25
|
+
|
|
26
|
+
ToGo is a high-performance Python library for computational geometry, providing a Cython wrapper around the above-mentioned C library.
|
|
27
|
+
|
|
28
|
+
The main goal is to offer a Pythonic, object-oriented, fast and memory-efficient library for geometric operations, including spatial predicates, format conversions, and spatial indexing. ToGo's API is flexible and allows you to reason in either TG concepts (if you're familiar with the TG library) or Shapely conventions (the de facto standard for geospatial work in Python)—whichever fits your workflow best.
|
|
29
|
+
|
|
30
|
+
See [SHAPELY_API.md](SHAPELY_API.md) for more details on Shapely compatibility.
|
|
31
|
+
|
|
32
|
+
## Installation
|
|
33
|
+
|
|
34
|
+
```bash
|
|
35
|
+
pip install togo
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
## Features
|
|
39
|
+
|
|
40
|
+
- Fast and efficient geometric operations
|
|
41
|
+
- Support for standard geometry types: Point, Line, Ring, Polygon, and their multi-variants
|
|
42
|
+
- Flexible API supporting both TG and Shapely conventions
|
|
43
|
+
- Geometric predicates: contains, intersects, covers, touches, etc.
|
|
44
|
+
- Format conversion between WKT, GeoJSON, WKB, and HEX
|
|
45
|
+
- Spatial indexing for accelerated queries
|
|
46
|
+
- Memory-efficient C implementation with Python-friendly interface
|
|
47
|
+
- Advanced operations via libgeos integration (buffer, unary union, etc.)
|
|
48
|
+
|
|
49
|
+
## Basic Usage
|
|
50
|
+
|
|
51
|
+
ToGo's API supports multiple styles of interaction. You can use Shapely-like conventions for familiarity, TG-like conventions if you're already familiar with that library, or mix both as needed.
|
|
52
|
+
|
|
53
|
+
### Creating Geometries
|
|
54
|
+
|
|
55
|
+
```python
|
|
56
|
+
from togo import Point, LineString, Polygon, Ring, Poly, Geometry
|
|
57
|
+
|
|
58
|
+
# Shapely-like syntax
|
|
59
|
+
point = Point(1.0, 2.0)
|
|
60
|
+
line = LineString([(0, 0), (1, 1), (2, 2)])
|
|
61
|
+
poly = Polygon([(0, 0), (4, 0), (4, 4), (0, 4), (0, 0)])
|
|
62
|
+
|
|
63
|
+
# TG-like syntax with Ring and Poly
|
|
64
|
+
ring = Ring([(0,0), (10,0), (10,10), (0,10), (0,0)])
|
|
65
|
+
polygon = Poly(ring)
|
|
66
|
+
|
|
67
|
+
# Direct Geometry creation from formats
|
|
68
|
+
geom = Geometry("POINT(1 2)", fmt='wkt')
|
|
69
|
+
geom2 = Geometry('{"type":"Point","coordinates":[1,2]}', fmt='geojson')
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
### Working with Geometries
|
|
73
|
+
|
|
74
|
+
```python
|
|
75
|
+
from togo import Point, Polygon
|
|
76
|
+
|
|
77
|
+
# Access properties (works with both API styles)
|
|
78
|
+
point = Point(1.0, 2.0)
|
|
79
|
+
print(point.geom_type) # 'Point'
|
|
80
|
+
print(point.bounds) # (1.0, 2.0, 1.0, 2.0)
|
|
81
|
+
|
|
82
|
+
poly = Polygon([(0, 0), (4, 0), (4, 4), (0, 4), (0, 0)])
|
|
83
|
+
print(poly.area) # 16.0
|
|
84
|
+
print(poly.length) # 16.0
|
|
85
|
+
|
|
86
|
+
# Convert between formats
|
|
87
|
+
print(point.to_wkt()) # 'POINT (1 2)'
|
|
88
|
+
print(point.to_geojson()) # '{"type":"Point","coordinates":[1.0,2.0]}'
|
|
89
|
+
|
|
90
|
+
# Spatial predicates
|
|
91
|
+
if poly.contains(point):
|
|
92
|
+
print("Polygon contains point!")
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
|
|
96
|
+
## Core Classes
|
|
97
|
+
|
|
98
|
+
### Geometry
|
|
99
|
+
|
|
100
|
+
The base class that wraps tg_geom structures and provides core operations:
|
|
101
|
+
|
|
102
|
+
```python
|
|
103
|
+
# Create from various formats
|
|
104
|
+
g1 = Geometry('POINT(1 2)', fmt='wkt')
|
|
105
|
+
g2 = Geometry('{"type":"Point","coordinates":[1,2]}', fmt='geojson')
|
|
106
|
+
|
|
107
|
+
# Geometric predicates
|
|
108
|
+
g1.intersects(g2)
|
|
109
|
+
g1.contains(g2)
|
|
110
|
+
g1.within(g2)
|
|
111
|
+
|
|
112
|
+
# Format conversion
|
|
113
|
+
g1.to_wkt()
|
|
114
|
+
g1.to_geojson()
|
|
115
|
+
|
|
116
|
+
# Access sub-geometries by index (e.g., for GeometryCollection, MultiPoint, etc.)
|
|
117
|
+
gc = Geometry('GEOMETRYCOLLECTION(POINT(1 2),POINT(3 4))', fmt='wkt')
|
|
118
|
+
first = gc[0] # Bound to TG function call tg_geom_geometry_at(idx)
|
|
119
|
+
second = gc[1]
|
|
120
|
+
print(first.type_string()) # 'Point'
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
### Point
|
|
124
|
+
|
|
125
|
+
```python
|
|
126
|
+
from togo import Point
|
|
127
|
+
|
|
128
|
+
# Create a point
|
|
129
|
+
p = Point(1.0, 2.0)
|
|
130
|
+
|
|
131
|
+
# Access coordinates
|
|
132
|
+
print(f"X: {p.x}, Y: {p.y}")
|
|
133
|
+
|
|
134
|
+
# Get as a tuple
|
|
135
|
+
print(p.as_tuple())
|
|
136
|
+
|
|
137
|
+
# Convert to a Geometry object
|
|
138
|
+
geom = p.as_geometry()
|
|
139
|
+
print(geom.type_string())
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
### Segment
|
|
143
|
+
|
|
144
|
+
```python
|
|
145
|
+
from togo import Segment, Point
|
|
146
|
+
|
|
147
|
+
# Create a segment from two points (or tuples)
|
|
148
|
+
seg = Segment(Point(0, 0), Point(1, 1))
|
|
149
|
+
# Or using tuples
|
|
150
|
+
tuple_seg = Segment((0, 0), (1, 1))
|
|
151
|
+
|
|
152
|
+
# Access endpoints
|
|
153
|
+
print(seg.a) # Point(0, 0)
|
|
154
|
+
print(seg.b) # Point(1, 1)
|
|
155
|
+
|
|
156
|
+
# Get the bounding rectangle
|
|
157
|
+
rect = seg.rect()
|
|
158
|
+
print(rect) # ((0.0, 0.0), (1.0, 1.0))
|
|
159
|
+
|
|
160
|
+
# Check intersection with another segment
|
|
161
|
+
other = Segment((1, 1), (2, 2))
|
|
162
|
+
print(seg.intersects(other)) # True or False
|
|
163
|
+
```
|
|
164
|
+
|
|
165
|
+
### Line
|
|
166
|
+
|
|
167
|
+
```python
|
|
168
|
+
from togo import Line
|
|
169
|
+
|
|
170
|
+
# Create a line from a list of tuples
|
|
171
|
+
line = Line([(0,0), (1,1), (2,0)])
|
|
172
|
+
|
|
173
|
+
# Get number of points
|
|
174
|
+
print(f"Number of points: {line.num_points}")
|
|
175
|
+
|
|
176
|
+
# Get all points as a list of tuples
|
|
177
|
+
print(f"Points: {line.points()}")
|
|
178
|
+
|
|
179
|
+
# Get the length of the line
|
|
180
|
+
print(f"Length: {line.length}")
|
|
181
|
+
|
|
182
|
+
# Get the bounding box
|
|
183
|
+
print(f"Bounding box: {line.rect()}")
|
|
184
|
+
|
|
185
|
+
# Get a point by index
|
|
186
|
+
print(f"First point: {line[0].as_tuple()}")
|
|
187
|
+
```
|
|
188
|
+
|
|
189
|
+
### Ring
|
|
190
|
+
|
|
191
|
+
```python
|
|
192
|
+
from togo import Ring
|
|
193
|
+
|
|
194
|
+
# Create a ring (must be closed)
|
|
195
|
+
ring = Ring([(0,0), (10,0), (10,10), (0,10), (0,0)])
|
|
196
|
+
|
|
197
|
+
# Get area and perimeter
|
|
198
|
+
print(f"Area: {ring.area}")
|
|
199
|
+
print(f"Perimeter: {ring.length}")
|
|
200
|
+
|
|
201
|
+
# Check if it's convex or clockwise
|
|
202
|
+
print(f"Is convex: {ring.is_convex()}")
|
|
203
|
+
print(f"Is clockwise: {ring.is_clockwise()}")
|
|
204
|
+
|
|
205
|
+
# Get bounding box
|
|
206
|
+
min_pt, max_pt = ring.rect().min, ring.rect().max
|
|
207
|
+
print(f"Bounding box: {min_pt.as_tuple()}, {max_pt.as_tuple()}")
|
|
208
|
+
```
|
|
209
|
+
|
|
210
|
+
### Poly
|
|
211
|
+
|
|
212
|
+
```python
|
|
213
|
+
from togo import Poly, Ring, Point
|
|
214
|
+
|
|
215
|
+
# Create a polygon with one exterior ring and one interior hole
|
|
216
|
+
exterior = Ring([(0,0), (10,0), (10,10), (0,10), (0,0)])
|
|
217
|
+
hole1 = Ring([(1,1), (2,1), (2,2), (1,2), (1,1)])
|
|
218
|
+
poly = Poly(exterior, holes=[hole1])
|
|
219
|
+
|
|
220
|
+
# Get the exterior ring
|
|
221
|
+
ext_ring = poly.exterior
|
|
222
|
+
print(f"Exterior has {ext_ring.num_points} points")
|
|
223
|
+
|
|
224
|
+
# Get number of holes
|
|
225
|
+
print(f"Number of holes: {poly.num_holes()}")
|
|
226
|
+
|
|
227
|
+
# Get a hole by index
|
|
228
|
+
h = poly.hole(0)
|
|
229
|
+
print(f"Hole area: {h.area()}")
|
|
230
|
+
|
|
231
|
+
# A polygon is a geometry, so you can use geometry methods
|
|
232
|
+
geom = poly.as_geometry()
|
|
233
|
+
print(f"Contains point (5,5): {geom.contains(Point(5,5).as_geometry())}")
|
|
234
|
+
# Point is inside the hole, so it is not contained by the polygon
|
|
235
|
+
print(f"Contains point (1.5,1.5): {geom.contains(Point(1.5,1.5).as_geometry())}")
|
|
236
|
+
```
|
|
237
|
+
|
|
238
|
+
### MultiGeometries
|
|
239
|
+
|
|
240
|
+
Creating collections of geometries:
|
|
241
|
+
|
|
242
|
+
```python
|
|
243
|
+
from togo import Geometry, Point, Line, Poly, Ring
|
|
244
|
+
|
|
245
|
+
# Create a MultiPoint
|
|
246
|
+
multi_point = Geometry.from_multipoint([(0,0), (1,1), Point(2,2)])
|
|
247
|
+
|
|
248
|
+
# Create a MultiLineString
|
|
249
|
+
multi_line = Geometry.from_multilinestring([
|
|
250
|
+
[(0,0), (1,1)],
|
|
251
|
+
Line([(2,2), (3,3)])
|
|
252
|
+
])
|
|
253
|
+
|
|
254
|
+
# Create a MultiPolygon
|
|
255
|
+
poly1 = Poly(Ring([(0,0), (1,0), (1,1), (0,1), (0,0)]))
|
|
256
|
+
poly2 = Poly(Ring([(2,2), (3,2), (3,3), (2,3), (2,2)]))
|
|
257
|
+
multi_poly = Geometry.from_multipolygon([poly1, poly2])
|
|
258
|
+
```
|
|
259
|
+
|
|
260
|
+
## Polygon Indexing
|
|
261
|
+
|
|
262
|
+
Togo supports different polygon indexing strategies for optimized spatial operations:
|
|
263
|
+
|
|
264
|
+
```python
|
|
265
|
+
from togo import TGIndex, set_polygon_indexing_mode
|
|
266
|
+
|
|
267
|
+
# Set the indexing mode
|
|
268
|
+
set_polygon_indexing_mode(TGIndex.NATURAL) # or NONE, YSTRIPES
|
|
269
|
+
```
|
|
270
|
+
|
|
271
|
+
## Integration with tgx and libgeos
|
|
272
|
+
|
|
273
|
+
Togo integrates with the [tgx](https://github.com/tidwall/tgx) extension and [libgeos](https://libgeos.org/) to provide advanced geometry operations, such as topological unions and conversions between TG and GEOS geometry formats. This allows you to leverage the speed of TG for basic operations and the flexibility of GEOS for more complex tasks.
|
|
274
|
+
|
|
275
|
+
### Example: Unary Union (GEOS integration)
|
|
276
|
+
|
|
277
|
+
The `unary_union` method demonstrates this integration. It combines multiple geometries into a single geometry using GEOS's topological union, with all conversions handled automatically:
|
|
278
|
+
|
|
279
|
+
```python
|
|
280
|
+
from togo import Geometry, Point, Poly, Ring
|
|
281
|
+
|
|
282
|
+
# Create several polygons
|
|
283
|
+
poly1 = Poly(Ring([(0,0), (2,0), (2,2), (0,2), (0,0)]))
|
|
284
|
+
poly2 = Poly(Ring([(1,1), (3,1), (3,3), (1,3), (1,1)]))
|
|
285
|
+
|
|
286
|
+
# Perform unary union (requires tgx and libgeos)
|
|
287
|
+
union = Geometry.unary_union([poly1, poly2])
|
|
288
|
+
|
|
289
|
+
# The result is a single geometry representing the union of the input polygons
|
|
290
|
+
print(union.to_wkt())
|
|
291
|
+
```
|
|
292
|
+
|
|
293
|
+
This operation uses `tgx` to convert `TG` geometries to `GEOS`, applies the union in `libgeos`, and converts the result back to `TG` format for further use in `ToGo`.
|
|
294
|
+
|
|
295
|
+
### Example: Buffer Operations (GEOS integration)
|
|
296
|
+
|
|
297
|
+
The `buffer()` method creates geometrical buffers (expanded or shrunk versions of geometries) using GEOS:
|
|
298
|
+
|
|
299
|
+
```python
|
|
300
|
+
from togo import Point, LineString, Polygon, Ring, Geometry
|
|
301
|
+
|
|
302
|
+
# Buffer a point to create a circular zone
|
|
303
|
+
point = Point(0, 0)
|
|
304
|
+
circular_zone = point.buffer(10.0, quad_segs=16)
|
|
305
|
+
print(f"Point buffer: {circular_zone.geom_type}") # Polygon
|
|
306
|
+
|
|
307
|
+
# Buffer a line to create a corridor around it
|
|
308
|
+
line = LineString([(0, 0), (10, 10)])
|
|
309
|
+
corridor = line.buffer(2.0, cap_style=1) # round ends
|
|
310
|
+
print(f"Line buffer: {corridor.geom_type}") # Polygon
|
|
311
|
+
|
|
312
|
+
# Buffer a polygon to expand or shrink it
|
|
313
|
+
exterior = Ring([(0, 0), (10, 0), (10, 10), (0, 10), (0, 0)])
|
|
314
|
+
poly = Polygon(exterior)
|
|
315
|
+
|
|
316
|
+
expanded = poly.buffer(2.0) # Expand outward by 2 units
|
|
317
|
+
shrunk = poly.buffer(-1.0) # Shrink inward by 1 unit
|
|
318
|
+
|
|
319
|
+
# Via Geometry object with advanced parameters
|
|
320
|
+
geom = Geometry("POLYGON((0 0, 20 0, 20 20, 0 20, 0 0))")
|
|
321
|
+
buffered = geom.buffer(
|
|
322
|
+
distance=3.0,
|
|
323
|
+
quad_segs=16, # Segments per quadrant (higher = smoother)
|
|
324
|
+
cap_style=1, # 1=round, 2=flat, 3=square
|
|
325
|
+
join_style=1, # 1=round, 2=mitre, 3=bevel
|
|
326
|
+
mitre_limit=5.0 # Mitre ratio limit
|
|
327
|
+
)
|
|
328
|
+
```
|
|
329
|
+
|
|
330
|
+
Like `unary_union`, buffer operations automatically handle TG ↔ GEOS conversions. For comprehensive buffer documentation, see [BUFFER_API.md](BUFFER_API.md).
|
|
331
|
+
|
|
332
|
+
## Performance Considerations
|
|
333
|
+
|
|
334
|
+
- Togo is optimized for speed and memory efficiency
|
|
335
|
+
- For large datasets, proper indexing can significantly improve performance
|
|
336
|
+
- Creating geometries with the appropriate format avoids unnecessary conversions
|
|
337
|
+
- Buffer operations support quad_segs parameter to balance quality vs. performance
|
|
338
|
+
|
|
339
|
+
Soon there will be a full API documentation, for now please refer to the test suite for more usage examples.
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
togo.cpython-314-x86_64-linux-gnu.so,sha256=VoY7_FHaAjz_pkCpgWcJpzIG4B2bTWtZj1TJKJBiEqg,9925536
|
|
2
|
+
togo-0.2.6.dist-info/METADATA,sha256=Hv9i0-DOa2DWbItaqHAIlwZ0ZK2ltXYo_UPXu6n6tp0,10326
|
|
3
|
+
togo-0.2.6.dist-info/WHEEL,sha256=W3HekPD1LPmaWNNpfLvJfkRKxErKmPGqCVkQ6jDfCSs,152
|
|
4
|
+
togo-0.2.6.dist-info/top_level.txt,sha256=bldd6tssR8THqoSDFauQQdh_pg79DMHBDhiNKgS4ttM,5
|
|
5
|
+
togo-0.2.6.dist-info/RECORD,,
|
|
6
|
+
togo-0.2.6.dist-info/licenses/LICENSE,sha256=OfTFHFMDSt9X89g-BWUVis-GuTPWAdjplg2z9d2dBCw,1073
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 Giorgio Salluzzo
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
togo
|
|
Binary file
|