togo 0.1.1__tar.gz → 0.1.3__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.

@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: togo
3
- Version: 0.1.1
3
+ Version: 0.1.3
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
@@ -86,26 +86,127 @@ g1.within(g2)
86
86
  # Format conversion
87
87
  g1.to_wkt()
88
88
  g1.to_geojson()
89
- ```
90
89
 
91
- ### Point, Line, Ring, Poly
90
+ # Access sub-geometries by index (e.g., for GeometryCollection, MultiPoint, etc.)
91
+ gc = Geometry('GEOMETRYCOLLECTION(POINT(1 2),POINT(3 4))', fmt='wkt')
92
+ first = gc[0] # Bound to TG function call tg_geom_geometry_at(idx)
93
+ second = gc[1]
94
+ print(first.type_string()) # 'Point'
95
+ ```
92
96
 
93
- Building blocks for constructing geometries:
97
+ ### Point
94
98
 
95
99
  ```python
100
+ from togo import Point
101
+
96
102
  # Create a point
97
103
  p = Point(1.0, 2.0)
98
104
 
99
- # Create a line
100
- line = Line([(0,0), (1,1), (2,2)])
105
+ # Access coordinates
106
+ print(f"X: {p.x}, Y: {p.y}")
107
+
108
+ # Get as a tuple
109
+ print(p.as_tuple())
110
+
111
+ # Convert to a Geometry object
112
+ geom = p.as_geometry()
113
+ print(geom.type_string())
114
+ ```
115
+
116
+ ### Segment
117
+
118
+ ```python
119
+ from togo import Segment, Point
120
+
121
+ # Create a segment from two points (or tuples)
122
+ seg = Segment(Point(0, 0), Point(1, 1))
123
+ # Or using tuples
124
+ tuple_seg = Segment((0, 0), (1, 1))
125
+
126
+ # Access endpoints
127
+ print(seg.a) # Point(0, 0)
128
+ print(seg.b) # Point(1, 1)
129
+
130
+ # Get the bounding rectangle
131
+ rect = seg.rect()
132
+ print(rect) # ((0.0, 0.0), (1.0, 1.0))
133
+
134
+ # Check intersection with another segment
135
+ other = Segment((1, 1), (2, 2))
136
+ print(seg.intersects(other)) # True or False
137
+ ```
138
+
139
+ ### Line
140
+
141
+ ```python
142
+ from togo import Line
143
+
144
+ # Create a line from a list of tuples
145
+ line = Line([(0,0), (1,1), (2,0)])
146
+
147
+ # Get number of points
148
+ print(f"Number of points: {line.num_points()}")
149
+
150
+ # Get all points as a list of tuples
151
+ print(f"Points: {line.points()}")
101
152
 
102
- # Create a ring (closed line)
153
+ # Get the length of the line
154
+ print(f"Length: {line.length()}")
155
+
156
+ # Get the bounding box
157
+ print(f"Bounding box: {line.rect()}")
158
+
159
+ # Get a point by index
160
+ print(f"First point: {line[0].as_tuple()}")
161
+ ```
162
+
163
+ ### Ring
164
+
165
+ ```python
166
+ from togo import Ring
167
+
168
+ # Create a ring (must be closed)
103
169
  ring = Ring([(0,0), (10,0), (10,10), (0,10), (0,0)])
104
170
 
105
- # Create a polygon with holes
171
+ # Get area and perimeter
172
+ print(f"Area: {ring.area()}")
173
+ print(f"Perimeter: {ring.perimeter()}")
174
+
175
+ # Check if it's convex or clockwise
176
+ print(f"Is convex: {ring.is_convex()}")
177
+ print(f"Is clockwise: {ring.is_clockwise()}")
178
+
179
+ # Get bounding box
180
+ min_pt, max_pt = ring.rect().min, ring.rect().max
181
+ print(f"Bounding box: {min_pt.as_tuple()}, {max_pt.as_tuple()}")
182
+ ```
183
+
184
+ ### Poly
185
+
186
+ ```python
187
+ from togo import Poly, Ring, Point
188
+
189
+ # Create a polygon with one exterior ring and one interior hole
106
190
  exterior = Ring([(0,0), (10,0), (10,10), (0,10), (0,0)])
107
- hole = Ring([(2,2), (8,2), (8,8), (2,8), (2,2)])
108
- poly = Poly(exterior, [hole])
191
+ hole1 = Ring([(1,1), (2,1), (2,2), (1,2), (1,1)])
192
+ poly = Poly(exterior, holes=[hole1])
193
+
194
+ # Get the exterior ring
195
+ ext_ring = poly.exterior()
196
+ print(f"Exterior has {ext_ring.num_points()} points")
197
+
198
+ # Get number of holes
199
+ print(f"Number of holes: {poly.num_holes()}")
200
+
201
+ # Get a hole by index
202
+ h = poly.hole(0)
203
+ print(f"Hole area: {h.area()}")
204
+
205
+ # A polygon is a geometry, so you can use geometry methods
206
+ geom = poly.as_geometry()
207
+ print(f"Contains point (5,5): {geom.contains(Point(5,5).as_geometry())}")
208
+ # Point is inside the hole, so it is not contained by the polygon
209
+ print(f"Contains point (1.5,1.5): {geom.contains(Point(1.5,1.5).as_geometry())}")
109
210
  ```
