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/lib/proj/area.rb CHANGED
@@ -1,32 +1,73 @@
1
- module Proj
2
- class Area
3
- attr_reader :name, :west_lon_degree, :south_lat_degree, :east_lon_degree, :north_lat_degree
4
-
5
- def self.for_object(pj_object)
6
- p_name = FFI::MemoryPointer.new(:pointer)
7
- p_west_lon_degree = FFI::MemoryPointer.new(:double)
8
- p_south_lat_degree = FFI::MemoryPointer.new(:double)
9
- p_east_lon_degree = FFI::MemoryPointer.new(:double)
10
- p_north_lat_degree = FFI::MemoryPointer.new(:double)
11
-
12
- result = Api.proj_get_area_of_use(Context.current, pj_object,
13
- p_west_lon_degree, p_south_lat_degree, p_east_lon_degree, p_north_lat_degree,
14
- p_name)
15
- unless result
16
- Error.check
17
- end
18
-
19
- name = p_name.read_pointer.read_string_to_null.force_encoding('utf-8')
20
- self.new(name,
21
- p_west_lon_degree.read_double, p_south_lat_degree.read_double, p_east_lon_degree.read_double, p_north_lat_degree.read_double)
22
- end
23
-
24
- def initialize(name, west_lon_degree, south_lat_degree, east_lon_degree, north_lat_degree)
25
- @name = name
26
- @west_lon_degree = west_lon_degree
27
- @south_lat_degree = south_lat_degree
28
- @east_lon_degree = east_lon_degree
29
- @north_lat_degree = north_lat_degree
30
- end
31
- end
32
- end
1
+ # encoding: UTF-8
2
+
3
+ module Proj
4
+ # Areas are used to specify the area of use for the choice of relevant coordinate operations.
5
+ # See Transformation#new
6
+ class Area
7
+ attr_reader :name, :west_lon_degree, :south_lat_degree, :east_lon_degree, :north_lat_degree
8
+
9
+ def self.finalize(pointer)
10
+ proc do
11
+ Api.proj_area_destroy(pointer)
12
+ end
13
+ end
14
+
15
+ def initialize(west_lon_degree:, south_lat_degree:, east_lon_degree:, north_lat_degree:, name: nil)
16
+ @west_lon_degree = west_lon_degree
17
+ @south_lat_degree = south_lat_degree
18
+ @east_lon_degree = east_lon_degree
19
+ @north_lat_degree = north_lat_degree
20
+ @name = name
21
+ create_area
22
+ end
23
+
24
+ def to_ptr
25
+ @area
26
+ end
27
+
28
+ # Sets the bounds for an area
29
+ #
30
+ # @see https://proj.org/development/reference/functions.html#c.proj_area_set_bbox
31
+ #
32
+ # @param west_lon_degree [Float] West longitude, in degrees. In [-180,180] range.
33
+ # @param south_lat_degree [Float] South latitude, in degrees. In [-90,90] range.
34
+ # @param east_lon_degree [Float] East longitude, in degrees. In [-180,180] range.
35
+ # @param north_lat_degree [Float] North latitude, in degrees. In [-90,90] range.
36
+ def set_bounds(west_lon_degree:, south_lat_degree:, east_lon_degree:, north_lat_degree:)
37
+ Api.proj_area_set_bbox(self, west_lon_degree, south_lat_degree, east_lon_degree, north_lat_degree)
38
+ end
39
+
40
+ # Sets the name for an area
41
+ #
42
+ # @param value [String] The name of the area
43
+ def name=(value)
44
+ @name = name
45
+ # This Api wasn't added until proj 9.1
46
+ if defined?(Api.proj_area_set_name)
47
+ Api.proj_area_set_name(self, value)
48
+ end
49
+ end
50
+
51
+ # Returns nice printout of an Area
52
+ #
53
+ # @return [String]
54
+ def to_s
55
+ "Area west_lon_degree: #{self.west_lon_degree}, south_lat_degree: #{self.south_lat_degree}, east_lon_degree: #{self.east_lon_degree}, north_lat_degree: #{self.north_lat_degree}"
56
+ end
57
+
58
+ private
59
+
60
+ # Creates an area
61
+ #
62
+ # @see https://proj.org/development/reference/functions.html#c.proj_area_create
63
+ def create_area
64
+ @area = Api.proj_area_create
65
+ self.set_bounds(west_lon_degree: west_lon_degree, south_lat_degree: south_lat_degree,
66
+ east_lon_degree: east_lon_degree, north_lat_degree: north_lat_degree)
67
+ if name
68
+ self.name = name
69
+ end
70
+ ObjectSpace.define_finalizer(self, self.class.finalize(@area))
71
+ end
72
+ end
73
+ end
@@ -0,0 +1,44 @@
1
+ module Proj
2
+ class AxisInfo
3
+ # @!attribute [r] name
4
+ # @return [String] Axis name
5
+ # @!attribute [r] abbreviation
6
+ # @return [String] Axis abbreviation
7
+ # @!attribute [r] direction
8
+ # @return [String] Axis direction
9
+ # @!attribute [r] unit_conv_factor
10
+ # @return [String] Axis unit_conv_factor
11
+ # @!attribute [r] unit_name
12
+ # @return [String] Axis unit_name
13
+ # @!attribute [r] unit_auth_name
14
+ # @return [String] Axis unit_auth_name
15
+ # @!attribute [r] unit_code
16
+ # @return [String] Axis unit_code
17
+ attr_reader :name, :abbreviation, :direction,
18
+ :unit_name, :unit_auth_name, :unit_code, :unit_conv_factor
19
+
20
+ def initialize(name:, abbreviation:, direction:, unit_conv_factor:, unit_name:, unit_auth_name:, unit_code:)
21
+ @name = name
22
+ @abbreviation = abbreviation
23
+ @direction = direction
24
+ @unit_conv_factor = unit_conv_factor
25
+ @unit_name = unit_name
26
+ @unit_auth_name = unit_auth_name
27
+ @unit_code = unit_code
28
+ end
29
+
30
+ # Returns axis information in PJ_AXIS_DESCRIPTION structure
31
+ #
32
+ # @return [PJ_AXIS_DESCRIPTION]
33
+ def to_description
34
+ Api::PJ_AXIS_DESCRIPTION.create(name: name, abbreviation: abbreviation, direction: direction,
35
+ unit_conv_factor: unit_conv_factor, unit_name: name, unit_type: self.unit_type)
36
+ end
37
+
38
+ def unit_type
39
+ database = Database.new(Context.default)
40
+ unit = database.unit(self.unit_auth_name, self.unit_code)
41
+ unit.type
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,13 @@
1
+ module Proj
2
+ class Bounds
3
+ attr_reader :name, :xmin, :ymin, :xmax, :ymax
4
+
5
+ def initialize(xmin, ymin, xmax, ymax, name = nil)
6
+ @xmin = xmin
7
+ @ymin = ymin
8
+ @xmax = xmax
9
+ @ymax = ymax
10
+ @name = name
11
+ end
12
+ end
13
+ end
data/lib/proj/context.rb CHANGED
@@ -1,10 +1,24 @@
1
1
  module Proj
