tg_geometry 0.2.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.
Files changed (38) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +37 -0
  3. data/README.md +107 -14
  4. data/benchmark/ewkb_roundtrip.rb +29 -0
  5. data/benchmark/geom_query.rb +33 -0
  6. data/benchmark/nearest_segment.rb +20 -0
  7. data/docs/GEOMETRY_QUERIES.md +23 -0
  8. data/docs/LIMITATIONS.md +12 -10
  9. data/docs/NEAREST_SEGMENT.md +17 -0
  10. data/docs/SRID_AND_EWKB.md +23 -0
  11. data/ext/tg_geometry/tg_geometry_ext.c +1176 -4
  12. data/lib/tg/geometry/active_record_source.rb +16 -34
  13. data/lib/tg/geometry/active_record_type.rb +61 -0
  14. data/lib/tg/geometry/registry.rb +17 -68
  15. data/lib/tg/geometry/version.rb +1 -1
  16. data/lib/tg/geometry.rb +85 -0
  17. data/spec/active_record_type_spec.rb +45 -0
  18. data/spec/constructors_spec.rb +104 -0
  19. data/spec/fixtures/feature_source/invalid_geometry_middle.geojson +8 -0
  20. data/spec/fixtures/feature_source/malformed_json.geojson +1 -0
  21. data/spec/fixtures/feature_source/mixed_geometry_types.geojson +8 -0
  22. data/spec/fixtures/feature_source/osm_like_feature_collection.geojson +10 -0
  23. data/spec/fixtures/feature_source/properties_null_missing.geojson +7 -0
  24. data/spec/fixtures/feature_source/simple_feature_collection.geojson +15 -0
  25. data/spec/fixtures/postgis/README.md +16 -0
  26. data/spec/fixtures/postgis/boundary_point_cases.geojson +83 -0
  27. data/spec/fixtures/postgis/multipolygon_large.ewkb +0 -0
  28. data/spec/fixtures/postgis/point_4326.ewkb +0 -0
  29. data/spec/fixtures/postgis/polygon_3857.ewkb +0 -0
  30. data/spec/fixtures/postgis/polygon_4326_simple.ewkb +0 -0
  31. data/spec/fixtures/postgis/polygon_4326_with_hole.ewkb +0 -0
  32. data/spec/index_geom_query_spec.rb +68 -0
  33. data/spec/keyword_validation_spec.rb +31 -0
  34. data/spec/nearest_segment_spec.rb +62 -0
  35. data/spec/postgis_fixtures_spec.rb +68 -0
  36. data/spec/srid_spec.rb +43 -0
  37. data/spec/to_ewkb_spec.rb +37 -0
  38. metadata +50 -2