110
211
 
111
212
  ### MultiGeometries
@@ -113,6 +214,8 @@ poly = Poly(exterior, [hole])
113
214
  Creating collections of geometries:
114
215
 
115
216
  ```python
217
+ from togo import Geometry, Point, Line, Poly, Ring
218
+
116
219
  # Create a MultiPoint
117
220
  multi_point = Geometry.from_multipoint([(0,0), (1,1), Point(2,2)])
118
221
 
@@ -66,26 +66,127 @@ g1.within(g2)
66
66
  # Format conversion
67
67
  g1.to_wkt()
68
68
  g1.to_geojson()
69
- ```
70
69
 
71
- ### Point, Line, Ring, Poly
70
+ # Access sub-geometries by index (e.g., for GeometryCollection, MultiPoint, etc.)
71
+ gc = Geometry('GEOMETRYCOLLECTION(POINT(1 2),POINT(3 4))', fmt='wkt')
72
+ first = gc[0] # Bound to TG function call tg_geom_geometry_at(idx)
73
+ second = gc[1]
74
+ print(first.type_string()) # 'Point'
75
+ ```
72
76
 
73
- Building blocks for constructing geometries:
77
+ ### Point
74
78
 
75
79
  ```python
80
+ from togo import Point
81
+
76
82
  # Create a point
77
83
  p = Point(1.0, 2.0)
78
84
 
79
- # Create a line
80
- line = Line([(0,0), (1,1), (2,2)])
85
+ # Access coordinates
86
+ print(f"X: {p.x}, Y: {p.y}")
87
+
88
+ # Get as a tuple
89
+ print(p.as_tuple())
90
+
91
+ # Convert to a Geometry object
92
+ geom = p.as_geometry()
93
+ print(geom.type_string())
94
+ ```
95
+
96
+ ### Segment
97
+
98
+ ```python
99
+ from togo import Segment, Point
100
+
101
+ # Create a segment from two points (or tuples)
102
+ seg = Segment(Point(0, 0), Point(1, 1))
103
+ # Or using tuples
104
+ tuple_seg = Segment((0, 0), (1, 1))
105
+
106
+ # Access endpoints
107
+ print(seg.a) # Point(0, 0)
108
+ print(seg.b) # Point(1, 1)
109
+
110
+ # Get the bounding rectangle
111
+ rect = seg.rect()
112
+ print(rect) # ((0.0, 0.0), (1.0, 1.0))
113
+
114
+ # Check intersection with another segment
115
+ other = Segment((1, 1), (2, 2))
116
+ print(seg.intersects(other)) # True or False
117
+ ```
118
+
119
+ ### Line
120
+
121
+ ```python
122
+ from togo import Line
123
+
124
+ # Create a line from a list of tuples
125
+ line = Line([(0,0), (1,1), (2,0)])
126
+
127
+ # Get number of points
128
+ print(f"Number of points: {line.num_points()}")
129
+
130
+ # Get all points as a list of tuples
131
+ print(f"Points: {line.points()}")
81
132
 
