ffi-geos 2.2.0 → 2.4.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 (42) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/main.yml +49 -0
  3. data/.rubocop-minitest.yml +240 -0
  4. data/.rubocop.yml +497 -111
  5. data/.rubocop_todo.yml +100 -0
  6. data/Gemfile +3 -6
  7. data/MIT-LICENSE +1 -1
  8. data/README.rdoc +2 -0
  9. data/ffi-geos.gemspec +5 -0
  10. data/lib/ffi-geos/buffer_params.rb +1 -1
  11. data/lib/ffi-geos/coordinate_sequence.rb +32 -32
  12. data/lib/ffi-geos/geojson_reader.rb +35 -0
  13. data/lib/ffi-geos/geojson_writer.rb +49 -0
  14. data/lib/ffi-geos/geometry.rb +11 -5
  15. data/lib/ffi-geos/geometry_collection.rb +5 -5
  16. data/lib/ffi-geos/line_string.rb +11 -11
  17. data/lib/ffi-geos/multi_line_string.rb +1 -1
  18. data/lib/ffi-geos/point.rb +4 -4
  19. data/lib/ffi-geos/polygon.rb +5 -5
  20. data/lib/ffi-geos/prepared_geometry.rb +21 -1
  21. data/lib/ffi-geos/strtree.rb +1 -1
  22. data/lib/ffi-geos/version.rb +1 -1
  23. data/lib/ffi-geos/wkb_reader.rb +1 -1
  24. data/lib/ffi-geos/wkb_writer.rb +14 -2
  25. data/lib/ffi-geos/wkt_reader.rb +1 -1
  26. data/lib/ffi-geos/wkt_writer.rb +2 -2
  27. data/lib/ffi-geos.rb +92 -4
  28. data/sonar-project.properties +4 -4
  29. data/test/coordinate_sequence_tests.rb +6 -6
  30. data/test/geojson_reader_tests.rb +170 -0
  31. data/test/geojson_writer_tests.rb +103 -0
  32. data/test/geometry_collection_tests.rb +4 -4
  33. data/test/geometry_tests.rb +75 -32
  34. data/test/line_string_tests.rb +13 -5
  35. data/test/point_tests.rb +3 -3
  36. data/test/polygon_tests.rb +3 -3
  37. data/test/prepared_geometry_tests.rb +30 -0
  38. data/test/strtree_tests.rb +8 -8
  39. data/test/test_helper.rb +43 -12
  40. data/test/wkb_writer_tests.rb +20 -0
  41. metadata +15 -6
  42. data/.travis.yml +0 -32
@@ -34,7 +34,7 @@ module Geos
34
34
  raise ParseError, e
35
35
  end
36
36
 
37
- def self.release(ptr) #:nodoc:
37
+ def self.release(ptr) # :nodoc:
38
38
  FFIGeos.GEOSWKBReader_destroy_r(Geos.current_handle_pointer, ptr)
39
39
  end
40
40
  end
@@ -20,7 +20,7 @@ module Geos
20
20
  set_options(options)
21
21
  end
22
22
 
23
- def self.release(ptr) #:nodoc:
23
+ def self.release(ptr) # :nodoc:
24
24
  FFIGeos.GEOSWKBWriter_destroy_r(Geos.current_handle_pointer, ptr)
25
25
  end
26
26
 
@@ -83,9 +83,21 @@ module Geos
83
83
  FFIGeos.GEOSWKBWriter_setByteOrder_r(Geos.current_handle_pointer, ptr, val)
84
84
  end
85
85
 
86
+ if FFIGeos.respond_to?(:GEOSWKBWriter_getFlavor_r)
87
+ def flavor
88
+ FFIGeos.GEOSWKBWriter_getFlavor_r(Geos.current_handle_pointer, ptr)
89
+ end
90
+ end
91
+
92
+ if FFIGeos.respond_to?(:GEOSWKBWriter_setFlavor_r)
93
+ def flavor=(val)
94
+ FFIGeos.GEOSWKBWriter_setFlavor_r(Geos.current_handle_pointer, ptr, val)
95
+ end
96
+ end
97
+
86
98
  private
87
99
 
88
- def set_options(options) #:nodoc:
100
+ def set_options(options) # :nodoc:
89
101
  self.include_srid = options[:include_srid] if options.key?(:include_srid)
90
102
  end