@@ -0,0 +1,68 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "spec_helper"
4
+
5
+ RSpec.describe "Index geometry queries" do
6
+ def polygon(min_x, min_y, max_x, max_y)
7
+ TG::Geometry.polygon([[min_x, min_y], [max_x, min_y], [max_x, max_y], [min_x, max_y], [min_x, min_y]])
8
+ end
9
+
10
+ let(:zones) do
11
+ [
12
+ [:a, polygon(0, 0, 10, 10)],
13
+ [:b, polygon(8, 8, 18, 18)],
14
+ [:c, polygon(30, 30, 40, 40)]
15
+ ]
16
+ end
17
+
18
+ def build(strategy)
19
+ TG::Geometry::Index.build(zones, via: :geom, strategy: strategy)
20
+ end
21
+
22
+ it "returns intersecting ids in insertion order" do
23
+ query = polygon(9, 9, 12, 12)
24
+
25
+ expect(build(:flat).intersecting_geom_ids(query)).to eq(%i[a b])
26
+ expect(build(:rtree).intersecting_geom_ids(query)).to eq(%i[a b])
27
+ end
28
+
29
+ it "supports line query intersections" do
30
+ query = TG::Geometry.line_string([[35, 35], [45, 45]])
31
+
32
+ expect(build(:flat).intersecting_geom_ids(query)).to eq([:c])
33
+ end
34
+
35
+ it "returns empty arrays for outside query geometries" do
36
+ expect(build(:rtree).intersecting_geom_ids(polygon(100, 100, 101, 101))).to eq([])
37
+ end
38
+
39
+ it "uses stored_geom covers query semantics" do
40
+ index = build(:flat)
41
+
42
+ expect(index.covering_geom_ids(TG::Geometry.point(5, 5))).to eq([:a])
43
+ expect(index.covering_geom_ids(TG::Geometry.point(0, 5))).to eq([:a])
44
+ expect(index.covering_geom_ids(polygon(9, 9, 12, 12))).to eq([:b])
45
+ end
46
+
47
+ it "uses stored_geom contains query semantics and excludes boundary" do
48
+ index = build(:flat)
49
+
50
+ expect(index.containing_geom_ids(TG::Geometry.point(5, 5))).to eq([:a])
51
+ expect(index.containing_geom_ids(TG::Geometry.point(0, 5))).to eq([])
52
+ expect(index.covering_geom_ids(TG::Geometry.point(0, 5))).to eq([:a])
53
+ end
54
+
55
+ it "does not read Index.build predicate for geometry methods" do
56
+ index = TG::Geometry::Index.build(zones, via: :geom, strategy: :flat, predicate: :contains)
57
+
58
+ expect(index.covering_geom_ids(TG::Geometry.point(0, 5))).to eq([:a])
59
+ end
60
+
61
+ it "raises TypeError for non-Geom query values" do
62
+ index = build(:flat)
63
+
64
+ expect { index.intersecting_geom_ids(nil) }.to raise_error(TypeError)
65
+ expect { index.covering_geom_ids("bad") }.to raise_error(TypeError)
66
+ expect { index.containing_geom_ids(1) }.to raise_error(TypeError)
67
+ end
68
+ end
@@ -0,0 +1,31 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "spec_helper"
4
+
5
+ RSpec.describe "strict keyword validation" do
6
+ let(:geom_without_srid) { TG::Geometry.parse_wkt("POINT (1 2)") }
7
+ let(:wkb) { geom_without_srid.to_wkb }
8
+
9
+ it "rejects unsupported SRID and EWKB flags on parse_wkb" do
10
+ expect { TG::Geometry.parse_wkb(wkb, srid: 4326) }
11
+ .to raise_error(TG::Geometry::ArgumentError, /unknown keyword: :srid/)
12
+ expect { TG::Geometry.parse_wkb(wkb, ewkb: true) }
13
+ .to raise_error(TG::Geometry::ArgumentError, /unknown keyword: :ewkb/)
14
+ end
15
+
16
+ it "rejects public release_gvl knobs on new v0.3.0 APIs" do
17
+ expect { TG::Geometry.line_string([[0, 0], [1, 1]], release_gvl: true) }
18
+ .to raise_error(TG::Geometry::ArgumentError, /unknown keyword: :release_gvl/)
19
+ expect { geom_without_srid.to_ewkb(srid: 4326, release_gvl: true) }
20
+ .to raise_error(TG::Geometry::ArgumentError, /unknown keyword: :release_gvl/)
21
+ end
22
+
23
+ it "rejects unknown constructor keywords" do
24
+ square = [[0, 0], [1, 0], [1, 1], [0, 0]]
25
+
26
+ expect { TG::Geometry.polygon(square, autoclose: true) }
27
+ .to raise_error(TG::Geometry::ArgumentError, /unknown keyword: :autoclose/)
28
+ expect { TG::Geometry.multi_polygon([{ exterior: square, holes: [], extra: true }]) }
29
+ .to raise_error(TG::Geometry::ArgumentError, /unknown keyword: :extra/)
30
+ end
31
+ end
@@ -0,0 +1,62 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "spec_helper"
4
+
5
+ RSpec.describe "nearest_segment" do
6
+ it "finds nearest line segments and projection points" do
7
+ line = TG::Geometry.line_string([[0, 0], [10, 0], [10, 10]]).line
8
+ nearest = line.nearest_segment(5, 3)
9
+
10
+ expect(nearest).to be_a(TG::Geometry::NearestSegment)
11
+ expect(nearest).to be_frozen
12
+ expect(nearest.segment).to be_a(TG::Geometry::Segment)
13
+ expect(nearest.index).to be >= 0
14
+ expect(nearest.distance).to be_within(1e-12).of(3.0)
15
+ expect(nearest.point).to eq([5.0, 0.0])
16
+ end
17
+
18
+ it "returns zero distance for a point on a segment" do
19
+ nearest = TG::Geometry.line_string([[0, 0], [10, 0]]).line.nearest_segment(5, 0)
20
+
21
+ expect(nearest.index).to eq(0)
22
+ expect(nearest.distance).to be_within(1e-12).of(0.0)
23
+ expect(nearest.point).to eq([5.0, 0.0])
24
+ end
25
+
26
+ it "handles outside-bbox and degenerate segments" do
27
+ outside = TG::Geometry.line_string([[0, 0], [10, 0]]).line.nearest_segment(20, 5)
28
+ degenerate = TG::Geometry.line_string([[1, 1], [1, 1]]).line.nearest_segment(4, 5)
29
+
30
+ expect(outside.index).to eq(0)
31
+ expect(outside.point).to eq([10.0, 0.0])
32
+ expect(degenerate.index).to eq(0)
33
+ expect(degenerate.point).to eq([1.0, 1.0])
34
+ end
35
+
36
+ it "finds nearest ring segments without depending on equal-distance tie break" do
37
+ ring = TG::Geometry.polygon([[0, 0], [10, 0], [10, 10], [0, 10], [0, 0]]).polygon.exterior_ring
38
+ center = ring.nearest_segment(5, 5)
39
+ corner = ring.nearest_segment(0, 0)
40
+
41
+ expect(center.index).to be_between(0, 3).inclusive
42
+ expect(center.distance).to be_within(1e-12).of(5.0)
43
+ expect(corner.distance).to be_within(1e-12).of(0.0)
44
+ end
45
+
46
+ it "keeps nearest result valid after parent GC" do
47
+ nearest = TG::Geometry.line_string([[0, 0], [10, 0]]).line.nearest_segment(5, 2)
48
+
49
+ GC.start
50
+ GC.compact if GC.respond_to?(:compact)
51
+
52
+ expect(nearest.segment.points).to eq([[0.0, 0.0], [10.0, 0.0]])
53
+ expect(nearest.point).to eq([5.0, 0.0])
54
+ end
55
+
56
+ it "rejects non-finite coordinates" do
57
+ line = TG::Geometry.line_string([[0, 0], [10, 0]]).line
58
+
59
+ expect { line.nearest_segment(Float::NAN, 0) }.to raise_error(TG::Geometry::ArgumentError)
60
+ expect { line.nearest_segment(0, Float::INFINITY) }.to raise_error(TG::Geometry::ArgumentError)
61
+ end
62
+ end
@@ -0,0 +1,68 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "json"
4
+ require "spec_helper"
5
+
6
+ RSpec.describe "PostGIS EWKB fixtures" do
7
+ FIXTURE_ROOT = File.expand_path("fixtures/postgis", __dir__)
8
+
9
+ CASES = {
10
+ "point_4326.ewkb" => { srid: 4326, bbox: [37.6, 55.7, 37.6, 55.7] },
11
+ "polygon_4326_simple.ewkb" => { srid: 4326, bbox: [0.0, 0.0, 10.0, 10.0] },
12
+ "polygon_4326_with_hole.ewkb" => { srid: 4326, bbox: [0.0, 0.0, 10.0, 10.0] },
13
+ "polygon_3857.ewkb" => { srid: 3857, bbox: [0.0, 0.0, 10.0, 10.0] },
14
+ "multipolygon_large.ewkb" => { srid: 4326, bbox: [99.0, 49.0, 101.0, 51.0] }
15
+ }.freeze
16
+
17
+ CASES.each do |filename, expected|
18
+ it "parses and roundtrips #{filename}" do
19
+ bytes = File.binread(File.join(FIXTURE_ROOT, filename))
20
+ geom = TG::Geometry.parse_wkb(bytes)
21
+ bbox = geom.bbox
22
+
23
+ expect(geom.srid).to eq(expected[:srid])
24
+ expect([bbox.min_x, bbox.min_y, bbox.max_x, bbox.max_y]).to all(be_a(Float))
25
+ [bbox.min_x, bbox.min_y, bbox.max_x, bbox.max_y].zip(expected[:bbox]).each do |actual, expected_coord|
26
+ expect(actual).to be_within(1e-9).of(expected_coord)
27
+ end
28
+ expect(geom.to_ewkb).to eq(bytes)
29
+ expect(TG::Geometry.parse_wkb(geom.to_wkb).srid).to be_nil
30
+ end
31
+ end
32
+
33
+ it "keeps hole coverage semantics stable" do
34
+ geom = TG::Geometry.parse_wkb(File.binread(File.join(FIXTURE_ROOT, "polygon_4326_with_hole.ewkb")))
35
+
36
+ expect(geom.covers_xy?(3, 3)).to be(false)
37
+ expect(geom.covers_xy?(1, 1)).to be(true)
38
+ end
39
+
40
+ it "checks boundary cases from GeoJSON" do
41
+ simple = TG::Geometry.parse_wkb(File.binread(File.join(FIXTURE_ROOT, "polygon_4326_simple.ewkb")))
42
+ data = JSON.parse(File.read(File.join(FIXTURE_ROOT, "boundary_point_cases.geojson")))
43
+ points = data.fetch("features").to_h do |feature|
44
+ [feature.fetch("properties").fetch("name"), feature.fetch("geometry").fetch("coordinates")]
45
+ end
46
+
47
+ expect(simple.covers_xy?(*points.fetch("inside_simple"))).to be(true)
48
+ expect(simple.covers_xy?(*points.fetch("boundary_simple"))).to be(true)
49
+ end
50
+
51
+ it "sanity-checks the large multipolygon quickly" do
52
+ started = Process.clock_gettime(Process::CLOCK_MONOTONIC)
53
+ geom = TG::Geometry.parse_wkb(File.binread(File.join(FIXTURE_ROOT, "multipolygon_large.ewkb")))
54
+ elapsed = Process.clock_gettime(Process::CLOCK_MONOTONIC) - started
55
+
56
+ expect(elapsed).to be < 1.0
57
+ expect(geom.covers_xy?(100.0, 50.0)).to be(true)
58
+ expect(geom.covers_xy?(200.0, 50.0)).to be(false)
59
+ end
60
+
61
+ it "documents SRID mismatch as user responsibility" do
62
+ geom_4326 = TG::Geometry.parse_wkb(File.binread(File.join(FIXTURE_ROOT, "polygon_4326_simple.ewkb")))
63
+ geom_3857 = TG::Geometry.parse_wkb(File.binread(File.join(FIXTURE_ROOT, "polygon_3857.ewkb")))
64
+
65
+ expect(geom_4326.srid).not_to eq(geom_3857.srid)
66
+ expect(geom_4326.intersects?(geom_3857)).to be(true)
67
+ end
68
+ end
data/spec/srid_spec.rb ADDED
@@ -0,0 +1,43 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "spec_helper"
4
+
5
+ RSpec.describe "SRID metadata" do
6
+ let(:plain_wkb) { TG::Geometry.parse_wkt("POINT (1 2)").to_wkb }
7
+ let(:ewkb_4326) { TG::Geometry.parse_wkt("POINT (1 2)").to_ewkb(srid: 4326) }
8
+ let(:ewkb_3857) { TG::Geometry.parse_wkt("POINT (1 2)").to_ewkb(srid: 3857) }
9
+ let(:ewkb_0) { TG::Geometry.parse_wkt("POINT (1 2)").to_ewkb(srid: 0) }
10
+
11
+ it "returns nil for plain WKB and non-SRID text formats" do
12
+ expect(TG::Geometry.parse_wkb(plain_wkb).srid).to be_nil
13
+ expect(TG::Geometry.parse_geojson('{"type":"Point","coordinates":[1,2]}').srid).to be_nil
14
+ expect(TG::Geometry.parse_wkt("POINT (1 2)").srid).to be_nil
15
+ end
16
+
17
+ it "extracts SRID from little-endian EWKB and hex EWKB" do
18
+ geom = TG::Geometry.parse_wkb(ewkb_4326)
19
+
20
+ expect(geom.srid).to eq(4326)
21
+ expect([geom.bbox.min_x, geom.bbox.min_y]).to eq([1.0, 2.0])
22
+ expect(TG::Geometry.parse_wkb(ewkb_3857).srid).to eq(3857)
23
+ expect(TG::Geometry.parse_wkb(ewkb_0).srid).to eq(0)
24
+ expect(TG::Geometry.parse_hex(ewkb_4326.unpack1("H*")).srid).to eq(4326)
25
+ end
26
+
27
+ it "extracts SRID from big-endian EWKB" do
28
+ # Big-endian EWKB: byte order 0, type POINT | SRID flag, SRID 4326, x=1.0, y=2.0.
29
+ ewkb = [0, 0x20000001, 4326].pack("C N N") + [1.0, 2.0].pack("G G")
30
+
31
+ expect(TG::Geometry.parse_wkb(ewkb).srid).to eq(4326)
32
+ expect(TG::Geometry.parse_wkb(ewkb).point).to eq([1.0, 2.0])
33
+ end
34
+
35
+ it "does not crash on malformed EWKB" do
36
+ expect { TG::Geometry.parse_wkb("\x01\x01\x00".b) }.to raise_error(TG::Geometry::ParseError)
37
+ end
38
+
39
+ it "uses constructor srid metadata" do
40
+ expect(TG::Geometry.polygon([[0, 0], [1, 0], [1, 1], [0, 0]], srid: 4326).srid).to eq(4326)
41
+ expect(TG::Geometry.polygon([[0, 0], [1, 0], [1, 1], [0, 0]]).srid).to be_nil
42
+ end
43
+ end
@@ -0,0 +1,37 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "spec_helper"
4
+
5
+ RSpec.describe "Geom#to_ewkb" do
6
+ let(:geom_without_srid) { TG::Geometry.parse_wkt("POLYGON ((0 0, 10 0, 10 10, 0 10, 0 0))") }
7
+ let(:geom_with_srid) { TG::Geometry.parse_wkb(geom_without_srid.to_ewkb(srid: 4326)) }
8
+
9
+ it "roundtrips semantic geometry and SRID" do
10
+ ewkb = geom_with_srid.to_ewkb
11
+ reparsed = TG::Geometry.parse_wkb(ewkb)
12
+
13
+ expect(reparsed.srid).to eq(4326)
14
+ expect(reparsed.type).to eq(:polygon)
15
+ expect(reparsed.bbox.max_x).to eq(10.0)
16
+ expect(reparsed.covers_xy?(5, 5)).to be(true)
17
+ end
18
+
19
+ it "can add or override SRID explicitly" do
20
+ expect(TG::Geometry.parse_wkb(geom_without_srid.to_ewkb(srid: 4326)).srid).to eq(4326)
21
+ expect(TG::Geometry.parse_wkb(geom_with_srid.to_ewkb(srid: 3857)).srid).to eq(3857)
22
+ end
23
+
24
+ it "returns frozen binary strings" do
25
+ ewkb = geom_with_srid.to_ewkb
26
+
27
+ expect(ewkb.encoding).to eq(Encoding::BINARY)
28
+ expect(ewkb).to be_frozen
29
+ end
30
+
31
+ it "rejects missing or invalid SRID" do
32
+ expect { geom_without_srid.to_ewkb }.to raise_error(TG::Geometry::ArgumentError)
33
+ expect { geom_with_srid.to_ewkb(srid: -1) }.to raise_error(TG::Geometry::ArgumentError)
34
+ expect { geom_with_srid.to_ewkb(srid: 2**31) }.to raise_error(TG::Geometry::ArgumentError)
35
+ expect { geom_with_srid.to_ewkb(srid: "4326") }.to raise_error(TG::Geometry::ArgumentError)
36
+ end
37
+ end
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.2.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-26 00:00:00.000000000 Z
11
+ date: 2026-05-27 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rake
@@ -38,6 +38,26 @@ 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
@@ -61,10 +81,13 @@ files:
61
81
  - Rakefile