82
- # Create a ring (closed line)
133
+ # Get the length of the line
134
+ print(f"Length: {line.length()}")
135
+
136
+ # Get the bounding box
137
+ print(f"Bounding box: {line.rect()}")
138
+
139
+ # Get a point by index
140
+ print(f"First point: {line[0].as_tuple()}")
141
+ ```
142
+
143
+ ### Ring
144
+
145
+ ```python
146
+ from togo import Ring
147
+
148
+ # Create a ring (must be closed)
83
149
  ring = Ring([(0,0), (10,0), (10,10), (0,10), (0,0)])
84
150
 
85
- # Create a polygon with holes
151
+ # Get area and perimeter
152
+ print(f"Area: {ring.area()}")
153
+ print(f"Perimeter: {ring.perimeter()}")
154
+
155
+ # Check if it's convex or clockwise
156
+ print(f"Is convex: {ring.is_convex()}")
157
+ print(f"Is clockwise: {ring.is_clockwise()}")
158
+
159
+ # Get bounding box
160
+ min_pt, max_pt = ring.rect().min, ring.rect().max
161
+ print(f"Bounding box: {min_pt.as_tuple()}, {max_pt.as_tuple()}")
162
+ ```
163
+
164
+ ### Poly
165
+
166
+ ```python
167
+ from togo import Poly, Ring, Point
168
+
169
+ # Create a polygon with one exterior ring and one interior hole
86
170
  exterior = Ring([(0,0), (10,0), (10,10), (0,10), (0,0)])
87
- hole = Ring([(2,2), (8,2), (8,8), (2,8), (2,2)])
88
- poly = Poly(exterior, [hole])
171
+ hole1 = Ring([(1,1), (2,1), (2,2), (1,2), (1,1)])
172
+ poly = Poly(exterior, holes=[hole1])
173
+
174
+ # Get the exterior ring
175
+ ext_ring = poly.exterior()
176
+ print(f"Exterior has {ext_ring.num_points()} points")
177
+
178
+ # Get number of holes
179
+ print(f"Number of holes: {poly.num_holes()}")
180
+
181
+ # Get a hole by index
182
+ h = poly.hole(0)
183
+ print(f"Hole area: {h.area()}")
184
+
185
+ # A polygon is a geometry, so you can use geometry methods
186
+ geom = poly.as_geometry()
187
+ print(f"Contains point (5,5): {geom.contains(Point(5,5).as_geometry())}")
188
+ # Point is inside the hole, so it is not contained by the polygon
189
+ print(f"Contains point (1.5,1.5): {geom.contains(Point(1.5,1.5).as_geometry())}")
89
190
  ```
90
191
 
91
192
  ### MultiGeometries
@@ -93,6 +194,8 @@ poly = Poly(exterior, [hole])
93
194
  Creating collections of geometries:
94
195
 
95
196
  ```python
197
+ from togo import Geometry, Point, Line, Poly, Ring
198
+
96
199
  # Create a MultiPoint
97
200
  multi_point = Geometry.from_multipoint([(0,0), (1,1), Point(2,2)])
98
201
 
@@ -8,7 +8,7 @@ build-backend = "setuptools.build_meta"
8
8
 
9
9
  [project]
10
10
  name = "togo"
11
- version = "0.1.1"
11
+ version = "0.1.3"
12
12
  description = "Lightweight Python bindings for the TG geometry library"
13
13
  readme = "README.md"
14
14
  authors = [
@@ -17,6 +17,22 @@ TG_HEADER_FILENAME = os.path.basename(urlparse(TG_HEADER_URL).path)
17
17
  if not os.path.exists(TG_HEADER_FILENAME):
18
18
  urllib.request.urlretrieve(TG_HEADER_URL, TG_HEADER_FILENAME)
19
19
 
20
+ # Enable optional AddressSanitizer build via env var ASAN=1
21
+ asan_enabled = os.environ.get("ASAN") == "1"
22
+ extra_compile_args = []
23
+ extra_link_args = []
24
+ if asan_enabled:
25
+ # Favor debuggability over speed
26
+ extra_compile_args += [
27
+ "-O1",
28
+ "-g",
29
+ "-fno-omit-frame-pointer",
30
+ "-fsanitize=address",
31
+ ]
32
+ extra_link_args += [
33
+ "-fsanitize=address",
34
+ ]
35
+
20
36
  setup(
21
37
  ext_modules=cythonize(
22
38
  [
@@ -24,8 +40,13 @@ setup(
24
40
  "togo",
25
41
  sources=["togo.pyx", TG_SOURCE_FILENAME],
26
42
  include_dirs=["."],
43
+ extra_compile_args=extra_compile_args,
44
+ extra_link_args=extra_link_args,
27
45
  )
28
46
  ]
29
47
  ),
48
+ # Explicitly disable auto-discovery in flat layout
49
+ packages=[],
50
+ py_modules=[],
30
51
  license="MIT",
31
52
  )
@@ -94,6 +94,9 @@ def test_geometry_num_lines_polys_geometries():
94
94
  "GEOMETRYCOLLECTION(POINT(1 2),LINESTRING(0 0,1 1))", fmt="wkt"
95
95
  )
