ffi-geos 2.2.0 → 2.4.0

Sign up to get free protection for your applications and to get access to all the features.
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,