2
2
  # Proj 4.8 introduced the concept of a thread context object to support multi-threaded programs. The bindings
3
- # automatically create on context per thread (its stored in local thread storage).
3
+ # automatically create one context per thread (its stored in local thread storage).
4
4
  class Context
5
- # The context for the current thread
5
+ attr_reader :database
6
+
7
+ # Returns the default Proj context. This context *must* only be used in the main thread
8
+ # In general it is better to create new contexts
6
9
  #
7
- # @return [Context]
10
+ # @return [Context] The default context
11
+ def self.default
12
+ result = Context.allocate
13
+ # The default Proj Context is represented by a null pointer
14
+ result.instance_variable_set(:@pointer, FFI::Pointer::NULL)
15
+ result
16
+ end
17
+
18
+ # The context for the current thread. If a context does not exist
19
+ # a new one is created
20
+ #
21
+ # @return [Context] The context for the current thread
8
22
  def self.current
9
23
  Thread.current[:proj_context] ||= Context.new
10
24
  end
@@ -19,43 +33,33 @@ module Proj
19
33
  @pointer = Api.proj_context_create
20
34
  ObjectSpace.define_finalizer(self, self.class.finalize(@pointer))
21
35
 
22
- set_database_path
36
+ @database = Database.new(self)
23
37
  end