96
96
  assert g_collection.num_geometries() == 2
97
+ # Use Geometry.__getitem__ to access sub-geometries of MultiLineString
98
+ first_line = g_lines[0]
99
+ assert first_line.type_string() == "LineString"
97
100
 
98
101
 
99
102
  def test_geometry_z_m():
@@ -156,3 +159,37 @@ def test_geometry_constructor_invalid():
156
159
  Geometry("not a geometry", fmt="geojson")
157
160
  with pytest.raises(ValueError):
158
161
  Geometry("not a geometry", fmt="hex")
162
+
163
+
164
+ def test_geometry_point_accessor():
165
+ g = Geometry("POINT(3 4)", fmt="wkt")
166
+ pt = g.point()
167
+ assert pt.x == 3.0 and pt.y == 4.0
168
+
169
+
170
+ def test_geometry_line_accessor_and_from_linestring():
171
+ points = [(0, 0), (1, 1), (2, 2)]
172
+ g = Geometry.from_linestring(points)
173
+ line = g.line()
174
+ pts = line.points()
175
+ assert pts == points
176
+
177
+
178
+ def test_geometry_poly_accessor():
179
+ # Polygon with one ring
180
+ wkt = "POLYGON((0 0,1 0,1 1,0 1,0 0))"
181
+ g = Geometry(wkt, fmt="wkt")
182
+ poly = g.poly()
183
+ ext = poly.exterior()
184
+ assert ext.num_points() == 5
185
+
186
+
187
+ def test_geometry_geom_at():
188
+ # GeometryCollection with two points
189
+ g = Geometry("GEOMETRYCOLLECTION(POINT(1 2),POINT(3 4))", fmt="wkt")
190
+ g0 = g[0]
191
+ g1 = g[1]
192
+ assert g0.type_string() == "Point"
193
+ assert g1.type_string() == "Point"
194
+ assert g0.point().x == 1.0 and g0.point().y == 2.0
195
+ assert g1.point().x == 3.0 and g1.point().y == 4.0
@@ -48,3 +48,18 @@ def test_line_as_geometry():
48
48
  assert g.type_string() == "LineString"
49
49
  rect = g.rect()
50
50
  assert rect == ((0.0, 0.0), (2.0, 2.0))
51
+
52
+
53
+ def test_line_getitem():
54
+ points = [(10, 20), (30, 40), (50, 60)]
55
+ line = Line(points)
56
+ pt0 = line[0]
57
+ pt1 = line[1]
58
+ pt2 = line[2]
59
+ assert pt0.x == 10 and pt0.y == 20
60
+ assert pt1.x == 30 and pt1.y == 40
61
+ assert pt2.x == 50 and pt2.y == 60
62
+ with pytest.raises(IndexError):
63
+ _ = line[3]
64
+ with pytest.raises(IndexError):
65
+ _ = line[-1]
@@ -0,0 +1,17 @@
1
+ from togo import Point, Segment
2
+
3
+
4
+ def test_segment_creation_and_rect():
5
+ a = Point(0, 0)
6
+ b = Point(1, 1)
7
+ seg = Segment(a, b)
8
+ rect = seg.rect()
9
+ assert rect == ((0, 0), (1, 1))
10
+
11
+
12
+ def test_segment_intersects():
13
+ seg1 = Segment(Point(0, 0), Point(1, 1))
14
+ seg2 = Segment(Point(0, 1), Point(1, 0))
15
+ seg3 = Segment(Point(2, 2), Point(3, 3))
16
+ assert seg1.intersects(seg2)
17
+ assert not seg1.intersects(seg3)