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.
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