proj4rb 3.0.0 → 4.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/ChangeLog +26 -15
- data/README.rdoc +82 -44
- data/Rakefile +27 -27
- data/lib/api/api.rb +96 -118
- data/lib/api/api_5_0.rb +331 -300
- data/lib/api/api_5_1.rb +6 -6
- data/lib/api/api_5_2.rb +4 -4
- data/lib/api/api_6_0.rb +116 -14
- data/lib/api/api_6_1.rb +4 -4
- data/lib/api/api_6_2.rb +9 -6
- data/lib/api/api_6_3.rb +6 -0
- data/lib/api/api_7_0.rb +68 -0
- data/lib/api/api_7_1.rb +73 -0
- data/lib/api/api_7_2.rb +14 -0
- data/lib/api/api_8_0.rb +6 -0
- data/lib/api/api_8_1.rb +24 -0
- data/lib/api/api_8_2.rb +6 -0
- data/lib/api/api_9_1.rb +7 -0
- data/lib/api/api_9_2.rb +9 -0
- data/lib/api/api_experimental.rb +196 -0
- data/lib/proj/area.rb +73 -32
- data/lib/proj/axis_info.rb +44 -0
- data/lib/proj/bounds.rb +13 -0
- data/lib/proj/context.rb +174 -28
- data/lib/proj/conversion.rb +92 -0
- data/lib/proj/coordinate.rb +281 -197
- data/lib/proj/coordinate_operation_mixin.rb +381 -0
- data/lib/proj/coordinate_system.rb +137 -0
- data/lib/proj/crs.rb +672 -204
- data/lib/proj/crs_info.rb +47 -0
- data/lib/proj/database.rb +305 -0
- data/lib/proj/datum.rb +32 -0
- data/lib/proj/datum_ensemble.rb +34 -0
- data/lib/proj/ellipsoid.rb +77 -41
- data/lib/proj/error.rb +62 -9
- data/lib/proj/file_api.rb +166 -0
- data/lib/proj/grid.rb +121 -0
- data/lib/proj/grid_cache.rb +64 -0
- data/lib/proj/grid_info.rb +19 -0
- data/lib/proj/network_api.rb +92 -0
- data/lib/proj/operation.rb +42 -42
- data/lib/proj/operation_factory_context.rb +136 -0
- data/lib/proj/parameter.rb +38 -0
- data/lib/proj/parameters.rb +106 -0
- data/lib/proj/pj_object.rb +670 -80
- data/lib/proj/pj_objects.rb +44 -0
- data/lib/proj/prime_meridian.rb +65 -39
- data/lib/proj/projection.rb +698 -207
- data/lib/proj/session.rb +46 -0
- data/lib/proj/strings.rb +32 -0
- data/lib/proj/transformation.rb +101 -60
- data/lib/proj/unit.rb +108 -53
- data/lib/proj.rb +110 -9
- data/proj4rb.gemspec +5 -5
- data/test/abstract_test.rb +23 -1
- data/test/context_test.rb +172 -82
- data/test/conversion_test.rb +368 -0
- data/test/coordinate_system_test.rb +144 -0
- data/test/crs_test.rb +770 -71
- data/test/database_test.rb +360 -0
- data/test/datum_ensemble_test.rb +65 -0
- data/test/datum_test.rb +55 -0
- data/test/ellipsoid_test.rb +64 -18
- data/test/file_api_test.rb +66 -0
- data/test/grid_cache_test.rb +72 -0
- data/test/grid_test.rb +141 -0
- data/test/network_api_test.rb +45 -0
- data/test/operation_factory_context_test.rb +201 -0
- data/test/parameters_test.rb +40 -0
- data/test/pj_object_test.rb +179 -0
- data/test/prime_meridian_test.rb +76 -0
- data/test/proj_test.rb +46 -4
- data/test/projection_test.rb +646 -222
- data/test/session_test.rb +78 -0
- data/test/transformation_test.rb +149 -7
- data/test/unit_test.rb +57 -28
- metadata +51 -13
- data/lib/api/api_4_9.rb +0 -31
- data/lib/proj/config.rb +0 -70
- data/lib/proj/point.rb +0 -72
- 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
|
-
|
13
|
-
context = Proj::Context.new
|
14
|
-
assert(context.to_ptr)
|
15
|
-
GC.start
|
16
|
-
end
|
17
|
-
assert(true)
|
18
|
-
end
|
19
|
-
|
20
|
-
def
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
end
|
29
|
-
|
30
|
-
def
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
end
|
39
|
-
|
40
|
-
def
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
end
|
72
|
-
|
73
|
-
def
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
end
|
82
|
-
|
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
|