62
82
  - benchmark/_support.rb
63
83
  - benchmark/batch_packed_vs_loop.rb
84
+ - benchmark/ewkb_roundtrip.rb
64
85
  - benchmark/falcon_concurrency.rb
65
86
  - benchmark/feature_source.rb
66
87
  - benchmark/flat_vs_rtree.rb
88
+ - benchmark/geom_query.rb
67
89
  - benchmark/gvl_threshold.rb
90
+ - benchmark/nearest_segment.rb
68
91
  - benchmark/objectspace_memsize.rb
69
92
  - benchmark/parse_throughput.rb
70
93
  - benchmark/rss_stability.rb
@@ -74,8 +97,11 @@ files:
74
97
  - docs/CONCURRENCY.md
75
98
  - docs/ERROR_HANDLING.md
76
99
  - docs/FEATURE_SOURCE.md
100
+ - docs/GEOMETRY_QUERIES.md
77
101
  - docs/LIMITATIONS.md
78
102
  - docs/MEMORY_OWNERSHIP.md
103
+ - docs/NEAREST_SEGMENT.md
104
+ - docs/SRID_AND_EWKB.md
79
105
  - ext/tg_geometry/extconf.rb
80
106
  - ext/tg_geometry/tg_geometry_ext.c
81
107
  - ext/tg_geometry/tg_geometry_vendor_json.c