24
38
 
25
- # Helper method that tries to locate the Proj coordinate database (proj.db)
26
- def set_database_path
27
- return unless Api.method_defined?(:proj_context_get_database_path)
28
- return if database_path
39
+ def initialize_copy(original)
40
+ ObjectSpace.undefine_finalizer(self)
41
+
42
+ super
29
43
 
30
- self.database_path = Config.instance.db_path
44
+ @pointer = Api.proj_context_clone(original)
45
+ @database = Database.new(self)
46
+
47
+ ObjectSpace.define_finalizer(self, self.class.finalize(@pointer))
31
48
  end
32
49
 
33
50
  def to_ptr
34
51
  @pointer
35
52
  end
36
53
 
37
- # Get the last error number
54
+ # Returns the current error-state of the context. An non-zero error codes indicates an error.
55
+ #
56
+ # See https://proj.org/development/reference/functions.html#c.proj_context_errno proj_context_errno
38
57
  #
39
58
  # return [Integer]
40
59
  def errno
41
60
  Api.proj_context_errno(self)
42
61
  end
43
62
 
44
- # Gets the path the Proj database
45
- #
46
- # return [String]
47
- def database_path
48
- Api.proj_context_get_database_path(self)
49
- end
50
-
51
- # Sets the path to the Proj database
52
- def database_path=(value)
53
- result = Api.proj_context_set_database_path(self, value, nil, nil)
54
- unless result == 1
55
- Error.check(self.errno)
56
- end
57
- end
58
-
59
63
  # Sets a custom log function
60
64
  #
61
65
  # @example
@@ -65,6 +69,7 @@ module Proj
65
69
  #
66
70
  # @param pointer [FFI::MemoryPointer] Optional pointer to custom data
67
71
  # @param proc [Proc] Custom logging procedure
72
+ #
68
73
  # @return [nil]
69
74
  def set_log_function(pointer = nil, &proc)
70
75
  Api.proj_log_func(self, pointer, proc)
@@ -72,14 +77,14 @@ module Proj
72
77
 
73
78
  # Gets the current log level
74
79
  #
75
- # @return [:PJ_LOG_LEVEL]
80
+ # @return [PJ_LOG_LEVEL]
76
81
  def log_level
77
82
  Api.proj_log_level(self, :PJ_LOG_TELL)
78
83
  end
79
84
 
80
85
  # Sets the current log level
81
86
  #
82
- # @param value [:PJ_LOG_LEVEL]
87
+ # @param value [PJ_LOG_LEVEL]
83
88
  # @return [nil]
84
89
  def log_level=(value)
85
90
  Api.proj_log_level(self, value)
@@ -89,15 +94,156 @@ module Proj
89
94
  #
90
95
  # @return [Boolean]
91
96
  def use_proj4_init_rules
92
- Api.proj_context_get_use_proj4_init_rules(self, 0)
97
+ result = Api.proj_context_get_use_proj4_init_rules(self, 0)
98
+ result == 1 ? true : false
93
99
  end
94
100
 
95
101
  # Sets if proj4 init rules should be used
96
102
  #
97
103
  # @param value [Boolean]
104
+ #
98
105
  # @return [nil]
99
106
  def use_proj4_init_rules=(value)
100
107
  Api.proj_context_use_proj4_init_rules(self, value ? 1 : 0)
101
108
  end
109
+
110
+ # Guess the "dialect" of the specified WKT string
111
+ #
112
+ # @see https://proj.org/development/reference/functions.html#c.proj_context_guess_wkt_dialect
113
+ #
114
+ # @param wkt [String] A WKT string
115
+ #
116
+ # @return [PJ_GUESSED_WKT_DIALECT]
117
+ def wkt_dialect(wkt)
118
+ Api.proj_context_guess_wkt_dialect(self, wkt)
119
+ end
120
+
121
+ # Sets the CA Bundle path which will be used by PROJ when curl and PROJ_NETWORK are enabled.
122
+ #
123
+ # @see https://proj.org/development/reference/functions.html#c.proj_context_set_ca_bundle_path
124
+ #
125
+ # @param path [String] Path to CA bundle.
126
+ #
127
+ # @return [nil]
128
+ def ca_bundle_path=(path)
129
+ Api.proj_context_set_ca_bundle_path(self, path.encode(:utf8))
130
+ end
131
+
132
+ # Returns the cache used to store grid files locally
133
+ #
134
+ # @return [GridCache]
135
+ def cache
136
+ GridCache.new(self)
137
+ end
138
+
139
+ # Returns if network access is enabled allowing {Grid} files to be downloaded
140
+ #
141
+ # @see https://proj.org/development/reference/functions.html#c.proj_context_is_network_enabled
142
+ #
143
+ # @return [Boolean] True if network access is enabled, otherwise false
144
+ def network_enabled?
145
+ result = Api.proj_context_is_network_enabled(self)
146
+ result == 1 ? true : false
147
+ end
148
+
149
+ # Enable or disable network access for downloading grid files
150
+ #
151
+ # @see https://proj.org/development/reference/functions.html#c.proj_context_set_enable_network
152
+ #
153
+ # @param value [Boolean] Specifies if network access should be enabled or disabled
154
+ def network_enabled=(value)
155
+ Api.proj_context_set_enable_network(self, value ? 1 : 0)
156
+ end
157
+
158
+ # Returns the URL endpoint to query for remote grids
159
+ #
160
+ # @see https://proj.org/development/reference/functions.html#c.proj_context_get_url_endpoint
161
+ #
162
+ # @return [String] Endpoint URL
163
+ def url
164
+ Api.proj_context_get_url_endpoint(self)
165
+ end
166
+
167
+ # Sets the URL endpoint to query for remote grids. This overrides the default endpoint in the PROJ configuration file or with the PROJ_NETWORK_ENDPOINT environment variable.
168
+ #
169
+ # @see https://proj.org/development/reference/functions.html#c.proj_context_set_url_endpoint
170
+ #
171
+ # @param value [String] Endpoint URL
172
+ def url=(value)
173
+ Api.proj_context_set_url_endpoint(self, value)
174
+ end
175
+
176
+ # Returns the user directory used to save grid files.
177
+ #
178
+ # @see https://proj.org/development/reference/functions.html#c.proj_context_get_user_writable_directory
179
+ #
180
+ # @param [Boolean] If set to TRUE, create the directory if it does not exist already. Defaults to false
181
+ #
182
+ # @return [String] Directory
183
+ def user_directory(create = false)
184
+ Api.proj_context_get_user_writable_directory(self, create ? 1 : 0)
185
+ end
186
+
187
+ # Sets the paths that Proj will search when opening one of its resource files
188
+ # such as the proj.db database, grids, etc.
189
+ #
190
+ # If set on the default context, they will be inherited by contexts created later.
191
+ #
192
+ # @see https://proj.org/development/reference/functions.html#c.proj_context_set_search_paths
193
+ def search_paths=(paths)
194
+ # Convert paths to C chars
195
+ paths_ptr = paths.map do |path|
196
+ FFI::MemoryPointer.from_string(path)
197
+ end
198
+
199
+ pointer = FFI::MemoryPointer.new(:pointer, paths.size)
200
+ pointer.write_array_of_pointer(paths_ptr)
201
+
202
+ if Api.method_defined?(:proj_context_set_search_paths)
203
+ Api.proj_context_set_search_paths(self, paths.size, pointer)
204
+ elsif Api.method_defined?(:pj_set_searchpath)
205
+ Api.pj_set_searchpath(paths.size, pointer)
206
+ end
207
+ end
208
+
209
+ # Installs a new {FileApi FileApiImpl}
210
+ #
211
+ # @see https://proj.org/development/reference/functions.html#c.proj_context_set_fileapi
212
+ def set_file_api(file_api_klass)
213
+ unless file_api_klass.kind_of?(Class)
214
+ raise("#{file_api_klass} must be a class whose initializer has single argument which is a context")
215
+ end
216
+
217
+ # There is no API to "uninstall" a FileApi. Thus it needs to stay alive
218
+ # until the context is GCed
219
+ @file_api = file_api_klass.new(self)
220
+ end
221
+
222
+ # Installs a new {NetworkApi NetworkApiImpl}
223
+ #
224
+ # @see https://proj.org/development/reference/functions.html#c.proj_context_set_network_callbacks
225
+ def set_network_api(network_api_klass)
226
+ unless network_api_klass.kind_of?(Class)
227
+ raise("#{network_api_klass} must be a class whose initializer has single argument which is a context")
228
+ end
229
+
230
+ # There is no API to "uninstall" a FileApi. Thus it needs to stay alive
231
+ # until the context is GCed
232
+ @network_api = network_api_klass.new(self)
233
+ end
234
+
235
+ # --- Deprecated -------
236
+ def database_path
237
+ self.database.path
238
+ end
239
+
240
+ # Sets the path to the Proj database
241
+ def database_path=(value)
242
+ self.database.path = value
243
+ end
244
+
245
+ extend Gem::Deprecate
246
+ deprecate :database_path, "context.database.path", 2023, 6
247
+ deprecate :database_path=, "context.database.path=", 2023, 6
102
248
  end
103
249
  end
@@ -0,0 +1,92 @@
1
+ # encoding: UTF-8
2
+ require 'stringio'
3
+
4
+ module Proj
5
+ # Conversions are {CoordinateOperationMix coordinate operations} that convert a source
6
+ # {Coordinate coordinate} to a new value. In Proj they are defined as operations that
7
+ # do not exert a change in reference frame while {Transformation transformations } do.
8
+ class Conversion < PjObject
9
+ include CoordinateOperationMixin
10
+
11
+ # Instantiate a Conversion
12
+
13
+ # Create a Transformation
14
+ #
15
+ # @param context [Context] Context
16
+ # @param name [String] Name of the transformation. Default is nil.
17
+ # @param auth_name [String] Transformation authority name. Default is nil.
18
+ # @param code [String] Transformation code. Default is nil.
19
+ # @param method_name [String] Method name. Default is nil.
20
+ # @param method_auth_name [String] Method authority name. Default is nil.
21
+ # @param method_code [String] Method code. Default is nil.
22
+ # @param params [Array<Parameter>] Parameter descriptions
23
+ # @param accuracy [Double] Accuracy of the transformation in meters. A negative value means unknown.
24
+ #
25
+ # @return [Conversion]
26
+ def self.create_conversion(context, name:, auth_name:, code:, method_name:, method_auth_name:, method_code:, params:)
27
+ params_ptr = FFI::MemoryPointer.new(Api::PJ_PARAM_DESCRIPTION, params.size)
28
+ params.each_with_index do |param, i|
29
+ param_description_target = Api::PJ_PARAM_DESCRIPTION.new(params_ptr[i])
30
+ param_description_source = param.to_description
31
+ param_description_target.to_ptr.__copy_from__(param_description_source.to_ptr, Api::PJ_PARAM_DESCRIPTION.size)
32
+ end
33
+
34
+ pointer = Api.proj_create_conversion(context, name, auth_name, code, method_name, method_auth_name, method_code, params.size, params_ptr)
35
+ Error.check_context(context)
36
+ self.create_object(pointer, context)
37
+ end
38
+
39
+ # Instantiates an conversion from a string. The string can be:
40
+ #
41
+ # * proj-string,
42
+ # * WKT string,
43
+ # * object code (like "EPSG:4326", "urn:ogc:def:crs:EPSG::4326", "urn:ogc:def:coordinateOperation:EPSG::1671"),
44
+ # * Object name. e.g "WGS 84", "WGS 84 / UTM zone 31N". In that case as uniqueness is not guaranteed, heuristics are applied to determine the appropriate best match.
45
+ # * OGC URN combining references for compound coordinate reference systems (e.g "urn:ogc:def:crs,crs:EPSG::2393,crs:EPSG::5717" or custom abbreviated syntax "EPSG:2393+5717"),
46
+ # * OGC URN combining references for concatenated operations (e.g. "urn:ogc:def:coordinateOperation,coordinateOperation:EPSG::3895,coordinateOperation:EPSG::1618")
47
+ # * PROJJSON string. The jsonschema is at https://proj.org/schemas/v0.4/projjson.schema.json (added in 6.2)
48
+ # * compound CRS made from two object names separated with " + ". e.g. "WGS 84 + EGM96 height" (added in 7.1)
49
+ #
50
+ # @see https://proj.org/development/reference/functions.html#c.proj_create
51
+ #
52
+ # @param value [String]. See above
53
+ #
54
+ # @return [Conversion]
55
+ def initialize(value, context=nil)
56
+ context ||= Context.current
57
+ ptr = Api.proj_create(context, value)
58
+
59
+ if ptr.null?
60
+ Error.check_context(context)
61
+ end
62
+
63
+ if Api.method_defined?(:proj_is_crs) && Api.proj_is_crs(ptr)
64
+ raise(Error, "Invalid conversion. Proj created an instance of: #{self.proj_type}.")
65
+ end
66
+
67
+ super(ptr, context)
68
+ end
69
+
70
+ # Return an equivalent projection. Currently implemented:
71
+ # * EPSG_CODE_METHOD_MERCATOR_VARIANT_A (1SP) to EPSG_CODE_METHOD_MERCATOR_VARIANT_B (2SP)
72
+ # * EPSG_CODE_METHOD_MERCATOR_VARIANT_B (2SP) to EPSG_CODE_METHOD_MERCATOR_VARIANT_A (1SP)
73
+ # * EPSG_CODE_METHOD_LAMBERT_CONIC_CONFORMAL_1SP to EPSG_CODE_METHOD_LAMBERT_CONIC_CONFORMAL_2SP
74
+ # * EPSG_CODE_METHOD_LAMBERT_CONIC_CONFORMAL_2SP to EPSG_CODE_METHOD_LAMBERT_CONIC_CONFORMAL_1SP
75
+ #
76
+ # @param new_method_epsg_code [String] EPSG code of the target method. Or nil in which case new_method_name must be specified.
77
+ # @param new_method_name [String] EPSG or PROJ target method name. Or nil in which case new_method_epsg_code must be specified
78
+ #
79
+ # @return [Conversion]
80
+ def convert_to_other_method(new_method_epsg_code: nil, new_method_name: nil)
81
+ ptr = Api.proj_convert_conversion_to_other_method(self.context, self,
82
+ new_method_epsg_code ? new_method_epsg_code: 0,
83
+ new_method_name)
84
+
85
+ if ptr.null?
86
+ Error.check_context(context)
87
+ end
88
+
89
+ self.class.create_object(ptr, context)
90
+ end
91
+ end
92
+ end