proj4rb 3.0.0 → 4.0.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.
- 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
|