proj4rb 3.0.0 → 4.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (82) hide show
  1. checksums.yaml +4 -4
  2. data/ChangeLog +26 -15
  3. data/README.rdoc +82 -44
  4. data/Rakefile +27 -27
  5. data/lib/api/api.rb +96 -118
  6. data/lib/api/api_5_0.rb +331 -300
  7. data/lib/api/api_5_1.rb +6 -6
  8. data/lib/api/api_5_2.rb +4 -4
  9. data/lib/api/api_6_0.rb +116 -14
  10. data/lib/api/api_6_1.rb +4 -4
  11. data/lib/api/api_6_2.rb +9 -6
  12. data/lib/api/api_6_3.rb +6 -0
  13. data/lib/api/api_7_0.rb +68 -0
  14. data/lib/api/api_7_1.rb +73 -0
  15. data/lib/api/api_7_2.rb +14 -0
  16. data/lib/api/api_8_0.rb +6 -0
  17. data/lib/api/api_8_1.rb +24 -0
  18. data/lib/api/api_8_2.rb +6 -0
  19. data/lib/api/api_9_1.rb +7 -0
  20. data/lib/api/api_9_2.rb +9 -0
  21. data/lib/api/api_experimental.rb +196 -0
  22. data/lib/proj/area.rb +73 -32
  23. data/lib/proj/axis_info.rb +44 -0
  24. data/lib/proj/bounds.rb +13 -0
  25. data/lib/proj/context.rb +174 -28
  26. data/lib/proj/conversion.rb +92 -0
  27. data/lib/proj/coordinate.rb +281 -197
  28. data/lib/proj/coordinate_operation_mixin.rb +381 -0
  29. data/lib/proj/coordinate_system.rb +137 -0
  30. data/lib/proj/crs.rb +672 -204
  31. data/lib/proj/crs_info.rb +47 -0
  32. data/lib/proj/database.rb +305 -0
  33. data/lib/proj/datum.rb +32 -0
  34. data/lib/proj/datum_ensemble.rb +34 -0
  35. data/lib/proj/ellipsoid.rb +77 -41
  36. data/lib/proj/error.rb +62 -9
  37. data/lib/proj/file_api.rb +166 -0
  38. data/lib/proj/grid.rb +121 -0
  39. data/lib/proj/grid_cache.rb +64 -0
  40. data/lib/proj/grid_info.rb +19 -0
  41. data/lib/proj/network_api.rb +92 -0
  42. data/lib/proj/operation.rb +42 -42
  43. data/lib/proj/operation_factory_context.rb +136 -0
  44. data/lib/proj/parameter.rb +38 -0
  45. data/lib/proj/parameters.rb +106 -0
  46. data/lib/proj/pj_object.rb +670 -80
  47. data/lib/proj/pj_objects.rb +44 -0
  48. data/lib/proj/prime_meridian.rb +65 -39
  49. data/lib/proj/projection.rb +698 -207
  50. data/lib/proj/session.rb +46 -0
  51. data/lib/proj/strings.rb +32 -0
  52. data/lib/proj/transformation.rb +101 -60
  53. data/lib/proj/unit.rb +108 -53
  54. data/lib/proj.rb +110 -9
  55. data/proj4rb.gemspec +5 -5
  56. data/test/abstract_test.rb +23 -1
  57. data/test/context_test.rb +172 -82
  58. data/test/conversion_test.rb +368 -0
  59. data/test/coordinate_system_test.rb +144 -0
  60. data/test/crs_test.rb +770 -71
  61. data/test/database_test.rb +360 -0
  62. data/test/datum_ensemble_test.rb +65 -0
  63. data/test/datum_test.rb +55 -0
  64. data/test/ellipsoid_test.rb +64 -18
  65. data/test/file_api_test.rb +66 -0
  66. data/test/grid_cache_test.rb +72 -0
  67. data/test/grid_test.rb +141 -0
  68. data/test/network_api_test.rb +45 -0
  69. data/test/operation_factory_context_test.rb +201 -0
  70. data/test/parameters_test.rb +40 -0
  71. data/test/pj_object_test.rb +179 -0
  72. data/test/prime_meridian_test.rb +76 -0
  73. data/test/proj_test.rb +46 -4
  74. data/test/projection_test.rb +646 -222
  75. data/test/session_test.rb +78 -0
  76. data/test/transformation_test.rb +149 -7
  77. data/test/unit_test.rb +57 -28
  78. metadata +51 -13
  79. data/lib/api/api_4_9.rb +0 -31
  80. data/lib/proj/config.rb +0 -70
  81. data/lib/proj/point.rb +0 -72
  82. data/test/prime_meridians_test.rb +0 -33