91
103
  end
@@ -28,7 +28,7 @@ module Geos
28
28
  raise ParseError, e
29
29
  end
30
30
 
31
- def self.release(ptr) #:nodoc:
31
+ def self.release(ptr) # :nodoc:
32
32
  FFIGeos.GEOSWKTReader_destroy_r(Geos.current_handle_pointer, ptr)
33
33
  end
34
34
  end
@@ -21,11 +21,11 @@ module Geos
21
21
  set_options(options)
22
22
  end
23
23
 
24
- def self.release(ptr) #:nodoc:
24
+ def self.release(ptr) # :nodoc:
25
25
  FFIGeos.GEOSWKTWriter_destroy_r(Geos.current_handle_pointer, ptr)
26
26
  end
27
27
 
28
- def set_options(options) #:nodoc:
28
+ def set_options(options) # :nodoc:
29
29
  [:trim, :old_3d, :rounding_precision, :output_dimensions].each do |k|
30
30
  send("#{k}=", options[k]) if respond_to?("#{k}=") && options.key?(k)
31
31
  end
data/lib/ffi-geos.rb CHANGED
@@ -15,6 +15,10 @@ module Geos
15
15
  File.join(GEOS_BASE, 'wkb_reader')
16
16
  autoload :WkbWriter,
17
17
  File.join(GEOS_BASE, 'wkb_writer')
18
+ autoload :GeoJSONReader,
19
+ File.join(GEOS_BASE, 'geojson_reader')
20
+ autoload :GeoJSONWriter,
21
+ File.join(GEOS_BASE, 'geojson_writer')
18
22
  autoload :CoordinateSequence,
19
23
  File.join(GEOS_BASE, 'coordinate_sequence')
20
24
  autoload :Geometry,
@@ -56,7 +60,13 @@ module Geos
56
60
  elsif FFI::Platform::IS_WINDOWS
57
61
  ENV['PATH'].split(File::PATH_SEPARATOR)
58
62
  else
59
- ['/usr/local/{lib64,lib}', '/opt/local/{lib64,lib}', '/usr/{lib64,lib}', '/usr/lib/{x86_64,i386}-linux-gnu']
63
+ [
64
+ '/usr/local/{lib64,lib}',
65
+ '/opt/local/{lib64,lib}',
66
+ '/usr/{lib64,lib}',
67
+ '/opt/homebrew/lib',
68
+ '/usr/lib/{x86_64,i386,aarch64}-linux-gnu'
69
+ ]
60
70
  end
61
71
  end
62
72
 
@@ -98,6 +108,11 @@ module Geos
98
108
  :ndr, 1 # Little Endian
99
109
  ])
100
110
 
111
+ Geos::Flavors = enum(:flavor, [
112
+ :extended, 1,
113
+ :iso, 2
114
+ ])
115
+
101
116
  Geos::BufferCapStyles = enum(:buffer_cap_style, [
102
117
  :round, 1,
103
118
  :flat, 2,
@@ -581,6 +596,11 @@ module Geos
581
596
  :pointer, :pointer, :pointer, :double, :int
582
597
  ],
583
598
 
599
+ GEOSConstrainedDelaunayTriangulation_r: [
600
+ # *geom, *handle, *geom
601
+ :pointer, :pointer, :pointer
602
+ ],
603
+
584
604
  GEOSVoronoiDiagram_r: [
585
605
  # *geom, *handle, *geom, *envelope, tolerance, only_edges
586
606
  :pointer, :pointer, :pointer, :pointer, :double, :int
@@ -721,6 +741,11 @@ module Geos
721
741
  :int, :pointer, :pointer, :pointer, :pointer
722
742
  ],
723
743
 
744
+ GEOSDistanceWithin_r: [
745
+ # (0 on exception, 1 otherwise), *handle, *geom_a, *geom_b, double distance
746
+ :char, :pointer, :pointer, :pointer, :double
747
+ ],
748
+
724
749
  GEOSHausdorffDistance_r: [
725
750
  # (0 on exception, 1 otherwise), *handle, *geom_a, *geom_b, (double *) distance
726
751
  :int, :pointer, :pointer, :pointer, :pointer
@@ -949,6 +974,21 @@ module Geos
949
974
  # (2 on exception, 1 on true, 0 on false), *handle, *prepared, *geom
950
975
  :char, :pointer, :pointer, :pointer
951
976
  ],
977
+
978
+ GEOSPreparedDistance_r: [
979
+ # (1 on success, 0 on failure), *handle, *prepared, *geom, *distance
980
+ :int, :pointer, :pointer, :pointer, :pointer
981
+ ],
982
+
983
+ GEOSPreparedDistanceWithin_r: [
984
+ # (1 on true, 0 on false), *handle, *prepared, *geom, max_distance
985
+ :char, :pointer, :pointer, :pointer, :double
986
+ ],
987
+
988
+ GEOSPreparedNearestPoints_r: [
989
+ # *coord_seq, *handle, *prepared, *geom
990
+ :pointer, :pointer, :pointer, :pointer
991
+ ],
952
992
  #### /PreparedGeometry functions ####
953
993
 
954
994
  #### WktReader functions ####
@@ -1082,8 +1122,52 @@ module Geos
1082
1122
  # void, *handle, *geom, bool
1083
1123
  :void, :pointer, :pointer, :char
1084
1124
  ],
1125
+
1126
+ GEOSWKBWriter_getFlavor_r: [
1127
+ # flavor, *handle, *geom
1128
+ :flavor, :pointer, :pointer
1129
+ ],
1130
+
1131
+ GEOSWKBWriter_setFlavor_r: [
1132
+ # void, *handle, *geom, flavor
1133
+ :void, :pointer, :pointer, :flavor
1134
+ ],
1085
1135
  #### /WkbWriter functions ####
1086
1136
 
1137
+ #### GeoJSONReader functions ####
1138
+ GEOSGeoJSONReader_create_r: [
1139
+ # *geojson_reader, *handle
1140
+ :pointer, :pointer
1141
+ ],
1142
+
1143
+ GEOSGeoJSONReader_readGeometry_r: [
1144
+ # *geom, *handle, *geojson_reader, string
1145
+ :pointer, :pointer, :pointer, :string
1146
+ ],
1147
+
1148
+ GEOSGeoJSONReader_destroy_r: [
1149
+ # void, *handle, *geojson_reader
1150
+ :void, :pointer, :pointer
1151
+ ],
1152
+ #### /GeoJSONReader functions ###
1153
+
1154
+ #### GeoJSONWriter functions ####
1155
+ GEOSGeoJSONWriter_create_r: [
1156
+ # *geojson_writer, *handle
1157
+ :pointer, :pointer
1158
+ ],
1159
+
1160
+ GEOSGeoJSONWriter_destroy_r: [
1161
+ # void, *handle, *geojson_writer
1162
+ :void, :pointer, :pointer
1163
+ ],
1164
+
1165
+ GEOSGeoJSONWriter_writeGeometry_r: [
1166
+ # string, *handle, *geojson_writer, :geom, :indent
1167
+ :string, :pointer, :pointer, :pointer, :int
1168
+ ],
1169
+ #### /GeoJSONWriter functions ####
1170
+
1087
1171
  #### Linearref functions ####