@@ -98,17 +124,33 @@ files:
98
124
  - ext/tg_geometry/vendor/tg/tg.h
99
125
  - lib/tg/geometry.rb
100
126
  - lib/tg/geometry/active_record_source.rb
127
+ - lib/tg/geometry/active_record_type.rb
101
128
  - lib/tg/geometry/registry.rb
102
129
  - lib/tg/geometry/version.rb
103
130
  - lib/tg_geometry.rb
104
131
  - script/vendor_libs.rb
105
132
  - spec/active_record_source_spec.rb
133
+ - spec/active_record_type_spec.rb
106
134
  - spec/auto_strategy_spec.rb
107
135
  - spec/batch_packed_spec.rb
108
136
  - spec/concurrency_spec.rb
137
+ - spec/constructors_spec.rb
109
138
  - spec/error_hardening_spec.rb
110
139
  - spec/feature_source_nogvl_spec.rb
111
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
112
154
  - spec/format_coverage_spec.rb
113
155
  - spec/fuzz_spec.rb
114
156
  - spec/geom_api_spec.rb
@@ -116,17 +158,23 @@ files:
116
158
  - spec/index_borrowed_geometry_spec.rb
117
159
  - spec/index_build_spec.rb
118
160
  - spec/index_flat_query_spec.rb
161
+ - spec/index_geom_query_spec.rb
119
162
  - spec/index_owned_geometry_spec.rb
120
163
  - spec/index_rtree_accounting_spec.rb
121
164
  - spec/index_rtree_order_spec.rb
165
+ - spec/keyword_validation_spec.rb
122
166
  - spec/load_and_errors_spec.rb
123
167
  - spec/low_level_geometry_spec.rb
124
168
  - spec/memory_gc_spec.rb
169
+ - spec/nearest_segment_spec.rb
170
+ - spec/postgis_fixtures_spec.rb
125
171
  - spec/ractor_spec.rb
126
172
  - spec/rect_api_spec.rb
127
173
  - spec/registry_spec.rb
128
174
  - spec/spec_helper.rb
175
+ - spec/srid_spec.rb
129
176
  - spec/tg_api_coverage_spec.rb
177
+ - spec/to_ewkb_spec.rb
130
178
  - spec/vendor_sources_spec.rb
131
179
  homepage: https://github.com/roman-haidarov/tg_geometry
132
180
  licenses: