tg_geometry 0.1.0 → 0.3.0
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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +55 -79
- data/README.md +168 -184
- data/Rakefile +3 -3
- data/benchmark/ewkb_roundtrip.rb +29 -0
- data/benchmark/falcon_concurrency.rb +1 -1
- data/benchmark/feature_source.rb +92 -0
- data/benchmark/geom_query.rb +33 -0
- data/benchmark/nearest_segment.rb +20 -0
- data/docs/ARCHITECTURE.md +29 -107
- data/docs/BENCHMARKING.md +20 -1
- data/docs/CASUAL_EXAMPLE.md +71 -458
- data/docs/CONCURRENCY.md +13 -7
- data/docs/ERROR_HANDLING.md +30 -0
- data/docs/FEATURE_SOURCE.md +166 -0
- data/docs/GEOMETRY_QUERIES.md +23 -0
- data/docs/LIMITATIONS.md +17 -54
- data/docs/MEMORY_OWNERSHIP.md +20 -2
- data/docs/NEAREST_SEGMENT.md +17 -0
- data/docs/SRID_AND_EWKB.md +23 -0
- data/ext/tg_geometry/extconf.rb +46 -4
- data/ext/tg_geometry/tg_geometry_ext.c +3643 -168
- data/ext/tg_geometry/tg_geometry_vendor_json.c +17 -0
- data/ext/tg_geometry/tg_geometry_vendor_tg.c +3 -0
- data/ext/tg_geometry/vendor/.vendored +8 -2
- data/ext/tg_geometry/vendor/json/LICENSE +20 -0
- data/ext/tg_geometry/vendor/json/VERSION +3 -0
- data/ext/tg_geometry/vendor/json/json.c +1024 -0
- data/ext/tg_geometry/vendor/json/json.h +207 -0
- data/lib/tg/geometry/active_record_source.rb +16 -34
- data/lib/tg/geometry/active_record_type.rb +61 -0
- data/lib/tg/geometry/registry.rb +16 -67
- data/lib/tg/geometry/version.rb +1 -1
- data/lib/tg/geometry.rb +85 -0
- data/script/vendor_libs.rb +22 -6
- data/spec/active_record_type_spec.rb +45 -0
- data/spec/{expansion_a_auto_strategy_spec.rb → auto_strategy_spec.rb} +1 -1
- data/spec/{block_12_batch_packed_spec.rb → batch_packed_spec.rb} +1 -1
- data/spec/{block_20_concurrency_spec.rb → concurrency_spec.rb} +1 -1
- data/spec/constructors_spec.rb +104 -0
- data/spec/{block_13_error_hardening_spec.rb → error_hardening_spec.rb} +1 -1
- data/spec/feature_source_nogvl_spec.rb +51 -0
- data/spec/feature_source_spec.rb +268 -0
- data/spec/fixtures/feature_source/invalid_geometry_middle.geojson +8 -0
- data/spec/fixtures/feature_source/malformed_json.geojson +1 -0
- data/spec/fixtures/feature_source/mixed_geometry_types.geojson +8 -0
- data/spec/fixtures/feature_source/osm_like_feature_collection.geojson +10 -0
- data/spec/fixtures/feature_source/properties_null_missing.geojson +7 -0
- data/spec/fixtures/feature_source/simple_feature_collection.geojson +15 -0
- data/spec/fixtures/postgis/README.md +16 -0
- data/spec/fixtures/postgis/boundary_point_cases.geojson +83 -0
- data/spec/fixtures/postgis/multipolygon_large.ewkb +0 -0
- data/spec/fixtures/postgis/point_4326.ewkb +0 -0
- data/spec/fixtures/postgis/polygon_3857.ewkb +0 -0
- data/spec/fixtures/postgis/polygon_4326_simple.ewkb +0 -0
- data/spec/fixtures/postgis/polygon_4326_with_hole.ewkb +0 -0
- data/spec/{expansion_d_format_coverage_spec.rb → format_coverage_spec.rb} +1 -1
- data/spec/{block_20_fuzz_spec.rb → fuzz_spec.rb} +1 -1
- data/spec/{block_4_geom_api_spec.rb → geom_api_spec.rb} +1 -1
- data/spec/{block_3_geom_parse_spec.rb → geom_parse_spec.rb} +1 -1
- data/spec/{block_8_index_borrowed_geometry_spec.rb → index_borrowed_geometry_spec.rb} +1 -1
- data/spec/{block_6_index_build_spec.rb → index_build_spec.rb} +2 -2
- data/spec/{block_9_flat_query_spec.rb → index_flat_query_spec.rb} +1 -1
- data/spec/index_geom_query_spec.rb +68 -0
- data/spec/{block_7_index_owned_geometry_spec.rb → index_owned_geometry_spec.rb} +1 -1
- data/spec/{block_10_rtree_strategy_spec.rb → index_rtree_accounting_spec.rb} +1 -1
- data/spec/{block_11_rtree_order_spec.rb → index_rtree_order_spec.rb} +1 -1
- data/spec/keyword_validation_spec.rb +31 -0
- data/spec/{block_1_skeleton_spec.rb → load_and_errors_spec.rb} +1 -1
- data/spec/{expansion_e_low_level_geometry_spec.rb → low_level_geometry_spec.rb} +1 -1
- data/spec/{block_14_memory_gc_hardening_spec.rb → memory_gc_spec.rb} +1 -1
- data/spec/nearest_segment_spec.rb +62 -0
- data/spec/postgis_fixtures_spec.rb +68 -0
- data/spec/{expansion_i_ractor_spec.rb → ractor_spec.rb} +1 -1
- data/spec/{block_5_rect_api_spec.rb → rect_api_spec.rb} +1 -1
- data/spec/{expansion_b_registry_spec.rb → registry_spec.rb} +1 -1
- data/spec/srid_spec.rb +43 -0
- data/spec/{expansion_j_full_tg_api_coverage_spec.rb → tg_api_coverage_spec.rb} +1 -1
- data/spec/to_ewkb_spec.rb +37 -0
- data/spec/{block_2_vendor_spec.rb → vendor_sources_spec.rb} +4 -4
- metadata +87 -38
- data/docs/ACTIVE_RECORD.md +0 -26
- data/docs/AUTO_STRATEGY.md +0 -15
- data/docs/EXPANSION_E_TO_H_STATUS.md +0 -51
- data/docs/FORMAT_COVERAGE.md +0 -23
- data/docs/FULL_TG_API_COVERAGE.md +0 -109
- data/docs/LOW_LEVEL_GEOMETRY.md +0 -121
- data/docs/RACTOR.md +0 -40
- data/docs/REGISTRY.md +0 -37
- data/docs/RELEASE_CHECKLIST.md +0 -39
- /data/spec/{expansion_c_active_record_source_spec.rb → active_record_source_spec.rb} +0 -0
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: tg_geometry
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.3.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Roman Haydarov
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2026-05-
|
|
11
|
+
date: 2026-05-27 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: rake
|
|
@@ -38,14 +38,35 @@ dependencies:
|
|
|
38
38
|
- - "~>"
|
|
39
39
|
- !ruby/object:Gem::Version
|
|
40
40
|
version: '3.13'
|
|
41
|
+
- !ruby/object:Gem::Dependency
|
|
42
|
+
name: activemodel
|
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
|
44
|
+
requirements:
|
|
45
|
+
- - ">="
|
|
46
|
+
- !ruby/object:Gem::Version
|
|
47
|
+
version: '6.0'
|
|
48
|
+
- - "<"
|
|
49
|
+
- !ruby/object:Gem::Version
|
|
50
|
+
version: '9.0'
|
|
51
|
+
type: :development
|
|
52
|
+
prerelease: false
|
|
53
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
54
|
+
requirements:
|
|
55
|
+
- - ">="
|
|
56
|
+
- !ruby/object:Gem::Version
|
|
57
|
+
version: '6.0'
|
|
58
|
+
- - "<"
|
|
59
|
+
- !ruby/object:Gem::Version
|
|
60
|
+
version: '9.0'
|
|
41
61
|
description: Defines TG::Geometry with immutable Geom parsing and constructor wrappers,
|
|
42
62
|
expanded geometry predicates and accessors, Rect helpers, Hex/GeoBIN writers, raw
|
|
43
63
|
extra_json access, read-only borrowed Line/Ring/Polygon and GeometryCollection child
|
|
44
64
|
wrappers, value Segment wrappers, Registry reload sugar, optional ActiveRecord source
|
|
45
65
|
helpers, and an immutable geofencing-oriented Index with owned and borrowed geometry
|
|
46
66
|
ingestion, flat/rtree strategies, deterministic ordered id results, exact rtree
|
|
47
|
-
allocation accounting, and native-endian packed point batch queries
|
|
48
|
-
|
|
67
|
+
allocation accounting, and native-endian packed point batch queries, and FeatureSource
|
|
68
|
+
GeoJSON FeatureCollection extraction/build paths over vendored C sources. Ractor
|
|
69
|
+
support is not claimed.
|
|
49
70
|
email:
|
|
50
71
|
- romnhajdarov@gmail.com
|
|
51
72
|
executables: []
|
|
@@ -60,33 +81,37 @@ files:
|
|
|
60
81
|
- Rakefile
|
|
61
82
|
- benchmark/_support.rb
|
|
62
83
|
- benchmark/batch_packed_vs_loop.rb
|
|
84
|
+
- benchmark/ewkb_roundtrip.rb
|
|
63
85
|
- benchmark/falcon_concurrency.rb
|
|
86
|
+
- benchmark/feature_source.rb
|
|
64
87
|
- benchmark/flat_vs_rtree.rb
|
|
88
|
+
- benchmark/geom_query.rb
|
|
65
89
|
- benchmark/gvl_threshold.rb
|
|
90
|
+
- benchmark/nearest_segment.rb
|
|
66
91
|
- benchmark/objectspace_memsize.rb
|
|
67
92
|
- benchmark/parse_throughput.rb
|
|
68
93
|
- benchmark/rss_stability.rb
|
|
69
|
-
- docs/ACTIVE_RECORD.md
|
|
70
94
|
- docs/ARCHITECTURE.md
|
|
71
|
-
- docs/AUTO_STRATEGY.md
|
|
72
95
|
- docs/BENCHMARKING.md
|
|
73
96
|
- docs/CASUAL_EXAMPLE.md
|
|
74
97
|
- docs/CONCURRENCY.md
|
|
75
98
|
- docs/ERROR_HANDLING.md
|
|
76
|
-
- docs/
|
|
77
|
-
- docs/
|
|
78
|
-
- docs/FULL_TG_API_COVERAGE.md
|
|
99
|
+
- docs/FEATURE_SOURCE.md
|
|
100
|
+
- docs/GEOMETRY_QUERIES.md
|
|
79
101
|
- docs/LIMITATIONS.md
|
|
80
|
-
- docs/LOW_LEVEL_GEOMETRY.md
|
|
81
102
|
- docs/MEMORY_OWNERSHIP.md
|
|
82
|
-
- docs/
|
|
83
|
-
- docs/
|
|
84
|
-
- docs/RELEASE_CHECKLIST.md
|
|
103
|
+
- docs/NEAREST_SEGMENT.md
|
|
104
|
+
- docs/SRID_AND_EWKB.md
|
|
85
105
|
- ext/tg_geometry/extconf.rb
|
|
86
106
|
- ext/tg_geometry/tg_geometry_ext.c
|
|
107
|
+
- ext/tg_geometry/tg_geometry_vendor_json.c
|
|
87
108
|
- ext/tg_geometry/tg_geometry_vendor_rtree.c
|
|
88
109
|
- ext/tg_geometry/tg_geometry_vendor_tg.c
|
|
89
110
|
- ext/tg_geometry/vendor/.vendored
|
|
111
|
+
- ext/tg_geometry/vendor/json/LICENSE
|
|
112
|
+
- ext/tg_geometry/vendor/json/VERSION
|
|
113
|
+
- ext/tg_geometry/vendor/json/json.c
|
|
114
|
+
- ext/tg_geometry/vendor/json/json.h
|
|
90
115
|
- ext/tg_geometry/vendor/rtree/LICENSE
|
|
91
116
|
- ext/tg_geometry/vendor/rtree/README.md
|
|
92
117
|
- ext/tg_geometry/vendor/rtree/VERSION
|
|
@@ -99,34 +124,58 @@ files:
|
|
|
99
124
|
- ext/tg_geometry/vendor/tg/tg.h
|
|
100
125
|
- lib/tg/geometry.rb
|
|
101
126
|
- lib/tg/geometry/active_record_source.rb
|
|
127
|
+
- lib/tg/geometry/active_record_type.rb
|
|
102
128
|
- lib/tg/geometry/registry.rb
|
|
103
129
|
- lib/tg/geometry/version.rb
|
|
104
130
|
- lib/tg_geometry.rb
|
|
105
131
|
- script/vendor_libs.rb
|
|
106
|
-
- spec/
|
|
107
|
-
- spec/
|
|
108
|
-
- spec/
|
|
109
|
-
- spec/
|
|
110
|
-
- spec/
|
|
111
|
-
- spec/
|
|
112
|
-
- spec/
|
|
113
|
-
- spec/
|
|
114
|
-
- spec/
|
|
115
|
-
- spec/
|
|
116
|
-
- spec/
|
|
117
|
-
- spec/
|
|
118
|
-
- spec/
|
|
119
|
-
- spec/
|
|
120
|
-
- spec/
|
|
121
|
-
- spec/
|
|
122
|
-
- spec/
|
|
123
|
-
- spec/
|
|
124
|
-
- spec/
|
|
125
|
-
- spec/
|
|
126
|
-
- spec/
|
|
127
|
-
- spec/
|
|
128
|
-
- spec/
|
|
132
|
+
- spec/active_record_source_spec.rb
|
|
133
|
+
- spec/active_record_type_spec.rb
|
|
134
|
+
- spec/auto_strategy_spec.rb
|
|
135
|
+
- spec/batch_packed_spec.rb
|
|
136
|
+
- spec/concurrency_spec.rb
|
|
137
|
+
- spec/constructors_spec.rb
|
|
138
|
+
- spec/error_hardening_spec.rb
|
|
139
|
+
- spec/feature_source_nogvl_spec.rb
|
|
140
|
+
- spec/feature_source_spec.rb
|
|
141
|
+
- spec/fixtures/feature_source/invalid_geometry_middle.geojson
|
|
142
|
+
- spec/fixtures/feature_source/malformed_json.geojson
|
|
143
|
+
- spec/fixtures/feature_source/mixed_geometry_types.geojson
|
|
144
|
+
- spec/fixtures/feature_source/osm_like_feature_collection.geojson
|
|
145
|
+
- spec/fixtures/feature_source/properties_null_missing.geojson
|
|
146
|
+
- spec/fixtures/feature_source/simple_feature_collection.geojson
|
|
147
|
+
- spec/fixtures/postgis/README.md
|
|
148
|
+
- spec/fixtures/postgis/boundary_point_cases.geojson
|
|
149
|
+
- spec/fixtures/postgis/multipolygon_large.ewkb
|
|
150
|
+
- spec/fixtures/postgis/point_4326.ewkb
|
|
151
|
+
- spec/fixtures/postgis/polygon_3857.ewkb
|
|
152
|
+
- spec/fixtures/postgis/polygon_4326_simple.ewkb
|
|
153
|
+
- spec/fixtures/postgis/polygon_4326_with_hole.ewkb
|
|
154
|
+
- spec/format_coverage_spec.rb
|
|
155
|
+
- spec/fuzz_spec.rb
|
|
156
|
+
- spec/geom_api_spec.rb
|
|
157
|
+
- spec/geom_parse_spec.rb
|
|
158
|
+
- spec/index_borrowed_geometry_spec.rb
|
|
159
|
+
- spec/index_build_spec.rb
|
|
160
|
+
- spec/index_flat_query_spec.rb
|
|
161
|
+
- spec/index_geom_query_spec.rb
|
|
162
|
+
- spec/index_owned_geometry_spec.rb
|
|
163
|
+
- spec/index_rtree_accounting_spec.rb
|
|
164
|
+
- spec/index_rtree_order_spec.rb
|
|
165
|
+
- spec/keyword_validation_spec.rb
|
|
166
|
+
- spec/load_and_errors_spec.rb
|
|
167
|
+
- spec/low_level_geometry_spec.rb
|
|
168
|
+
- spec/memory_gc_spec.rb
|
|
169
|
+
- spec/nearest_segment_spec.rb
|
|
170
|
+
- spec/postgis_fixtures_spec.rb
|
|
171
|
+
- spec/ractor_spec.rb
|
|
172
|
+
- spec/rect_api_spec.rb
|
|
173
|
+
- spec/registry_spec.rb
|
|
129
174
|
- spec/spec_helper.rb
|
|
175
|
+
- spec/srid_spec.rb
|
|
176
|
+
- spec/tg_api_coverage_spec.rb
|
|
177
|
+
- spec/to_ewkb_spec.rb
|
|
178
|
+
- spec/vendor_sources_spec.rb
|
|
130
179
|
homepage: https://github.com/roman-haidarov/tg_geometry
|
|
131
180
|
licenses:
|
|
132
181
|
- MIT
|
|
@@ -142,7 +191,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
|
142
191
|
requirements:
|
|
143
192
|
- - ">="
|
|
144
193
|
- !ruby/object:Gem::Version
|
|
145
|
-
version: '3.
|
|
194
|
+
version: '3.1'
|
|
146
195
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
147
196
|
requirements:
|
|
148
197
|
- - ">="
|
|
@@ -153,5 +202,5 @@ rubygems_version: 3.3.27
|
|
|
153
202
|
signing_key:
|
|
154
203
|
specification_version: 4
|
|
155
204
|
summary: Native extension for TG::Geometry parsing, predicates, immutable indexes,
|
|
156
|
-
registries, low-level wrappers, and packed point batches
|
|
205
|
+
FeatureSource imports, registries, low-level wrappers, and packed point batches
|
|
157
206
|
test_files: []
|
data/docs/ACTIVE_RECORD.md
DELETED
|
@@ -1,26 +0,0 @@
|
|
|
1
|
-
# ActiveRecord source helper
|
|
2
|
-
|
|
3
|
-
`TG::Geometry::ActiveRecordSource` is an optional Ruby helper. It does not require Rails or ActiveRecord and is not loaded from a separate integration gem.
|
|
4
|
-
|
|
5
|
-
It accepts any object that responds to `find_each`, or any Enumerable:
|
|
6
|
-
|
|
7
|
-
```ruby
|
|
8
|
-
entries = TG::Geometry::ActiveRecordSource.call(
|
|
9
|
-
Zone.where(active: true),
|
|
10
|
-
id: :id,
|
|
11
|
-
geometry: :geojson,
|
|
12
|
-
batch_size: 1_000
|
|
13
|
-
)
|
|
14
|
-
|
|
15
|
-
index = TG::Geometry::Index.build(entries, via: :geojson, strategy: :rtree)
|
|
16
|
-
```
|
|
17
|
-
|
|
18
|
-
It can also feed a Registry:
|
|
19
|
-
|
|
20
|
-
```ruby
|
|
21
|
-
class DeliveryZones < TG::Geometry::Registry
|
|
22
|
-
active_record_source Zone.where(active: true), id: :id, geometry: :geojson
|
|
23
|
-
end
|
|
24
|
-
```
|
|
25
|
-
|
|
26
|
-
Field readers may be Symbols, Strings, or Procs. The helper only converts application records into `[[id, object], ...]`; it does not mutate records, keep database connections, create background jobs, install reload hooks, or add a Rails dependency to the native extension.
|
data/docs/AUTO_STRATEGY.md
DELETED
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
# Auto strategy status
|
|
2
|
-
|
|
3
|
-
`strategy: :auto` is not exposed in the first public release.
|
|
4
|
-
|
|
5
|
-
The release-core contract only enables explicit `strategy: :flat` and `strategy: :rtree`. Automatic threshold selection requires a complete project-owned benchmark matrix and explicit approval before it can become public API.
|
|
6
|
-
|
|
7
|
-
Use `benchmark/flat_vs_rtree.rb` to compare strategies for a workload, then pass the chosen strategy explicitly:
|
|
8
|
-
|
|
9
|
-
```ruby
|
|
10
|
-
index = TG::Geometry::Index.build(entries, via: :geojson, strategy: :rtree)
|
|
11
|
-
# or
|
|
12
|
-
index = TG::Geometry::Index.build(entries, via: :geojson, strategy: :flat)
|
|
13
|
-
```
|
|
14
|
-
|
|
15
|
-
Do not infer a universal crossover from rtree internals or from a partial benchmark run.
|
|
@@ -1,51 +0,0 @@
|
|
|
1
|
-
# Expansion Blocks E–H status
|
|
2
|
-
|
|
3
|
-
## Expansion Block E — Low-level Ring / Line / Polygon APIs
|
|
4
|
-
|
|
5
|
-
Implemented as read-only borrowed wrappers:
|
|
6
|
-
|
|
7
|
-
- `TG::Geometry::Geom#point`
|
|
8
|
-
- `TG::Geometry::Geom#line`
|
|
9
|
-
- `TG::Geometry::Geom#polygon`
|
|
10
|
-
- `TG::Geometry::Line`
|
|
11
|
-
- `TG::Geometry::Ring`
|
|
12
|
-
- `TG::Geometry::Polygon`
|
|
13
|
-
|
|
14
|
-
Invariant satisfied: child pointers are borrowed from the parent TG geometry and the wrapper keeps the parent Ruby `TG::Geometry::Geom` alive through `geom_owner` with compaction-aware marking.
|
|
15
|
-
|
|
16
|
-
Tests: `spec/expansion_e_low_level_geometry_spec.rb` covers accessors, private allocation, out-of-range errors, and parent survival after `GC.start` / `GC.compact`.
|
|
17
|
-
|
|
18
|
-
## Expansion Block F — Callback/search APIs
|
|
19
|
-
|
|
20
|
-
OPEN QUESTION: not implemented.
|
|
21
|
-
|
|
22
|
-
Reason: the roadmap allows callback/search APIs only with a new callback safety contract. The current contract still forbids public callback/block APIs in the first release. No `geom.search`, `index.search`, or `each_match` method is exposed.
|
|
23
|
-
|
|
24
|
-
Required before implementation:
|
|
25
|
-
|
|
26
|
-
- explicit callback exception propagation semantics;
|
|
27
|
-
- GVL behavior for Ruby callbacks inside C loops;
|
|
28
|
-
- proof that borrowed pointers cannot be invalidated by callback reentrancy;
|
|
29
|
-
- benchmark of callback overhead;
|
|
30
|
-
- tests for exceptions raised from callbacks.
|
|
31
|
-
|
|
32
|
-
## Expansion Block G — Fast no-allocation point query optimization
|
|
33
|
-
|
|
34
|
-
OPEN QUESTION: not implemented.
|
|
35
|
-
|
|
36
|
-
Reason: the current implementation intentionally constructs a temporary TG point geometry for `covers` / `contains` correctness. Replacing this with `tg_geom_intersects_xy` or a specialized helper requires proof of exact boundary semantics and a benchmark proving benefit.
|
|
37
|
-
|
|
38
|
-
Current invariant: point query semantics remain exact and boundary behavior is covered by existing tests.
|
|
39
|
-
|
|
40
|
-
## Expansion Block H — Geodesic helpers or projection integration
|
|
41
|
-
|
|
42
|
-
OPEN QUESTION: not implemented.
|
|
43
|
-
|
|
44
|
-
Reason: TG core remains planar XY. No optional geodesic/projection dependency has been approved. The gem continues to document that `length`, `area`, and `perimeter` are in input coordinate units, not meters for lon/lat.
|
|
45
|
-
|
|
46
|
-
Required before implementation:
|
|
47
|
-
|
|
48
|
-
- explicit optional dependency decision;
|
|
49
|
-
- public API shape;
|
|
50
|
-
- tests separating planar TG behavior from geodesic/projection helpers;
|
|
51
|
-
- documentation that TG itself does not handle geodesics.
|
data/docs/FORMAT_COVERAGE.md
DELETED
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
# Format coverage
|
|
2
|
-
|
|
3
|
-
Expansion Block D exposes additional TG format helpers without changing ownership rules.
|
|
4
|
-
|
|
5
|
-
## Parse helpers
|
|
6
|
-
|
|
7
|
-
- `TG::Geometry.parse_hex(str, index: :ystripes)`
|
|
8
|
-
- `TG::Geometry.parse_geobin(bytes, index: :ystripes)`
|
|
9
|
-
|
|
10
|
-
These are shortcuts over `TG::Geometry.parse(..., format: :hex)` and `TG::Geometry.parse(..., format: :geobin)`.
|
|
11
|
-
|
|
12
|
-
## Writer helpers
|
|
13
|
-
|
|
14
|
-
- `TG::Geometry::Geom#to_hex` -> UTF-8 String
|
|
15
|
-
- `TG::Geometry::Geom#to_geobin` -> ASCII-8BIT String
|
|
16
|
-
|
|
17
|
-
Writers use the same direct Ruby string buffer pattern as existing writers. Hex is text and GeoBIN is binary.
|
|
18
|
-
|
|
19
|
-
## Raw extra_json
|
|
20
|
-
|
|
21
|
-
- `TG::Geometry::Geom#extra_json` -> UTF-8 String or nil
|
|
22
|
-
|
|
23
|
-
This returns a copied Ruby String from TG's raw extra JSON pointer. It does not parse JSON into Hashes and does not expose borrowed child wrappers. This follows the constraint that raw `extra_json` is safer than implicit `JSON.parse`.
|
|
@@ -1,109 +0,0 @@
|
|
|
1
|
-
# Full TG API coverage status
|
|
2
|
-
|
|
3
|
-
This document covers Expansion Block J as implemented in grouped, safe increments.
|
|
4
|
-
|
|
5
|
-
Block J does not mean exposing every upstream TG function in one change. The rule is: implement in groups, define ownership for each group, add tests, and avoid environment allocator overrides or global mutable settings.
|
|
6
|
-
|
|
7
|
-
## Implemented group: predicates
|
|
8
|
-
|
|
9
|
-
`TG::Geometry::Geom` now exposes additional read-only predicates:
|
|
10
|
-
|
|
11
|
-
- `equals?(other)`
|
|
12
|
-
- `disjoint?(other)`
|
|
13
|
-
- `within?(other)`
|
|
14
|
-
- `covers?(other)`
|
|
15
|
-
- `covered_by?(other)`
|
|
16
|
-
- `touches?(other)`
|
|
17
|
-
- `intersects_xy?(x, y)`
|
|
18
|
-
- `intersects_rect?(rect)`
|
|
19
|
-
- `intersects_rect?(min_x, min_y, max_x, max_y)`
|
|
20
|
-
|
|
21
|
-
Existing methods remain:
|
|
22
|
-
|
|
23
|
-
- `contains?(other)`
|
|
24
|
-
- `intersects?(other)`
|
|
25
|
-
- `covers_xy?(x, y)`
|
|
26
|
-
|
|
27
|
-
`equals?` intentionally does not change Ruby `==`, `eql?`, or `hash`. Ruby equality remains identity-based until that open API decision is explicitly made.
|
|
28
|
-
|
|
29
|
-
## Implemented group: geometry accessors
|
|
30
|
-
|
|
31
|
-
`TG::Geometry::Geom` now exposes safe read-only accessors for upstream geometry collections and coordinate metadata:
|
|
32
|
-
|
|
33
|
-
- `feature?`
|
|
34
|
-
- `feature_collection?`
|
|
35
|
-
- `empty?`
|
|
36
|
-
- `dims`
|
|
37
|
-
- `has_z?`
|
|
38
|
-
- `has_m?`
|
|
39
|
-
- `z`
|
|
40
|
-
- `m`
|
|
41
|
-
- `extra_coords`
|
|
42
|
-
- `num_points`
|
|
43
|
-
- `point_at(index)`
|
|
44
|
-
- `points`
|
|
45
|
-
- `num_lines`
|
|
46
|
-
- `line_at(index)`
|
|
47
|
-
- `lines`
|
|
48
|
-
- `num_polygons`
|
|
49
|
-
- `polygon_at(index)`
|
|
50
|
-
- `polygons`
|
|
51
|
-
- `num_geometries`
|
|
52
|
-
- `geometry_at(index)`
|
|
53
|
-
- `geometries`
|
|
54
|
-
|
|
55
|
-
`geometry_at` and `geometries` return borrowed immutable `TG::Geometry::Geom` wrappers. They keep the parent wrapper alive through `geom_owner`, mark it for GC, update it during compaction, and do not call `tg_geom_free` for the borrowed child pointer.
|
|
56
|
-
|
|
57
|
-
## Implemented group: point and empty constructors
|
|
58
|
-
|
|
59
|
-
Safe constructors are exposed only where ownership is simple and the returned object owns exactly one `struct tg_geom *`:
|
|
60
|
-
|
|
61
|
-
- `TG::Geometry.point(x, y)`
|
|
62
|
-
- `TG::Geometry.point_z(x, y, z)`
|
|
63
|
-
- `TG::Geometry.point_m(x, y, m)`
|
|
64
|
-
- `TG::Geometry.point_zm(x, y, z, m)`
|
|
65
|
-
- `TG::Geometry.empty_point`
|
|
66
|
-
- `TG::Geometry.empty_linestring`
|
|
67
|
-
- `TG::Geometry.empty_polygon`
|
|
68
|
-
- `TG::Geometry.empty_multipoint`
|
|
69
|
-
- `TG::Geometry.empty_multilinestring`
|
|
70
|
-
- `TG::Geometry.empty_multipolygon`
|
|
71
|
-
- `TG::Geometry.empty_geometrycollection`
|
|
72
|
-
|
|
73
|
-
Numeric coordinates are converted with `NUM2DBL` and rejected if NaN or Infinity.
|
|
74
|
-
|
|
75
|
-
## Implemented group: segments
|
|
76
|
-
|
|
77
|
-
`TG::Geometry::Segment` is a frozen value wrapper over one copied `struct tg_segment`.
|
|
78
|
-
|
|
79
|
-
Created by:
|
|
80
|
-
|
|
81
|
-
- `TG::Geometry::Line#segment_at(index)`
|
|
82
|
-
- `TG::Geometry::Line#segments`
|
|
83
|
-
- `TG::Geometry::Ring#segment_at(index)`
|
|
84
|
-
- `TG::Geometry::Ring#segments`
|
|
85
|
-
|
|
86
|
-
Methods:
|
|
87
|
-
|
|
88
|
-
- `a -> [Float, Float]`
|
|
89
|
-
- `b -> [Float, Float]`
|
|
90
|
-
- `points -> [[Float, Float], [Float, Float]]`
|
|
91
|
-
- `bbox -> TG::Geometry::Rect`
|
|
92
|
-
- `intersects?(other_segment)`
|
|
93
|
-
|
|
94
|
-
`TG::Geometry::Segment.allocate` is disabled. Segment wrappers do not borrow parent TG memory and do not call any TG free function.
|
|
95
|
-
|
|
96
|
-
## Still not implemented
|
|
97
|
-
|
|
98
|
-
The following remain outside this grouped implementation:
|
|
99
|
-
|
|
100
|
-
- Line/Ring/Polygon public constructors from Ruby arrays;
|
|
101
|
-
- MultiLineString / MultiPolygon constructors from low-level wrappers;
|
|
102
|
-
- callback/search APIs;
|
|
103
|
-
- nearest segment APIs;
|
|
104
|
-
- environment configuration functions;
|
|
105
|
-
- global allocator override;
|
|
106
|
-
- mutable settings;
|
|
107
|
-
- user callbacks inside C loops.
|
|
108
|
-
|
|
109
|
-
Those require separate ownership and callback-safety contracts before implementation.
|
data/docs/LOW_LEVEL_GEOMETRY.md
DELETED
|
@@ -1,121 +0,0 @@
|
|
|
1
|
-
# Low-level geometry wrappers
|
|
2
|
-
|
|
3
|
-
This document covers Expansion Block E.
|
|
4
|
-
|
|
5
|
-
## Scope
|
|
6
|
-
|
|
7
|
-
The first low-level API exposes borrowed read-only views over TG child types:
|
|
8
|
-
|
|
9
|
-
- `TG::Geometry::Line`
|
|
10
|
-
- `TG::Geometry::Ring`
|
|
11
|
-
- `TG::Geometry::Polygon`
|
|
12
|
-
- `TG::Geometry::Segment`
|
|
13
|
-
|
|
14
|
-
These wrappers are created only from `TG::Geometry::Geom`, `TG::Geometry::Polygon`, `TG::Geometry::Line`, and `TG::Geometry::Ring` methods. Public `.allocate` is disabled for all four classes.
|
|
15
|
-
|
|
16
|
-
## Ownership model
|
|
17
|
-
|
|
18
|
-
TG child accessors return borrowed pointers owned by the parent `struct tg_geom`. The Line/Ring/Polygon Ruby wrappers therefore store:
|
|
19
|
-
|
|
20
|
-
- `geom_owner`: the original `TG::Geometry::Geom` Ruby object;
|
|
21
|
-
- a borrowed `const struct tg_line *`, `const struct tg_ring *`, or `const struct tg_poly *` pointer.
|
|
22
|
-
|
|
23
|
-
The wrappers mark `geom_owner` with `rb_gc_mark_movable` and update it in `dcompact` with `rb_gc_location`. They do not call `tg_line_free`, `tg_ring_free`, or `tg_poly_free` for borrowed children.
|
|
24
|
-
|
|
25
|
-
`TG::Geometry::Segment` is a value wrapper over a copied `struct tg_segment`, so it does not store `geom_owner` and does not free any TG-owned pointer.
|
|
26
|
-
|
|
27
|
-
Allocator pairs:
|
|
28
|
-
|
|
29
|
-
Resource | Allocator | Deallocator | Owner | Notes
|
|
30
|
-
--- | --- | --- | --- | ---
|
|
31
|
-
`tg_line_wrapper_t` | `TypedData_Make_Struct` / Ruby allocator | `ruby_xfree` | Ruby object | borrowed pointer, marks parent `geom_owner`
|
|
32
|
-
`tg_ring_wrapper_t` | `TypedData_Make_Struct` / Ruby allocator | `ruby_xfree` | Ruby object | borrowed pointer, marks parent `geom_owner`
|
|
33
|
-
`tg_polygon_wrapper_t` | `TypedData_Make_Struct` / Ruby allocator | `ruby_xfree` | Ruby object | borrowed pointer, marks parent `geom_owner`
|
|
34
|
-
`tg_segment_wrapper_t` | `TypedData_Make_Struct` / Ruby allocator | `ruby_xfree` | Ruby object | owns copied `struct tg_segment` value
|
|
35
|
-
TG child pointers | parent `struct tg_geom` | parent `TG::Geometry::Geom` dfree | parent geometry | never freed by child wrappers
|
|
36
|
-
|
|
37
|
-
## Public API
|
|
38
|
-
|
|
39
|
-
### `TG::Geometry::Geom#point`
|
|
40
|
-
|
|
41
|
-
Returns `[x, y]` for point geometries. Returns `nil` for non-point geometries.
|
|
42
|
-
|
|
43
|
-
### `TG::Geometry::Geom#line`
|
|
44
|
-
|
|
45
|
-
Returns a frozen `TG::Geometry::Line` for LineString geometries. Returns `nil` otherwise.
|
|
46
|
-
|
|
47
|
-
### `TG::Geometry::Geom#polygon`
|
|
48
|
-
|
|
49
|
-
Returns a frozen `TG::Geometry::Polygon` for Polygon geometries. Returns `nil` otherwise.
|
|
50
|
-
|
|
51
|
-
### `TG::Geometry::Line`
|
|
52
|
-
|
|
53
|
-
Methods:
|
|
54
|
-
|
|
55
|
-
- `bbox -> TG::Geometry::Rect`
|
|
56
|
-
- `num_points -> Integer`
|
|
57
|
-
- `point_at(index) -> [Float, Float]`
|
|
58
|
-
- `points -> Array<[Float, Float]>`
|
|
59
|
-
- `num_segments -> Integer`
|
|
60
|
-
- `segment_at(index) -> TG::Geometry::Segment`
|
|
61
|
-
- `segments -> Array<TG::Geometry::Segment>`
|
|
62
|
-
- `length -> Float`
|
|
63
|
-
- `clockwise? -> Boolean`
|
|
64
|
-
|
|
65
|
-
`length` is measured in input coordinate units. For lon/lat data this is not meters.
|
|
66
|
-
|
|
67
|
-
### `TG::Geometry::Ring`
|
|
68
|
-
|
|
69
|
-
Methods:
|
|
70
|
-
|
|
71
|
-
- `bbox -> TG::Geometry::Rect`
|
|
72
|
-
- `num_points -> Integer`
|
|
73
|
-
- `point_at(index) -> [Float, Float]`
|
|
74
|
-
- `points -> Array<[Float, Float]>`
|
|
75
|
-
- `num_segments -> Integer`
|
|
76
|
-
- `segment_at(index) -> TG::Geometry::Segment`
|
|
77
|
-
- `segments -> Array<TG::Geometry::Segment>`
|
|
78
|
-
- `area -> Float`
|
|
79
|
-
- `perimeter -> Float`
|
|
80
|
-
- `clockwise? -> Boolean`
|
|
81
|
-
- `convex? -> Boolean`
|
|
82
|
-
|
|
83
|
-
`area` and `perimeter` are measured in input coordinate units. For lon/lat data these are not square meters or meters.
|
|
84
|
-
|
|
85
|
-
### `TG::Geometry::Polygon`
|
|
86
|
-
|
|
87
|
-
Methods:
|
|
88
|
-
|
|
89
|
-
- `bbox -> TG::Geometry::Rect`
|
|
90
|
-
- `exterior_ring -> TG::Geometry::Ring`
|
|
91
|
-
- `num_holes -> Integer`
|
|
92
|
-
- `hole_at(index) -> TG::Geometry::Ring`
|
|
93
|
-
- `holes -> Array<TG::Geometry::Ring>`
|
|
94
|
-
- `clockwise? -> Boolean`
|
|
95
|
-
|
|
96
|
-
`hole_at` rejects out-of-range indexes with `TG::Geometry::ArgumentError`.
|
|
97
|
-
|
|
98
|
-
### `TG::Geometry::Segment`
|
|
99
|
-
|
|
100
|
-
Methods:
|
|
101
|
-
|
|
102
|
-
- `a -> [Float, Float]`
|
|
103
|
-
- `b -> [Float, Float]`
|
|
104
|
-
- `points -> [[Float, Float], [Float, Float]]`
|
|
105
|
-
- `bbox -> TG::Geometry::Rect`
|
|
106
|
-
- `intersects?(other_segment) -> Boolean`
|
|
107
|
-
|
|
108
|
-
Segments are copied by value from a line or ring. They do not keep or free borrowed TG pointers.
|
|
109
|
-
|
|
110
|
-
## Error paths
|
|
111
|
-
|
|
112
|
-
- Wrong wrapper type is handled by `TypedData_Get_Struct` and raises `TypeError`.
|
|
113
|
-
- Out-of-range child indexes raise `TG::Geometry::ArgumentError`.
|
|
114
|
-
- Child wrappers are immutable and cannot be constructed directly from Ruby.
|
|
115
|
-
|
|
116
|
-
## Not implemented in this block
|
|
117
|
-
|
|
118
|
-
- Low-level constructors for Ring, Line, or Polygon.
|
|
119
|
-
- Mutable coordinate access.
|
|
120
|
-
- Polygon `area` / `perimeter` convenience aggregation. Ring-level values are exposed first to avoid undocumented assumptions about hole orientation and aggregation semantics.
|
|
121
|
-
- Geodesic length/area.
|
data/docs/RACTOR.md
DELETED
|
@@ -1,40 +0,0 @@
|
|
|
1
|
-
# Ractor investigation
|
|
2
|
-
|
|
3
|
-
This document covers Expansion Block I.
|
|
4
|
-
|
|
5
|
-
## Current result
|
|
6
|
-
|
|
7
|
-
`tg_geometry` does not claim Ractor support.
|
|
8
|
-
|
|
9
|
-
The current native wrappers are frozen and immutable for normal Ruby thread reads, but they are not Ractor-shareable Ruby objects. The test suite records this boundary with `Ractor.shareable?` and `Ractor.make_shareable` checks for:
|
|
10
|
-
|
|
11
|
-
- `TG::Geometry::Geom`
|
|
12
|
-
- `TG::Geometry::Rect`
|
|
13
|
-
- `TG::Geometry::Index`
|
|
14
|
-
|
|
15
|
-
This is an explicit unsupported boundary, not a partial support claim.
|
|
16
|
-
|
|
17
|
-
## Shareability rules
|
|
18
|
-
|
|
19
|
-
Current rule for public docs and code comments:
|
|
20
|
-
|
|
21
|
-
- Normal Ruby thread read-only use is supported by immutable object design and tests.
|
|
22
|
-
- Ractor support is not supported and not advertised.
|
|
23
|
-
- Do not use `TG::Geometry::Geom`, `TG::Geometry::Rect`, `TG::Geometry::Index`, or borrowed low-level wrappers as cross-Ractor shareable objects.
|
|
24
|
-
- Do not add Ractor-specific code paths without a new explicit design and tests.
|
|
25
|
-
|
|
26
|
-
## Why no support claim is made
|
|
27
|
-
|
|
28
|
-
The extension stores native pointers and Ruby `VALUE` references inside TypedData wrappers. The current contract validates GC marking, compaction, ownership, and normal thread read-only access. It does not define or validate cross-Ractor transfer/share semantics for those wrappers.
|
|
29
|
-
|
|
30
|
-
## Required before changing this status
|
|
31
|
-
|
|
32
|
-
Before any future Ractor support claim:
|
|
33
|
-
|
|
34
|
-
1. Define shareability rules for owned and borrowed `TG::Geometry::Geom` wrappers.
|
|
35
|
-
2. Define shareability rules for `TG::Geometry::Index` entries and id `VALUE`s.
|
|
36
|
-
3. Define behavior for borrowed Line/Ring/Polygon/Segment wrappers.
|
|
37
|
-
4. Add Ractor tests that pass on the supported Ruby matrix.
|
|
38
|
-
5. Document whether objects are shareable directly, require duplication, or are unsupported.
|
|
39
|
-
|
|
40
|
-
Until those items exist, Ractor remains unsupported.
|
data/docs/REGISTRY.md
DELETED
|
@@ -1,37 +0,0 @@
|
|
|
1
|
-
# Registry
|
|
2
|
-
|
|
3
|
-
`TG::Geometry::Registry` is Ruby-side application sugar over immutable `TG::Geometry::Index`.
|
|
4
|
-
|
|
5
|
-
It does not add a mutable native index. `reload!` always builds a new Index and then swaps a Ruby reference:
|
|
6
|
-
|
|
7
|
-
```ruby
|
|
8
|
-
class DeliveryZones < TG::Geometry::Registry
|
|
9
|
-
source do
|
|
10
|
-
[
|
|
11
|
-
[:zone_a, '{"type":"Polygon","coordinates":[[[0,0],[10,0],[10,10],[0,10],[0,0]]]}']
|
|
12
|
-
]
|
|
13
|
-
end
|
|
14
|
-
end
|
|
15
|
-
|
|
16
|
-
registry = DeliveryZones.new(via: :geojson, strategy: :rtree)
|
|
17
|
-
registry.reload!
|
|
18
|
-
registry.find_covering(5, 5)
|
|
19
|
-
```
|
|
20
|
-
|
|
21
|
-
Readers capture the current immutable Index. An active reader can continue using the old Index while `reload!` builds and swaps a new one.
|
|
22
|
-
|
|
23
|
-
## API
|
|
24
|
-
|
|
25
|
-
- `source { ... }` on a subclass defines the entry source.
|
|
26
|
-
- `index_options(...)` on a subclass sets default Index options.
|
|
27
|
-
- `reload!` builds and swaps a new Index.
|
|
28
|
-
- `find_covering`, `covering_ids`, `intersecting_rect`, and `covering_ids_batch_packed` delegate to the current Index.
|
|
29
|
-
- `index`, `size`, `bbox`, and `loaded?` expose current state.
|
|
30
|
-
|
|
31
|
-
The source must return the strict first-release entry format:
|
|
32
|
-
|
|
33
|
-
```ruby
|
|
34
|
-
[[id, object], [id, object], ...]
|
|
35
|
-
```
|
|
36
|
-
|
|
37
|
-
No Redis dependency, no Rails dependency, no global native singleton, and no in-place Index mutation are introduced.
|
data/docs/RELEASE_CHECKLIST.md
DELETED
|
@@ -1,39 +0,0 @@
|
|
|
1
|
-
# First public release checklist
|
|
2
|
-
|
|
3
|
-
This checklist is intentionally conservative. Do not publish until every required item is satisfied.
|
|
4
|
-
|
|
5
|
-
## Required state before release
|
|
6
|
-
|
|
7
|
-
- [ ] All release-core specs pass locally.
|
|
8
|
-
- [ ] GC.stress specs pass.
|
|
9
|
-
- [ ] GC.compact specs pass.
|
|
10
|
-
- [ ] ASAN status is documented.
|
|
11
|
-
- [ ] Valgrind status is documented.
|
|
12
|
-
- [ ] Benchmark scripts exist and have been run for the full scenario matrix.
|
|
13
|
-
- [ ] README and docs are complete.
|
|
14
|
-
- [ ] Gem metadata is final:
|
|
15
|
-
- gem name: `tg_geometry`;
|
|
16
|
-
- author: `Roman Haydarov`;
|
|
17
|
-
- email: `romnhajdarov@gmail.com`;
|
|
18
|
-
- repository: `https://github.com/roman-haidarov/tg_geometry`.
|
|
19
|
-
- [ ] Vendored TG and rtree versions are pinned in `VERSION` files.
|
|
20
|
-
- [ ] Upstream license files are included under `ext/tg_geometry/vendor/*/LICENSE`.
|
|
21
|
-
- [ ] `CHANGELOG.md` exists.
|
|
22
|
-
|
|
23
|
-
## Do not release if any of these are true
|
|
24
|
-
|
|
25
|
-
- [ ] Any OPEN QUESTION affects correctness.
|
|
26
|
-
- [ ] Any memory accounting path is approximate.
|
|
27
|
-
- [ ] Any failed build path waits for GC instead of immediate dispose.
|
|
28
|
-
- [ ] `strategy: :auto` is enabled without benchmark-derived threshold.
|
|
29
|
-
- [ ] Public API differs from the contract without Roman approval.
|
|
30
|
-
- [ ] Ractor support is claimed.
|
|
31
|
-
- [ ] Performance claims are present without project-owned benchmark output.
|
|
32
|
-
|
|
33
|
-
## OPEN QUESTION: ASAN setup
|
|
34
|
-
|
|
35
|
-
ASAN setup is not fully specified in the contract and the worker must not research it independently. The repository contains a placeholder CI job that fails with an explicit message until Roman approves the exact ASAN approach.
|
|
36
|
-
|
|
37
|
-
## OPEN QUESTION: Valgrind setup
|
|
38
|
-
|
|
39
|
-
Valgrind setup can vary by CI image and Ruby build. The repository contains a placeholder CI job that installs/runs nothing by default and asks for approval before adding a final Valgrind configuration.
|
|
File without changes
|