1088
1172
  GEOSProject_r: [
1089
1173
  # distance, *handle, *geom_a, *geom_b
@@ -1363,12 +1447,14 @@ module Geos
1363
1447
  GEOS_CAPI_VERSION,
1364
1448
  GEOS_CAPI_VERSION_MAJOR, GEOS_CAPI_VERSION_MINOR, GEOS_CAPI_VERSION_PATCH,
1365
1449
  GEOS_SVN_REVISION =
1366
- if !(versions = Geos.version.scan(/^
1450
+ if (versions = Geos.version.scan(/^
1367
1451
  ((\d+)\.(\d+)\.(\d+)((?:dev|rc|beta|alpha)\d*)?)
1368
1452
  -CAPI-
1369
1453
  ((\d+)\.(\d+)\.(\d+))
1370
1454
  (?:\s+r?(\h+))?
1371
1455
  $/x)).empty?
1456
+ ['0.0.0', 0, 0, 0, nil, '0.0.0', 0, 0, 0]
1457
+ else
1372
1458
  versions = versions[0]
1373
1459
  [
1374
1460
  versions[0],
@@ -1382,11 +1468,13 @@ module Geos
1382
1468
  versions[8].to_i,
1383
1469
  versions[9]&.to_i
1384
1470
  ]
1385
- else
1386
- ['0.0.0', 0, 0, 0, nil, '0.0.0', 0, 0, 0]
1387
1471
  end
1388
1472
  GEOS_CAPI_FIRST_INTERFACE = GEOS_CAPI_VERSION_MAJOR.to_i
1389
1473
  GEOS_CAPI_LAST_INTERFACE = GEOS_CAPI_VERSION_MAJOR.to_i + GEOS_CAPI_VERSION_MINOR.to_i
1474
+
1475
+ GEOS_NICE_VERSION = [GEOS_VERSION_MAJOR, GEOS_VERSION_MINOR, GEOS_VERSION_PATCH].collect { |version|
1476
+ version.to_s.rjust(2, '0')
1477
+ }.join
1390
1478
  end
1391
1479
 
1392
1480
  module Constants
@@ -2,15 +2,15 @@ sonar.projectKey=dark-panda_ffi-geos
2
2
  sonar.organization=dark-panda
3
3
 
4
4
  # This is the name and version displayed in the SonarCloud UI.
5
- #sonar.projectName=ffi-geos
6
- #sonar.projectVersion=1.0
5
+ sonar.projectName=ffi-geos
6
+ sonar.projectVersion=1.0
7
7
 
8
8
  # Path is relative to the sonar-project.properties file. Replace "\" by "/" on Windows.
9
9
  sonar.sources=lib, test
10
10
 
11
11
  # Encoding of the source code. Default is default system encoding
12
- #sonar.sourceEncoding=UTF-8
12
+ sonar.sourceEncoding=UTF-8
13
13
 
14
14
  # Additional reports
15
15
  sonar.ruby.rubocop.reportPaths=rubocop-report.json
16
- sonar.ruby.coverage.reportPaths=coverage/.resultset.json
16
+ sonar.ruby.coverage.reportPaths=coverage/coverage.json
@@ -515,16 +515,16 @@ class CoordinateSequenceTests < Minitest::Test
515
515
  end
516
516
 
517
517
  undef :affine_tester
518
- def affine_tester(method, expected, coords, *args)
518
+ def affine_tester(method, expected, coords, *args, **options)
519
519
  cs = Geos::CoordinateSequence.new(coords)
520
- cs.send("#{method}!", *args)
520
+ cs.__safe_send__("#{method}!", *args, **options)
521
521
 
522
522
  expected.length.times do |i|
523
523
  assert_in_delta(expected[i], cs.get_ordinate(0, i), TOLERANCE)
524
524
  end
525
525
 
526
526
  cs = Geos::CoordinateSequence.new(coords)
527
- cs_2 = cs.send(method, *args)
527
+ cs_2 = cs.__safe_send__(method, *args, **options)
528
528
 
529
529
  expected.length.times do |i|
530
530
  assert_in_delta(coords[i], cs.get_ordinate(0, i), TOLERANCE)
@@ -542,21 +542,21 @@ class CoordinateSequenceTests < Minitest::Test
542
542
  def test_rotate_x
543
543
  affine_tester(:rotate_x, [1, -1, -1], [1, 1, 1], Math::PI)
544
544
  affine_tester(:rotate_x, [1, -1, 1], [1, 1, 1], Math::PI / 2)
545
- affine_tester(:rotate_x, [1, 1, -1], [1, 1, 1], Math::PI + Math::PI / 2)
545
+ affine_tester(:rotate_x, [1, 1, -1], [1, 1, 1], Math::PI + (Math::PI / 2))
546
546
  affine_tester(:rotate_x, [1, 1, 1], [1, 1, 1], Math::PI * 2)
547
547
  end
548
548
 
549
549
  def test_rotate_y
550
550
  affine_tester(:rotate_y, [-1, 1, -1], [1, 1, 1], Math::PI)
551
551
  affine_tester(:rotate_y, [1, 1, -1], [1, 1, 1], Math::PI / 2)
552
- affine_tester(:rotate_y, [-1, 1, 1], [1, 1, 1], Math::PI + Math::PI / 2)
552
+ affine_tester(:rotate_y, [-1, 1, 1], [1, 1, 1], Math::PI + (Math::PI / 2))
553
553
  affine_tester(:rotate_y, [1, 1, 1], [1, 1, 1], Math::PI * 2)
554
554
  end
555
555
 
556
556
  def test_rotate_z
557
557
  affine_tester(:rotate_z, [-1, -1], [1, 1], Math::PI)
558
558
  affine_tester(:rotate_z, [-1, 1], [1, 1], Math::PI / 2)
559
- affine_tester(:rotate_z, [1, -1], [1, 1], Math::PI + Math::PI / 2)
559
+ affine_tester(:rotate_z, [1, -1], [1, 1], Math::PI + (Math::PI / 2))
560
560
  affine_tester(:rotate_z, [1, 1], [1, 1], Math::PI * 2)
561
561
  end
562
562
 
@@ -0,0 +1,170 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'test_helper'
4
+
5
+ class GeoJSONReaderTests < Minitest::Test
6
+ include TestHelper
7
+
8
+ attr_reader :json_reader
9
+
10
+ def setup
11
+ super
12
+
13
+ skip unless ENV['FORCE_TESTS'] || Geos::FFIGeos.respond_to?(:GEOSGeoJSONReader_create_r)
14
+
15
+ @json_reader = Geos::GeoJSONReader.new
16
+
17
+ @writer.rounding_precision = 3
18
+ end
19
+
20
+ def json_read(*args, **options)
21
+ json_reader.read(*args, **options)
22
+ end
23
+
24
+ def geojson_tester(expected, json, **options)
25
+ assert_equal(expected, write(json_read(json, **options)))
26
+ end
27
+
28
+ def test_point
29
+ geojson_tester(
30
+ 'POINT (-117.000 33.000)',
31
+ '{"type":"Point","coordinates":[-117.0,33.0]}'
32
+ )
33
+ end
34
+
35
+ def test_line_string
36
+ geojson_tester(
37
+ 'LINESTRING (102.000 0.000, 103.000 1.000, 104.000 0.000, 105.000 1.000)',
38
+ '{"type":"LineString","coordinates":[[102.0,0.0],[103.0,1.0],[104.0,0.0],[105.0,1.0]]}'
39
+ )
40
+ end
41
+
42
+ def test_polygon
43
+ geojson_tester(
44
+ 'POLYGON ((30.000 10.000, 40.000 40.000, 20.000 40.000, 10.000 20.000, 30.000 10.000))',
45
+ '{"type":"Polygon","coordinates":[[[30,10],[40,40],[20,40],[10,20],[30,10]]]}'
46
+ )
47
+ end
48
+
49
+ def test_polygon_with_inner_ring
50
+ geojson_tester(
51
+ 'POLYGON ((35.000 10.000, 45.000 45.000, 15.000 40.000, 10.000 20.000, 35.000 10.000), (20.000 30.000, 35.000 35.000, 30.000 20.000, 20.000 30.000))',
52
+ '{"type":"Polygon","coordinates":[[[35,10],[45,45],[15,40],[10,20],[35,10]],[[20,30],[35,35],[30,20],[20,30]]]}'
53
+ )
54
+ end
55
+
56
+ def test_multi_point
57
+ geojson_tester(
58
+ 'MULTIPOINT (10.000 40.000, 40.000 30.000, 20.000 20.000, 30.000 10.000)',
59
+ '{"type":"MultiPoint","coordinates":[[10, 40], [40, 30], [20, 20], [30, 10]]}'
60
+ )
61
+ end
62
+
63
+ def test_multi_line_string
64
+ geojson_tester(
65
+ 'MULTILINESTRING ((10.000 10.000, 20.000 20.000, 10.000 40.000), (40.000 40.000, 30.000 30.000, 40.000 20.000, 30.000 10.000))',
66
+ '{"type":"MultiLineString","coordinates":[[[10, 10], [20, 20], [10, 40]],[[40, 40], [30, 30], [40, 20], [30, 10]]]}'
67
+ )
68
+ end
69
+
70
+ def test_multi_polygon
71
+ geojson_tester(
72
+ 'MULTIPOLYGON (((40.000 40.000, 20.000 45.000, 45.000 30.000, 40.000 40.000)), ((20.000 35.000, 10.000 30.000, 10.000 10.000, 30.000 5.000, 45.000 20.000, 20.000 35.000), (30.000 20.000, 20.000 15.000, 20.000 25.000, 30.000 20.000)))',
73
+ '{"type": "MultiPolygon", "coordinates": [[[[40, 40], [20, 45], [45, 30], [40, 40]]], [[[20, 35], [10, 30], [10, 10], [30, 5], [45, 20], [20, 35]], [[30, 20], [20, 15], [20, 25], [30, 20]]]]}'
74
+ )
75
+ end
76
+
77
+ def test_geometry_collection
78
+ geojson_tester(
79
+ 'GEOMETRYCOLLECTION (POINT (40.000 10.000), LINESTRING (10.000 10.000, 20.000 20.000, 10.000 40.000), POLYGON ((40.000 40.000, 20.000 45.000, 45.000 30.000, 40.000 40.000)))',
80
+ '{"type": "GeometryCollection","geometries": [{"type": "Point","coordinates": [40, 10]},{"type": "LineString","coordinates": [[10, 10], [20, 20], [10, 40]]},{"type": "Polygon","coordinates": [[[40, 40], [20, 45], [45, 30], [40, 40]]]}]}'
81
+ )
82
+ end
83
+
84
+ def test_feature_collection
85
+ geojson_tester(
86
+ 'GEOMETRYCOLLECTION (POINT (-117.000 33.000), POINT (-122.000 45.000))',
87
+ '{"type":"FeatureCollection","features":[{"type":"Feature","geometry":{"type":"Point","coordinates":[-117.0,33.0]}},{"type":"Feature","geometry":{"type":"Point","coordinates":[-122.0,45.0]}}]}'
88
+ )
89
+ end
90
+
91
+ def test_empty_point
92
+ geojson_tester(
93
+ 'POINT EMPTY',
94
+ '{"type":"Point","coordinates":[]}'
95
+ )
96
+ end
97
+
98
+ def test_empty_line_string
99
+ geojson_tester(
100
+ 'LINESTRING EMPTY',
101
+ '{"type":"LineString","coordinates":[]}'
102
+ )
103
+ end
104
+
105
+ def test_empty_polygon
106
+ geojson_tester(
107
+ 'POLYGON EMPTY',
108
+ '{"type":"Polygon","coordinates":[]}'
109
+ )
110
+ end
111
+
112
+ def test_empty_multi_point
113
+ geojson_tester(
114
+ 'MULTIPOINT EMPTY',
115
+ '{"type":"MultiPoint","coordinates":[]}'
116
+ )
117
+ end
118
+
119
+ def test_empty_multi_line_string
120
+ geojson_tester(
121
+ 'MULTILINESTRING EMPTY',
122
+ '{"type":"MultiLineString","coordinates":[]}'
123
+ )
124
+ end
125
+
126
+ def test_empty_multi_polygon
127
+ geojson_tester(
128
+ 'MULTIPOLYGON EMPTY',
129
+ '{"type": "MultiPolygon", "coordinates": []}'
130
+ )
131
+ end
132
+
133
+ def test_empty_geometry_collection
134
+ geojson_tester(
135
+ 'GEOMETRYCOLLECTION EMPTY',
136
+ '{"type": "GeometryCollection","geometries": []}'
137
+ )
138
+ end
139
+
140
+ def test_incomplete_geojson
141
+ assert_raises(Geos::GeoJSONReader::ParseError) do
142
+ json_reader.read('{"type":"Point","coordinates":[-117.0]}')
143
+ end
144
+
145
+ assert_raises(Geos::GeoJSONReader::ParseError) do
146
+ json_reader.read('{"type":"LineString","coordinates":[[1,2],[2]]}')
147
+ end
148
+ end
149
+
150
+ def test_broken_geojson
151
+ assert_raises(Geos::GeoJSONReader::ParseError) do
152
+ json_reader.read('<gml>NOT_GEO_JSON</gml>')
153
+ end
154
+ end
155
+
156
+ def test_incompatible_type
157
+ assert_raises(Geos::GeoJSONReader::ParseError) do
158
+ json_reader.read('{"type":"Line","coordinates":[[1,2],[2,3]]}')
159
+ end
160
+ end
161
+
162
+ def test_srid_from_options
163
+ geom = json_reader.read(
164
+ '{"type":"Point","coordinates":[-117.0,33.0]}',
165
+ srid: 3857
166
+ )
167
+
168
+ assert_equal(geom.srid, 3857)
169
+ end
170
+ end
@@ -0,0 +1,103 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'test_helper'
4
+
5
+ class GeoJSONWriterTests < Minitest::Test
6
+ include TestHelper
7
+
8
+ attr_reader :json_writer
9
+
10
+ def setup
11
+ super
12
+
13
+ skip unless ENV['FORCE_TESTS'] || Geos::FFIGeos.respond_to?(:GEOSGeoJSONWriter_create_r)
14
+
15
+ @json_writer = Geos::GeoJSONWriter.new
16
+ end
17
+
18
+ def json_write(*args, **options)
19
+ json_writer.write(*args, **options)
20
+ end
21
+
22
+ def geojson_tester(expected, geom, **options)
23
+ assert_equal(expected, json_write(read(geom), **options))
24
+ end
25
+
26
+ def test_point
27
+ geojson_tester('{"type":"Point","coordinates":[-117.0,33.0]}', 'POINT(-117 33)')
28
+ end
29
+
30
+ def test_line_string
31
+ geojson_tester('{"type":"LineString","coordinates":[[102.0,0.0],[103.0,1.0],[104.0,0.0],[105.0,1.0]]}', 'LINESTRING(102.0 0.0, 103.0 1.0, 104.0 0.0, 105.0 1.0)')
32
+ end
33
+
34
+ def test_polygon
35
+ geojson_tester('{"type":"Polygon","coordinates":[[[30.0,10.0],[40.0,40.0],[20.0,40.0],[10.0,20.0],[30.0,10.0]]]}', 'POLYGON((30 10, 40 40, 20 40, 10 20, 30 10))')
36
+ end
37
+
38
+ def test_polygon_with_inner_ring
39
+ geojson_tester('{"type":"Polygon","coordinates":[[[35.0,10.0],[45.0,45.0],[15.0,40.0],[10.0,20.0],[35.0,10.0]],[[20.0,30.0],[35.0,35.0],[30.0,20.0],[20.0,30.0]]]}', 'POLYGON((35 10, 45 45, 15 40, 10 20, 35 10), (20 30, 35 35, 30 20, 20 30))')
40
+ end
41
+
42
+ def test_multi_point
43
+ geojson_tester('{"type":"MultiPoint","coordinates":[[10.0,40.0],[40.0,30.0],[20.0,20.0],[30.0,10.0]]}', 'MULTIPOINT ((10 40), (40 30), (20 20), (30 10))')
44
+ end
45
+
46
+ def test_multi_line_string
47
+ geojson_tester('{"type":"MultiLineString","coordinates":[[[10.0,10.0],[20.0,20.0],[10.0,40.0]],[[40.0,40.0],[30.0,30.0],[40.0,20.0],[30.0,10.0]]]}', 'MULTILINESTRING ((10 10, 20 20, 10 40),(40 40, 30 30, 40 20, 30 10))')
48
+ end
49
+
50
+ def test_multi_polygon
51
+ geojson_tester('{"type":"MultiPolygon","coordinates":[[[[30.0,20.0],[45.0,40.0],[10.0,40.0],[30.0,20.0]]],[[[15.0,5.0],[40.0,10.0],[10.0,20.0],[5.0,10.0],[15.0,5.0]]]]}', 'MULTIPOLYGON (((30 20, 45 40, 10 40, 30 20)),((15 5, 40 10, 10 20, 5 10, 15 5)))')
52
+ end
53
+
54
+ def test_geometry_collection
55
+ geojson_tester('{"type":"GeometryCollection","geometries":[{"type":"Point","coordinates":[1.0,1.0]},{"type":"Point","coordinates":[2.0,2.0]}]}', 'GEOMETRYCOLLECTION(POINT(1 1),POINT(2 2))')
56
+ end
57
+
58
+ def test_write_with_indentation
59
+ geojson_tester(<<~JSON.strip, 'LINESTRING(102.0 0.0, 103.0 1.0, 104.0 0.0, 105.0 1.0)', indentation: 2)
60
+ {
61
+ "type": "LineString",
62
+ "coordinates": [
63
+ [
64
+ 102.0,
65
+ 0.0
66
+ ],
67
+ [
68
+ 103.0,
69
+ 1.0
70
+ ],
71
+ [
72
+ 104.0,
73
+ 0.0
74
+ ],
75
+ [
76
+ 105.0,
77
+ 1.0
78
+ ]
79
+ ]
80
+ }
81
+ JSON
82
+ end
83
+
84
+ def test_empty_point
85
+ geojson_tester('{"type":"Point","coordinates":[]}', 'POINT EMPTY')
86
+ end
87
+
88
+ def test_empty_line_string
89
+ geojson_tester('{"type":"LineString","coordinates":[]}', 'LINESTRING EMPTY')
90
+ end
91
+
92
+ def test_empty_polygon
93
+ geojson_tester('{"type":"Polygon","coordinates":[[]]}', 'POLYGON EMPTY')
94
+ end
95
+
96
+ def test_empty_geometry_collection
97
+ geojson_tester('{"type":"GeometryCollection","geometries":[]}', 'GEOMETRYCOLLECTION EMPTY')
98
+ end
99
+
100
+ def test_linear_ring
101
+ geojson_tester('{"type":"LineString","coordinates":[[0.0,0.0],[1.0,1.0],[1.0,0.0],[0.0,0.0]]}', 'LINEARRING (0 0, 1 1, 1 0, 0 0)')
102
+ end
103
+ end
@@ -174,7 +174,7 @@ class GeometryCollectionTests < Minitest::Test
174
174
 
175
175
  def test_snap_to_grid
176
176
  wkt = 'GEOMETRYCOLLECTION (LINESTRING (-10.12 0, -10.12 5, -10.12 5, -10.12 6, -10.12 6, -10.12 6, -10.12 7, -10.12 7, -10.12 7, -10.12 8, -10.12 8, -9 8, -9 9, -10.12 0), ' \
177
- 'POLYGON ((-10.12 0, -10.12 5, -10.12 5, -10.12 6, -10.12 6, -10.12 6, -10.12 7, -10.12 7, -10.12 7, -10.12 8, -10.12 8, -9 8, -9 9, -10.12 0)), POINT (10.12 10.12))'
177
+ 'POLYGON ((-10.12 0, -10.12 5, -10.12 5, -10.12 6, -10.12 6, -10.12 6, -10.12 7, -10.12 7, -10.12 7, -10.12 8, -10.12 8, -9 8, -9 9, -10.12 0)), POINT (10.12 10.12))'
178
178
 
179
179
  expected = 'GEOMETRYCOLLECTION (LINESTRING (-10 0, -10 5, -10 5, -10 6, -10 6, -10 6, -10 7, -10 7, -10 7, -10 8, -10 8, -9 8, -9 9, -10 0), POLYGON ((-10 0, -10 5, -10 5, -10 6, -10 6, -10 6, -10 7, -10 7, -10 7, -10 8, -10 8, -9 8, -9 9, -10 0)), POINT (10 10))'
180
180
 
@@ -255,7 +255,7 @@ class GeometryCollectionTests < Minitest::Test
255
255
  affine_tester(:rotate_x,
256
256
  'GEOMETRYCOLLECTION Z (POINT Z (1 1 -1), LINESTRING Z (1 1 -1, 10 10 -10), POLYGON Z ((0 0 0, 5 0 0, 5 0 -5, 0 0 -5, 0 0 0)))',
257
257
  wkt,
258
- Math::PI + Math::PI / 2)
258
+ Math::PI + (Math::PI / 2))
259
259
 
260
260
  affine_tester(:rotate_x,
261
261
  wkt,
@@ -282,7 +282,7 @@ class GeometryCollectionTests < Minitest::Test
282
282
  affine_tester(:rotate_y,
283
283
  'GEOMETRYCOLLECTION Z (POINT Z (-1 1 1), LINESTRING Z (-1 1 1, -10 10 10), POLYGON Z ((0 0 0, 0 0 5, 0 5 5, 0 5 0, 0 0 0)))',
284
284
  wkt,
285
- Math::PI + Math::PI / 2)
285
+ Math::PI + (Math::PI / 2))
286
286
 
287
287
  affine_tester(:rotate_y,
288
288
  wkt,
@@ -308,7 +308,7 @@ class GeometryCollectionTests < Minitest::Test
308
308
  affine_tester(:rotate_z,
309
309
  'GEOMETRYCOLLECTION (POINT (1 -1), LINESTRING (0 0, 10 -10), POLYGON ((0 0, 0 -5, 5 -5, 5 0, 0 0)))',
310
310
  wkt,
311
- Math::PI + Math::PI / 2)
311
+ Math::PI + (Math::PI / 2))
312
312
 
313
313
  affine_tester(:rotate_z,
314
314
  wkt,