data/test/context_test.rb CHANGED
@@ -1,82 +1,172 @@
1
- # encoding: UTF-8
2
-
3
- require_relative './abstract_test'
4
-
5
- class ContextTest < AbstractTest
6
- def test_create
7
- context = Proj::Context.new
8
- assert(context.to_ptr)
9
- end
10
-
11
- def test_finalize
12
- 500.times do
13
- context = Proj::Context.new
14
- assert(context.to_ptr)
15
- GC.start
16
- end
17
- assert(true)
18
- end
19
-
20
- def test_one_per_thread
21
- context_1 = Proj::Context.current
22
- context_2 = Proj::Context.current
23
- assert_same(context_1, context_2)
24
- end
25
-
26
- def test_database_path
27
- refute_nil(Proj::Context.current.database_path)
28
- end
29
-
30
- def test_log_level
31
- assert_equal(:PJ_LOG_NONE, Proj::Context.current.log_level)
32
- end
33
-
34
- def test_set_log_level
35
- context = Proj::Context.new
36
- context.log_level = :PJ_LOG_ERROR
37
- assert_equal(:PJ_LOG_ERROR, context.log_level)
38
- end
39
-
40
- def test_invalid_database_path
41
- path = '/wrong'
42
- error = assert_raises(Proj::Error) do
43
- Proj::Context.current.database_path = path
44
- end
45
- # TODO - if you run this test on its own you get a useful error message, if you run all tests
46
- # at once you get a useless error message. Not sure what is causing the difference
47
- assert_match(/No such file or directory|generic error of unknown origin/, error.to_s)
48
- end
49
-
50
- def test_set_log_function
51
- context = Proj::Context.new
52
- called = false
53
-
54
- data = FFI::MemoryPointer.new(:int)
55
- data.write_int(5)
56
-
57
- context.set_log_function(data) do |pointer, int, message|
58
- called = true
59
- refute(pointer.null?)
60
- assert_equal(5, pointer.read_int)
61
- assert_equal(1, int)
62
- assert_equal('proj_context_set_database_path: Open of /wrong failed', message)
63
- end
64
-
65
- begin
66
- context.database_path = '/wrong'
67
- rescue
68
- end
69
-
70
- assert(called)
71
- end
72
-
73
- def test_use_proj4_init_rules
74
- refute(Proj::Context.current.use_proj4_init_rules)
75
-
76
- Proj::Context.current.use_proj4_init_rules = true
77
- assert(Proj::Context.current.use_proj4_init_rules)
78
-
79
- Proj::Context.current.use_proj4_init_rules = false
80
- refute(Proj::Context.current.use_proj4_init_rules)
81
- end
82
- end
1
+ # encoding: UTF-8
2
+
3
+ require_relative './abstract_test'
4
+
5
+ class ContextTest < AbstractTest
6
+ def test_create
7
+ context = Proj::Context.new
8
+ assert(context.to_ptr)
9
+ end
10
+
11
+ def test_finalize
12
+ 100.times do
13
+ context = Proj::Context.new
14
+ assert(context.to_ptr)
15
+ GC.start
16
+ end
17
+ assert(true)
18
+ end
19
+
20
+ def test_clone
21
+ context = Proj::Context.new
22
+ refute(context.use_proj4_init_rules)
23
+ context.use_proj4_init_rules = true
24
+ assert(context.use_proj4_init_rules)
25
+
26
+ clone = context.clone
27
+ assert(clone.use_proj4_init_rules)
28
+ end
29
+
30
+ def test_dup
31
+ context = Proj::Context.new
32
+ refute(context.use_proj4_init_rules)
33
+ context.use_proj4_init_rules = true
34
+ assert(context.use_proj4_init_rules)
35
+
36
+ clone = context.clone
37
+ assert(clone.use_proj4_init_rules)
38
+ end
39
+
40
+ def test_one_per_thread
41
+ context_1 = Proj::Context.current
42
+ context_2 = Proj::Context.current
43
+ assert_same(context_1, context_2)
44
+ end
45
+
46
+ def test_search_paths
47
+ context = Proj::Context.new
48
+ path = File.join(Dir.tmpdir, "temp_proj_dic2")
49
+
50
+ begin
51
+ File.open(path, 'wb') do |file|
52
+ file << "<MY_PIPELINE> +proj=pipeline +step +proj=utm +zone=31 +ellps=GRS80"
53
+ end
54
+
55
+ # Try to use the pipeline, an error will occur since it is not on the path
56
+ error = assert_raises(Proj::Error) do
57
+ Proj::Conversion.new("+init=temp_proj_dic2:MY_PIPELINE")
58
+ end
59
+ assert_equal("Invalid value for an argument", error.to_s)
60
+
61
+ # Set the path and try again
62
+ context.search_paths = [File.dirname(path)]
63
+ conversion = Proj::Conversion.new("+init=temp_proj_dic2:MY_PIPELINE", context)
64
+ ensure
65
+ File.delete(path)
66
+ end
67
+ end
68
+
69
+ def test_database_path
70
+ refute_nil(Proj::Context.current.database_path)
71
+ end
72
+
73
+ def test_log_level
74
+ assert_equal(:PJ_LOG_ERROR, Proj::Context.current.log_level)
75
+ end
76
+
77
+ def test_set_log_level
78
+ context = Proj::Context.new
79
+ context.log_level = :PJ_LOG_ERROR
80
+ assert_equal(:PJ_LOG_ERROR, context.log_level)
81
+ end
82
+
83
+ def test_invalid_database_path
84
+ context = Proj::Context.new
85
+ path = '/wrong'
86
+ error = assert_raises(Proj::Error) do
87
+ context.database.path = path
88
+ end
89
+ # TODO - if you run this test on its own you get a useful error message, if you run all tests
90
+ # at once you get a useless error message. Not sure what is causing the difference
91
+ #assert_match(/No such file or directory|generic error of unknown origin|File not found or invalid/, error.to_s)
92
+ assert_equal("Unknown error (code 4096)", error.to_s)
93
+ end
94
+
95
+ def test_set_log_function
96
+ context = Proj::Context.new
97
+ called = false
98
+
99
+ data = FFI::MemoryPointer.new(:int)
100
+ data.write_int(5)
101
+
102
+ context.set_log_function(data) do |pointer, int, message|
103
+ called = true
104
+ refute(pointer.null?)
105
+ assert_equal(5, pointer.read_int)
106
+ assert_equal(1, int)
107
+ assert_equal('proj_context_set_database_path: Open of /wrong failed', message)
108
+ end
109
+
110
+ begin
111
+ context.database.path = '/wrong'
112
+ rescue
113
+ end
114
+
115
+ assert(called)
116
+ end
117
+
118
+ def test_use_proj4_init_rules
119
+ context = Proj::Context.new
120
+ refute(context.use_proj4_init_rules)
121
+
122
+ context.use_proj4_init_rules = true
123
+ assert(context.use_proj4_init_rules)
124
+
125
+ context.use_proj4_init_rules = false
126
+ refute(context.use_proj4_init_rules)
127
+ end
128
+
129
+ def test_network_enabled
130
+ context = Proj::Context.new
131
+ refute(context.network_enabled?)
132
+ end
133
+
134
+ def test_network_enabled_set
135
+ context = Proj::Context.new
136
+ refute(context.network_enabled?)
137
+
138
+ context.network_enabled = true
139
+ assert(context.network_enabled?)
140
+
141
+ context.network_enabled = false
142
+ refute(context.network_enabled?)
143
+ end
144
+
145
+ def test_url
146
+ context = Proj::Context.new
147
+ assert_equal("https://cdn.proj.org", context.url)
148
+ end
149
+
150
+ def test_url_set
151
+ context = Proj::Context.new
152
+ assert_equal("https://cdn.proj.org", context.url)
153
+
154
+ context.url = "https://cdn.proj.org/changed"
155
+ assert_equal("https://cdn.proj.org/changed", context.url)
156
+
157
+ context.url = "https://cdn.proj.org"
158
+ assert_equal("https://cdn.proj.org", context.url)
159
+ end
160
+
161
+ def test_user_directory
162
+ context = Proj::Context.new
163
+ assert_match(/proj$/, context.user_directory)
164
+ end
165
+
166
+ def test_wkt_dialect
167
+ context = Proj::Context.new
168
+
169
+ wkt = 'LOCAL_CS["foo"]'
170
+ assert_equal(:PJ_GUESSED_WKT2_2015, context.wkt_dialect(wkt))
171
+ end
172
+ end
@@ -0,0 +1,368 @@
1
+ # encoding: UTF-8
2
+
3
+ require_relative './abstract_test'
4
+
5
+ class ConversionTest < AbstractTest
6
+ def test_create_conversion
7
+ context = Proj::Context.new
8
+ param = Proj::Parameter.new(name: "param name", value: 0.99,
9
+ unit_conv_factor: 1.0, unit_type: :PJ_UT_SCALE)
10
+
11
+ conversion = Proj::Conversion.create_conversion(context, name: "conv",
12
+ auth_name: "conv auth", code: "conv code",
13
+ method_name: "method", method_auth_name: "method auth", method_code: "method code",
14
+ params: [param])
15
+ assert(conversion)
16
+ assert_equal("conv", conversion.name)
17
+ assert_equal("conv auth:conv code", conversion.auth)
18
+ assert_equal(:PJ_TYPE_CONVERSION, conversion.proj_type)
19
+ end
20
+
21
+ def test_inverse_operation
22
+ operation = Proj::Conversion.new(<<~EOS)
23
+ +proj=pipeline +step +proj=axisswap +order=2,1 +step
24
+ +proj=unitconvert +xy_in=deg +xy_out=rad +step +proj=push
25
+ +v_3 +step +proj=cart +ellps=evrst30 +step +proj=helmert
26
+ +x=293 +y=836 +z=318 +rx=0.5 +ry=1.6 +rz=-2.8 +s=2.1
27
+ +convention=position_vector +step +inv +proj=cart
28
+ +ellps=WGS84 +step +proj=pop +v_3 +step +proj=unitconvert
29
+ +xy_in=rad +xy_out=deg +step +proj=axisswap +order=2,1
30
+ EOS
31
+
32
+ inverse = operation.create_inverse
33
+ proj_string = inverse.to_proj_string(:PJ_PROJ_5, multiline: true, indentation_width: 4, max_line_length: 40)
34
+
35
+ expected = if proj7?
36
+ <<~EOS
37
+ +proj=pipeline
38
+ +step +proj=axisswap +order=2,1
39
+ +step +proj=unitconvert +xy_in=deg
40
+ +xy_out=rad
41
+ +step +proj=push +v_3
42
+ +step +proj=cart +ellps=WGS84
43
+ +step +inv +proj=helmert +x=293
44
+ +y=836 +z=318 +rx=0.5 +ry=1.6
45
+ +rz=-2.8 +s=2.1
46
+ +convention=position_vector
47
+ +step +inv +proj=cart +ellps=evrst30
48
+ +step +proj=pop +v_3
49
+ +step +proj=unitconvert +xy_in=rad
50
+ +xy_out=deg
51
+ +step +proj=axisswap +order=2,1
52
+ EOS
53
+ else
54
+ "+proj=pipeline +step +proj=axisswap +order=2,1 +step +proj=unitconvert +xy_in=deg +xy_out=rad +step +proj=push +v_3 +step +proj=cart +ellps=WGS84 +step +inv +proj=helmert +x=293 +y=836 +z=318 +rx=0.5 +ry=1.6 +rz=-2.8 +s=2.1 +convention=position_vector +step +inv +proj=cart +ellps=evrst30 +step +proj=pop +v_3 +step +proj=unitconvert +xy_in=rad +xy_out=deg +step +proj=axisswap +order=2,1"
55
+ end
56
+
57
+ assert_equal(expected.strip, proj_string)
58
+ end
59
+
60
+ def test_accuracy_coordinate_operation
61
+ object = Proj::Conversion.create_from_database("EPSG", "1170", :PJ_CATEGORY_COORDINATE_OPERATION)
62
+ assert_equal(16.0, object.accuracy)
63
+ end
64
+
65
+ def test_roundrip
66
+ conversion = Proj::Conversion.new("+proj=cart +ellps=GRS80")
67
+ coord1 = Proj::Coordinate.new(lon: Proj.degrees_to_radians(12), lat: Proj.degrees_to_radians(55), z: 100)
68
+ coord2 = conversion.forward(coord1)
69
+
70
+ dist = conversion.roundtrip(:PJ_FWD, 10000, coord1)
71
+ dist += conversion.roundtrip(:PJ_INV, 10000, coord2)
72
+ assert(dist < 4e-9)
73
+ end
74
+
75
+ def test_accuracy_projection
76
+ conversion = Proj::Conversion.create("+proj=helmert")
77
+ assert_equal(-1.0, conversion.accuracy)
78
+ end
79
+
80
+ def test_method_info
81
+ crs = Proj::Crs.create_from_database("EPSG", "32631", :PJ_CATEGORY_CRS)
82
+ operation = crs.coordinate_operation
83
+ assert_equal("Transverse Mercator", operation.method_name)
84
+ assert_equal("EPSG", operation.method_auth_name)
85
+ assert_equal("9807", operation.method_code)
86
+ end
87
+
88
+ def test_ballpark_transformation
89
+ crs = Proj::Crs.create_from_database("EPSG", "32631", :PJ_CATEGORY_CRS)
90
+ operation = crs.coordinate_operation
91
+ refute(operation.ballpark_transformation?)
92
+ end
93
+
94
+ def test_param_count
95
+ crs = Proj::Crs.create_from_database("EPSG", "32631", :PJ_CATEGORY_CRS)
96
+ operation = crs.coordinate_operation
97
+ assert_equal(5, operation.param_count)
98
+ end
99
+
100
+ def test_param
101
+ crs = Proj::Crs.create_from_database("EPSG", "32631", :PJ_CATEGORY_CRS)
102
+ operation = crs.coordinate_operation
103
+
104
+ param = operation.param(3)
105
+ assert_equal("False easting", param.name)
106
+ assert_equal("EPSG", param.auth_name)
107
+ assert_equal("8806", param.code)
108
+ assert_equal(500000.0, param.value)
109
+ refute(param.value_string)
110
+ assert_equal(1.0, param.unit_conv_factor)
111
+ assert_equal("metre", param.unit_name)
112
+ assert_equal("EPSG", param.unit_auth_name)
113
+ assert_equal("9001", param.unit_code)
114
+ assert_equal("linear", param.unit_category)
115
+ end
116
+
117
+ def test_grid_count
118
+ operation = Proj::Conversion.create_from_database("EPSG", "1312", :PJ_CATEGORY_COORDINATE_OPERATION)
119
+ assert_equal(1, operation.grid_count)
120
+ end
121
+
122
+ def test_grid_url_invalid_index
123
+ context = Proj::Context.new
124
+ conversion = Proj::Conversion.create_from_database("EPSG", "1312", :PJ_CATEGORY_COORDINATE_OPERATION, false, context)
125
+
126
+ error = assert_raises(Proj::Error) do
127
+ conversion.grid(-1)
128
+ end
129
+
130
+ if proj9?
131
+ assert_equal("File not found or invalid", error.to_s)
132
+ else
133
+ assert_equal("Unknown error (code 4096)", error.to_s)
134
+ end
135
+ end
136
+
137
+ def test_grid_url
138
+ context = Proj::Context.new
139
+
140
+ conversion = Proj::Conversion.create_from_database("EPSG", "1312", :PJ_CATEGORY_COORDINATE_OPERATION, true, context)
141
+ grid = conversion.grid(0)
142
+
143
+ assert_equal("ca_nrc_ntv1_can.tif", grid.name)
144
+ assert_match(/ntv1_can/, grid.full_name)
145
+ assert(grid.package_name.empty?)
146
+ assert_equal("https://cdn.proj.org/ca_nrc_ntv1_can.tif", grid.url)
147
+ assert(grid.downloadable?)
148
+ assert(grid.open_license?)
149
+ assert(grid.available?)
150
+ end
151
+
152
+ def test_xy_dist
153
+ conversion = Proj::Conversion.new("+proj=utm; +zone=32; +ellps=GRS80")
154
+ coord1 = Proj::Coordinate.new(lam: Proj.degrees_to_radians(12),
155
+ phi: Proj.degrees_to_radians(55))
156
+
157
+ coord2 = conversion.forward(coord1)
158
+ coord1 = conversion.forward(coord1)
159
+
160
+ dist = conversion.xy_distance(coord1, coord2)
161
+ assert(dist < 2e-9)
162
+ end
163
+
164
+ def test_angular_input
165
+ conversion = Proj::Conversion.new("+proj=cart +ellps=GRS80")
166
+ assert(conversion.angular_input?(:PJ_FWD))
167
+ refute(conversion.angular_input?(:PJ_INV))
168
+ end
169
+
170
+ def test_angular_output
171
+ conversion = Proj::Conversion.new("+proj=cart +ellps=GRS80")
172
+ refute(conversion.angular_output?(:PJ_FWD))
173
+ assert(conversion.angular_output?(:PJ_INV))
174
+ end
175
+
176
+ def test_degree_input
177
+ skip "Unsure why these test fail"
178
+ conversion = Proj::Conversion.new(<<~EOS)
179
+ +proj=pipeline
180
+ +step +inv +proj=utm +zone=32 +ellps=GRS80
181
+ "+step +proj=unitconvert +xy_in=rad +xy_out=deg
182
+ EOS
183
+
184
+ refute(conversion.degree_input?(:PJ_FWD))
185
+ assert(conversion.degree_input?(:PJ_INV))
186
+ end
187
+
188
+ def test_degree_output
189
+ skip "Unsure why these test fail"
190
+ conversion = Proj::Conversion.new(<<~EOS)
191
+ +proj=pipeline
192
+ +step +inv +proj=utm +zone=32 +ellps=GRS80
193
+ "+step +proj=unitconvert +xy_in=rad +xy_out=deg
194
+ EOS
195
+
196
+ assert(conversion.degree_output?(:PJ_FWD))
197
+ refute(conversion.degree_output?(:PJ_INV))
198
+ end
199
+
200
+ def test_steps_concatenated
201
+ context = Proj::Context.new
202
+ source_crs = Proj::Conversion.create_from_database("EPSG", "28356", :PJ_CATEGORY_CRS)
203
+ target_crs = Proj::Conversion.create_from_database("EPSG", "7856", :PJ_CATEGORY_CRS)
204
+
205
+ factory_context = Proj::OperationFactoryContext.new(context)
206
+ factory_context.spatial_criterion = :PROJ_SPATIAL_CRITERION_PARTIAL_INTERSECTION
207
+ factory_context.grid_availability = :PROJ_GRID_AVAILABILITY_IGNORED
208
+
209
+ operations = factory_context.create_operations(source_crs, target_crs)
210
+ assert_equal(3, operations.count)
211
+
212
+ operation = operations[0]
213
+ assert_instance_of(Proj::Conversion, operation)
214
+ assert_equal(:PJ_TYPE_CONCATENATED_OPERATION, operation.proj_type)
215
+
216
+ assert_equal(3, operation.step_count)
217
+ refute(operation.step(-1))
218
+
219
+ step = operation.step(1)
220
+ assert_equal("Transformation of GDA94 coordinates that have been derived through GNSS CORS.", step.scope)
221
+ assert_equal("Scale difference in ppb where 1/billion = 1E-9. See CT codes 8444-46 for NTv2 method giving equivalent results for Christmas Island, Cocos Islands and Australia respectively. See CT code 8447 for alternative including distortion model for Australia only.", step.remarks)
222
+ end
223
+
224
+ def test_transform_array
225
+ crs = Proj::Conversion.new("+proj=utm +zone=32 +ellps=GRS80")
226
+
227
+ coord1 = Proj::Coordinate.new(lon: Proj.degrees_to_radians(12), lat: Proj.degrees_to_radians(55), z: 45)
228
+ coord2 = Proj::Coordinate.new(lon: Proj.degrees_to_radians(12), lat: Proj.degrees_to_radians(56), z: 50)
229
+ new_coords = crs.transform_array([coord1, coord2], :PJ_FWD)
230
+
231
+ coord = new_coords[0]
232
+ assert_equal(691875.6321396607, coord.x)
233
+ assert_equal(6098907.825005012, coord.y)
234
+ assert_equal(45, coord.z)
235
+ assert_equal(0, coord.t)
236
+
237
+ coord = new_coords[1]
238
+ assert_equal(687071.439109443, coord.x)
239
+ assert_equal(6210141.326748009, coord.y)
240
+ assert_equal(50, coord.z)
241
+ assert_equal(0, coord.t)
242
+ end
243
+
244
+ def test_transform_array_invalid
245
+ context = Proj::Context.new
246
+ crs = Proj::Conversion.new("+proj=utm +zone=32 +ellps=GRS80", context)
247
+
248
+ coord1 = Proj::Coordinate.new(lon: Proj.degrees_to_radians(12), lat: Proj.degrees_to_radians(95), z: 45)
249
+ coord2 = Proj::Coordinate.new(lon: Proj.degrees_to_radians(12), lat: Proj.degrees_to_radians(56), z: 50)
250
+
251
+ error = assert_raises(Proj::Error) do
252
+ crs.transform_array([coord1, coord2], :PJ_FWD)
253
+ end
254
+
255
+ assert_equal("Invalid coordinate", error.to_s)
256
+ end
257
+
258
+ def test_pipeline
259
+ conversion = Proj::Conversion.new(<<~EOS)
260
+ +proj=pipeline
261
+ +step +inv +proj=lcc +lat_1=33.88333333333333
262
+ +lat_2=32.78333333333333 +lat_0=32.16666666666666
263
+ +lon_0=-116.25 +x_0=2000000.0001016 +y_0=500000.0001016001 +ellps=GRS80
264
+ +towgs84=0,0,0,0,0,0,0 +units=us-ft +no_defs
265
+ +step +proj=lcc +lat_1=33.88333333333333 +lat_2=32.78333333333333 +lat_0=32.16666666666666
266
+ +lon_0=-116.25 +x_0=2000000 +y_0=500000
267
+ +ellps=GRS80 +towgs84=0,0,0,0,0,0,0 +units=m +no_defs
268
+ EOS
269
+
270
+ # The Presidio, approximately
271
+ coordinate_1 = Proj::Coordinate.new(x: 4760096.421921, y: 3744293.729449)
272
+ coordinate_2 = conversion.forward(coordinate_1)
273
+
274
+ assert_in_delta(1450880.2910605003, coordinate_2.x)
275
+ assert_in_delta(1141263.01116045, coordinate_2.y)
276
+ end
277
+
278
+ if proj9?
279
+ def test_last_used_operation
280
+ wkt = <<~EOS
281
+ CONVERSION["UTM zone 31N",
282
+ METHOD["Transverse Mercator",
283
+ ID["EPSG",9807]],
284
+ PARAMETER["Latitude of natural origin",0,
285
+ ANGLEUNIT["degree",0.0174532925199433],
286
+ ID["EPSG",8801]],
287
+ PARAMETER["Longitude of natural origin",3,
288
+ ANGLEUNIT["degree",0.0174532925199433],
289
+ ID["EPSG",8802]],
290
+ PARAMETER["Scale factor at natural origin",0.9996,
291
+ SCALEUNIT["unity",1],
292
+ ID["EPSG",8805]],
293
+ PARAMETER["False easting",500000,
294
+ LENGTHUNIT["metre",1],
295
+ ID["EPSG",8806]],
296
+ PARAMETER["False northing",0,
297
+ LENGTHUNIT["metre",1],
298
+ ID["EPSG",8807]],
299
+ ID["EPSG",16031]]
300
+ EOS
301
+
302
+ operation = Proj::Conversion.create_from_wkt(wkt)
303
+ puts operation.to_wkt
304
+
305
+ operation = Proj::Conversion.create_from_database("EPSG", "16031", :PJ_CATEGORY_COORDINATE_OPERATION)
306
+ puts operation.to_wkt
307
+
308
+ last = operation.last_used_operation
309
+ refute(last)
310
+
311
+ coord = Proj::Coordinate.new(x: Proj::Api.proj_torad(3.0), y: 0, z: 0, t: 0)
312
+ new_coord = operation.forward(coord)
313
+
314
+ assert_in_delta(500000, new_coord.x, 1.0)
315
+ assert_in_delta(0.0, new_coord.y)
316
+ assert_in_delta(0.0, new_coord.z)
317
+ assert_in_delta(0.0, new_coord.t)
318
+
319
+ last = operation.last_used_operation
320
+ assert(last)
321
+ assert(last.equivalent_to?(operation, :PJ_COMP_STRICT))
322
+ end
323
+ end
324
+
325
+ def test_convert_conversion_to_other_method
326
+ context = Proj::Context.new
327
+ coordinate_system = Proj::CoordinateSystem.create_ellipsoidal_2d(:PJ_ELLPS2D_LONGITUDE_LATITUDE, context)
328
+
329
+ crs = Proj::Crs.create_geographic(context, name: "WGS 84", datum_name: "World Geodetic System 1984", ellps_name: "WGS 84",
330
+ semi_major_meter: 6378137, inv_flattening: 298.257223563,
331
+ prime_meridian_name: "Greenwich", prime_meridian_offset: 0.0, pm_angular_units: "Degree", pm_units_conv: 0.0174532925199433,
332
+ coordinate_system: coordinate_system)
333
+
334
+ mercator = Proj::Projection.mercator_variant_a(context, center_lat: 0, center_long: 1,
335
+ scale: 0.99,
336
+ false_easting: 2, false_northing: 3,
337
+ ang_unit_name: "Degree", ang_unit_conv_factor: 0.0174532925199433,
338
+ linear_unit_name: "Metre", linear_unit_conv_factor: 1.0)
339
+
340
+ cartesian = Proj::CoordinateSystem.create_cartesian_2d(context, :PJ_CART2D_EASTING_NORTHING)
341
+
342
+ projected = Proj::Crs.create_projected(context, name: "My CRS", geodetic_crs: crs,
343
+ conversion: mercator, coordinate_system: cartesian)
344
+
345
+ conversion = projected.coordinate_operation
346
+ assert_equal(:PJ_TYPE_CONVERSION, conversion.proj_type)
347
+
348
+ # Error - Don't set code or method name
349
+ new_conversion = conversion.convert_to_other_method
350
+ refute(new_conversion)
351
+
352
+ # 9805 is epsg code mercator variant b
353
+ new_conversion = conversion.convert_to_other_method(new_method_epsg_code: 9805)
354
+ assert(new_conversion)
355
+ refute(new_conversion.equivalent_to?(conversion, :PJ_COMP_STRICT))
356
+ assert(new_conversion.equivalent_to?(conversion, :PJ_COMP_EQUIVALENT))
357
+
358
+ new_conversion = conversion.convert_to_other_method(new_method_name: "Mercator (variant B)")
359
+ assert(new_conversion)
360
+ refute(new_conversion.equivalent_to?(conversion, :PJ_COMP_STRICT))
361
+ assert(new_conversion.equivalent_to?(conversion, :PJ_COMP_EQUIVALENT))
362
+
363
+ # Convert back
364
+ new_conversion = conversion.convert_to_other_method(new_method_name: "Mercator (variant A)")
365
+ assert(new_conversion)
366
+ assert(new_conversion.equivalent_to?(conversion, :PJ_COMP_STRICT))
367
+ end
368
+ end