togo 0.1.3__tar.gz → 0.1.5__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.
Potentially problematic release.
This version of togo might be problematic. Click here for more details.
- togo-0.1.5/MANIFEST.in +4 -0
- {togo-0.1.3/togo.egg-info → togo-0.1.5}/PKG-INFO +25 -1
- {togo-0.1.3 → togo-0.1.5}/README.md +24 -0
- {togo-0.1.3 → togo-0.1.5}/pyproject.toml +11 -1
- togo-0.1.5/setup.py +74 -0
- {togo-0.1.3 → togo-0.1.5}/tests/test_geometries.py +31 -0
- {togo-0.1.3 → togo-0.1.5}/tests/test_geometry.py +41 -1
- togo-0.1.5/tgx.c +781 -0
- togo-0.1.5/tgx.h +21 -0
- {togo-0.1.3 → togo-0.1.5}/togo.c +6123 -3536
- {togo-0.1.3 → togo-0.1.5/togo.egg-info}/PKG-INFO +25 -1
- {togo-0.1.3 → togo-0.1.5}/togo.egg-info/SOURCES.txt +7 -1
- {togo-0.1.3 → togo-0.1.5}/togo.pyx +223 -41
- togo-0.1.5/vendor/geos/local/include/geos/export.h +51 -0
- togo-0.1.5/vendor/geos/local/include/geos_c.h +6742 -0
- togo-0.1.5/vendor/geos/local/lib/libgeos.a +0 -0
- togo-0.1.5/vendor/geos/local/lib/libgeos_c.a +0 -0
- togo-0.1.3/MANIFEST.in +0 -5
- togo-0.1.3/setup.py +0 -52
- {togo-0.1.3 → togo-0.1.5}/LICENSE +0 -0
- {togo-0.1.3 → togo-0.1.5}/setup.cfg +0 -0
- {togo-0.1.3 → togo-0.1.5}/tests/test_factories.py +0 -0
- {togo-0.1.3 → togo-0.1.5}/tests/test_line.py +0 -0
- {togo-0.1.3 → togo-0.1.5}/tests/test_point.py +0 -0
- {togo-0.1.3 → togo-0.1.5}/tests/test_poly.py +0 -0
- {togo-0.1.3 → togo-0.1.5}/tests/test_rect.py +0 -0
- {togo-0.1.3 → togo-0.1.5}/tests/test_ring.py +0 -0
- {togo-0.1.3 → togo-0.1.5}/tests/test_segment.py +0 -0
- {togo-0.1.3 → togo-0.1.5}/tg.c +0 -0
- {togo-0.1.3 → togo-0.1.5}/tg.h +0 -0
- {togo-0.1.3 → togo-0.1.5}/togo.egg-info/dependency_links.txt +0 -0
- {togo-0.1.3 → togo-0.1.5}/togo.egg-info/top_level.txt +0 -0
togo-0.1.5/MANIFEST.in
ADDED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: togo
|
|
3
|
-
Version: 0.1.
|
|
3
|
+
Version: 0.1.5
|
|
4
4
|
Summary: Lightweight Python bindings for the TG geometry library
|
|
5
5
|
Author-email: Giorgio Salluzzo <giorgio.salluzzo@gmail.com>
|
|
6
6
|
License: MIT
|
|
@@ -242,6 +242,30 @@ from togo import TGIndex, set_polygon_indexing_mode
|
|
|
242
242
|
set_polygon_indexing_mode(TGIndex.NATURAL) # or NONE, YSTRIPES
|
|
243
243
|
```
|
|
244
244
|
|
|
245
|
+
## Integration with tgx and libgeos
|
|
246
|
+
|
|
247
|
+
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.
|
|
248
|
+
|
|
249
|
+
### Example: Unary Union (GEOS integration)
|
|
250
|
+
|
|
251
|
+
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:
|
|
252
|
+
|
|
253
|
+
```python
|
|
254
|
+
from togo import Geometry, Point, Poly, Ring
|
|
255
|
+
|
|
256
|
+
# Create several polygons
|
|
257
|
+
poly1 = Poly(Ring([(0,0), (2,0), (2,2), (0,2), (0,0)]))
|
|
258
|
+
poly2 = Poly(Ring([(1,1), (3,1), (3,3), (1,3), (1,1)]))
|
|
259
|
+
|
|
260
|
+
# Perform unary union (requires tgx and libgeos)
|
|
261
|
+
union = Geometry.unary_union([poly1, poly2])
|
|
262
|
+
|
|
263
|
+
# The result is a single geometry representing the union of the input polygons
|
|
264
|
+
print(union.to_wkt())
|
|
265
|
+
```
|
|
266
|
+
|
|
267
|
+
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`.
|
|
268
|
+
|
|
245
269
|
## Performance Considerations
|
|
246
270
|
|
|
247
271
|
- Togo is optimized for speed and memory efficiency
|
|
@@ -222,6 +222,30 @@ from togo import TGIndex, set_polygon_indexing_mode
|
|
|
222
222
|
set_polygon_indexing_mode(TGIndex.NATURAL) # or NONE, YSTRIPES
|
|
223
223
|
```
|
|
224
224
|
|
|
225
|
+
## Integration with tgx and libgeos
|
|
226
|
+
|
|
227
|
+
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.
|
|
228
|
+
|
|
229
|
+
### Example: Unary Union (GEOS integration)
|
|
230
|
+
|
|
231
|
+
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:
|
|
232
|
+
|
|
233
|
+
```python
|
|
234
|
+
from togo import Geometry, Point, Poly, Ring
|
|
235
|
+
|
|
236
|
+
# Create several polygons
|
|
237
|
+
poly1 = Poly(Ring([(0,0), (2,0), (2,2), (0,2), (0,0)]))
|
|
238
|
+
poly2 = Poly(Ring([(1,1), (3,1), (3,3), (1,3), (1,1)]))
|
|
239
|
+
|
|
240
|
+
# Perform unary union (requires tgx and libgeos)
|
|
241
|
+
union = Geometry.unary_union([poly1, poly2])
|
|
242
|
+
|
|
243
|
+
# The result is a single geometry representing the union of the input polygons
|
|
244
|
+
print(union.to_wkt())
|
|
245
|
+
```
|
|
246
|
+
|
|
247
|
+
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`.
|
|
248
|
+
|
|
225
249
|
## Performance Considerations
|
|
226
250
|
|
|
227
251
|
- Togo is optimized for speed and memory efficiency
|
|
@@ -8,7 +8,7 @@ build-backend = "setuptools.build_meta"
|
|
|
8
8
|
|
|
9
9
|
[project]
|
|
10
10
|
name = "togo"
|
|
11
|
-
version = "0.1.
|
|
11
|
+
version = "0.1.5"
|
|
12
12
|
description = "Lightweight Python bindings for the TG geometry library"
|
|
13
13
|
readme = "README.md"
|
|
14
14
|
authors = [
|
|
@@ -33,3 +33,13 @@ Tracker = "https://github.com/mindflayer/togo/issues"
|
|
|
33
33
|
addopts = "-v -x -q"
|
|
34
34
|
testpaths = ["tests"]
|
|
35
35
|
pythonpath = ["."]
|
|
36
|
+
|
|
37
|
+
[tool.cython-lint]
|
|
38
|
+
max-line-length = 100
|
|
39
|
+
|
|
40
|
+
[tool.cibuildwheel]
|
|
41
|
+
#skip = ["*-musllinux_*"]
|
|
42
|
+
build-verbosity = 1
|
|
43
|
+
before-build = "bash tools/prepare_vendor.sh"
|
|
44
|
+
# Compute platform ID from CIBW_BUILD and point LD_LIBRARY_PATH at the right vendor dir for repair
|
|
45
|
+
repair-wheel-command = "PLATFORM_ID=$(echo \"$CIBW_BUILD\" | cut -d- -f2-); LD_LIBRARY_PATH=/project/vendor/geos/${PLATFORM_ID}/lib auditwheel repair -w {dest_dir} {wheel}"
|
togo-0.1.5/setup.py
ADDED
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import os
|
|
2
|
+
|
|
3
|
+
from setuptools import setup, Extension
|
|
4
|
+
from Cython.Build import cythonize
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
def _platform_id():
|
|
8
|
+
tag = os.environ.get("CIBW_BUILD", "local")
|
|
9
|
+
return tag.split("-", 1)[1] if "-" in tag else tag
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
extra_compile_args = [
|
|
13
|
+
"-ffunction-sections", # Enable function-level sections
|
|
14
|
+
"-fdata-sections", # Enable data-level sections
|
|
15
|
+
]
|
|
16
|
+
# Avoid gc-sections when statically linking C++ libs with RTTI/vtables
|
|
17
|
+
extra_link_args = [
|
|
18
|
+
# intentionally no --gc-sections
|
|
19
|
+
"-lstdc++", # Link against C++ standard library
|
|
20
|
+
]
|
|
21
|
+
|
|
22
|
+
# Enable optional AddressSanitizer build via env var ASAN=1
|
|
23
|
+
if os.environ.get("ASAN") == "1":
|
|
24
|
+
# Favor debuggability over speed
|
|
25
|
+
extra_compile_args += [
|
|
26
|
+
"-O1",
|
|
27
|
+
"-g",
|
|
28
|
+
"-fno-omit-frame-pointer",
|
|
29
|
+
"-fsanitize=address",
|
|
30
|
+
]
|
|
31
|
+
extra_link_args += [
|
|
32
|
+
"-fsanitize=address",
|
|
33
|
+
]
|
|
34
|
+
|
|
35
|
+
repo_root = os.path.abspath(os.path.dirname(__file__))
|
|
36
|
+
plat_id = _platform_id()
|
|
37
|
+
|
|
38
|
+
# Prefer platform-specific vendor path, fall back to legacy flat layout
|
|
39
|
+
cand_include = os.path.join(repo_root, "vendor", "geos", plat_id, "include")
|
|
40
|
+
cand_lib = os.path.join(repo_root, "vendor", "geos", plat_id, "lib")
|
|
41
|
+
if os.path.isdir(cand_include) and os.path.isdir(cand_lib):
|
|
42
|
+
geos_include = cand_include
|
|
43
|
+
geos_lib = cand_lib
|
|
44
|
+
else:
|
|
45
|
+
geos_include = os.path.join(repo_root, "vendor", "geos", "include")
|
|
46
|
+
geos_lib = os.path.join(repo_root, "vendor", "geos", "lib")
|
|
47
|
+
|
|
48
|
+
setup(
|
|
49
|
+
ext_modules=cythonize(
|
|
50
|
+
[
|
|
51
|
+
Extension(
|
|
52
|
+
"togo",
|
|
53
|
+
sources=["togo.pyx", "tg.c", "tgx.c"],
|
|
54
|
+
include_dirs=[
|
|
55
|
+
".", # For tg.h and tgx.h
|
|
56
|
+
geos_include,
|
|
57
|
+
],
|
|
58
|
+
# Link static archives as whole-archive to keep all needed RTTI/vtables
|
|
59
|
+
extra_compile_args=extra_compile_args,
|
|
60
|
+
extra_link_args=[
|
|
61
|
+
"-Wl,--whole-archive",
|
|
62
|
+
os.path.join(geos_lib, "libgeos_c.a"),
|
|
63
|
+
os.path.join(geos_lib, "libgeos.a"),
|
|
64
|
+
"-Wl,--no-whole-archive",
|
|
65
|
+
]
|
|
66
|
+
+ extra_link_args,
|
|
67
|
+
)
|
|
68
|
+
]
|
|
69
|
+
),
|
|
70
|
+
# Explicitly disable auto-discovery in flat layout
|
|
71
|
+
packages=[],
|
|
72
|
+
py_modules=[],
|
|
73
|
+
license="MIT",
|
|
74
|
+
)
|
|
@@ -58,3 +58,34 @@ def test_buenos_aires():
|
|
|
58
58
|
b_aires_center = rect.center()
|
|
59
59
|
assert b_aires_center.as_tuple() == (-58.38268310487112, -34.70305640194427)
|
|
60
60
|
assert b_aires.intersects(b_aires_center.as_geometry())
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
def test_togo_union_benin():
|
|
64
|
+
g = Geometry.unary_union(
|
|
65
|
+
[Geometry(TOGO, fmt="geojson"), Geometry(BENIN, fmt="geojson")]
|
|
66
|
+
)
|
|
67
|
+
# The union should not be empty and should be a valid geometry
|
|
68
|
+
assert not g.is_empty()
|
|
69
|
+
assert g.type_string() == "Polygon"
|
|
70
|
+
wkt = g.to_wkt()
|
|
71
|
+
new_g = Geometry(wkt, fmt="wkt")
|
|
72
|
+
assert new_g.equals(g)
|
|
73
|
+
assert new_g.rect() == g.rect()
|
|
74
|
+
assert new_g.within(g) and g.within(new_g)
|
|
75
|
+
assert g.contains(new_g) and new_g.contains(g)
|
|
76
|
+
assert g.intersects(new_g) and new_g.intersects(g)
|
|
77
|
+
assert not g.disjoint(new_g) and not new_g.disjoint(g)
|
|
78
|
+
assert not g.touches(new_g) and not new_g.touches(g)
|
|
79
|
+
assert g.num_points() == new_g.num_points()
|
|
80
|
+
assert g.dims() == new_g.dims()
|
|
81
|
+
assert g.has_z() == new_g.has_z()
|
|
82
|
+
assert g.has_m() == new_g.has_m()
|
|
83
|
+
assert g.is_feature() == new_g.is_feature()
|
|
84
|
+
assert g.is_featurecollection() == new_g.is_featurecollection()
|
|
85
|
+
assert g.to_geojson() == new_g.to_geojson()
|
|
86
|
+
assert g.to_hex() == new_g.to_hex()
|
|
87
|
+
assert g.to_wkb() == new_g.to_wkb()
|
|
88
|
+
assert g.to_geobin() == new_g.to_geobin()
|
|
89
|
+
assert g.memsize() == new_g.memsize()
|
|
90
|
+
assert g.coveredby(new_g) and new_g.coveredby(g)
|
|
91
|
+
assert g.covers(new_g) and new_g.covers(g)
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import pytest
|
|
2
|
-
from togo import Geometry
|
|
2
|
+
from togo import Geometry, Point, Ring, Poly
|
|
3
3
|
|
|
4
4
|
|
|
5
5
|
def test_geometry_wkt():
|
|
@@ -193,3 +193,43 @@ def test_geometry_geom_at():
|
|
|
193
193
|
assert g1.type_string() == "Point"
|
|
194
194
|
assert g0.point().x == 1.0 and g0.point().y == 2.0
|
|
195
195
|
assert g1.point().x == 3.0 and g1.point().y == 4.0
|
|
196
|
+
|
|
197
|
+
|
|
198
|
+
def test_tgx_meters_grid():
|
|
199
|
+
# Create a simple point geometry
|
|
200
|
+
g = Geometry('{"type": "Point", "coordinates": [1.0, 2.0]}')
|
|
201
|
+
origin = Point(0.0, 0.0)
|
|
202
|
+
g2 = g.to_meters_grid(origin)
|
|
203
|
+
g3 = g2.from_meters_grid(origin)
|
|
204
|
+
# Should round-trip back to original coordinates
|
|
205
|
+
assert g3.point().x == pytest.approx(1.0, abs=1e-6)
|
|
206
|
+
assert g3.point().y == pytest.approx(2.0, abs=1e-6)
|
|
207
|
+
|
|
208
|
+
|
|
209
|
+
def test_unary_union_geos_lines():
|
|
210
|
+
g1 = Geometry("LINESTRING(0 0, 1 1)", fmt="wkt")
|
|
211
|
+
g2 = Geometry("LINESTRING(1 1, 2 2)", fmt="wkt")
|
|
212
|
+
u = Geometry.unary_union([g1, g2])
|
|
213
|
+
assert u.type_string() == "MultiLineString"
|
|
214
|
+
wkt = u.to_wkt()
|
|
215
|
+
assert wkt == "MULTILINESTRING((0 0,1 1),(1 1,2 2))"
|
|
216
|
+
|
|
217
|
+
|
|
218
|
+
def test_unary_union_geos_polys():
|
|
219
|
+
# Two intersecting squares
|
|
220
|
+
outer1 = Ring([(0, 0), (2, 0), (2, 2), (0, 2), (0, 0)])
|
|
221
|
+
poly1 = Poly(outer1)
|
|
222
|
+
outer2 = Ring([(1, 1), (3, 1), (3, 3), (1, 3), (1, 1)])
|
|
223
|
+
poly2 = Poly(outer2)
|
|
224
|
+
union_geom = Geometry.unary_union([poly1, poly2])
|
|
225
|
+
# Should be a single Polygon
|
|
226
|
+
assert union_geom.type_string() == "Polygon"
|
|
227
|
+
# Area should be 7 (each square is 4, overlap is 1)
|
|
228
|
+
# So union area = 4 + 4 - 1 = 7
|
|
229
|
+
area = union_geom.poly().exterior().area()
|
|
230
|
+
assert area == 7.0
|
|
231
|
+
# Bounding box should be ((0,0),(3,3))
|
|
232
|
+
assert union_geom.rect() == ((0.0, 0.0), (3.0, 3.0))
|
|
233
|
+
# WKT should represent the merged polygon
|
|
234
|
+
wkt = union_geom.to_wkt()
|
|
235
|
+
assert wkt == "POLYGON((2 0,0 0,0 2,1 2,1 3,3 3,3 1,2 1,2 0))"
|