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
@@ -0,0 +1,47 @@
1
+ # encoding: UTF-8
2
+ module Proj
3
+ class CrsInfo
4
+ attr_reader :auth_name, :code, :name, :type, :deprecated, :bbox_valid,
5
+ :west_lon_degree, :south_lat_degree, :east_lon_degree, :north_lat_degree,
6
+ :area_name, :projection_method_name, :celestial_body_name
7
+
8
+ def self.from_proj_crs_info(proj_crs_info)
9
+ data = {auth_name: proj_crs_info[:auth_name],
10
+ code: proj_crs_info[:code],
11
+ name: proj_crs_info[:name],
12
+ type: proj_crs_info[:type],
13
+ deprecated: proj_crs_info[:deprecated] == 1 ? true : false,
14
+ bbox_valid: proj_crs_info[:bbox_valid] == 1 ? true : false,
15
+ west_lon_degree: proj_crs_info[:west_lon_degree],
16
+ south_lat_degree: proj_crs_info[:south_lat_degree],
17
+ east_lon_degree: proj_crs_info[:east_lon_degree],
18
+ north_lat_degree: proj_crs_info[:north_lat_degree],
19
+ area_name: proj_crs_info[:area_name],
20
+ projection_method_name: proj_crs_info[:projection_method_name]}
21
+
22
+ if Api::PROJ_VERSION >= Gem::Version.new('8.1.0')
23
+ data[:celestial_body_name] = proj_crs_info[:celestial_body_name]
24
+ end
25
+
26
+ new(**data)
27
+ end
28
+
29
+ def initialize(auth_name:, code:, name:, type:, deprecated:, bbox_valid:,
30
+ west_lon_degree:, south_lat_degree:, east_lon_degree:, north_lat_degree:,
31
+ area_name:, projection_method_name:, celestial_body_name: nil)
32
+ @auth_name = auth_name
33
+ @code = code
34
+ @name = name
35
+ @type = type
36
+ @deprecated = deprecated
37
+ @bbox_valid = bbox_valid
38
+ @west_lon_degree = west_lon_degree
39
+ @south_lat_degree = south_lat_degree
40
+ @east_lon_degree = east_lon_degree
41
+ @north_lat_degree = north_lat_degree
42
+ @area_name = area_name
43
+ @projection_method_name = projection_method_name
44
+ @celestial_body_name = celestial_body_name
45
+ end
46
+ end
47
+ end
@@ -0,0 +1,305 @@
1
+ module Proj
2
+ CelestialBody = Struct.new(:auth_name, :name)
3
+
4
+ # This class provides access the Proj SQLite database called proj.db. The database
5
+ # stores transformation information that must be accessible for the library to work properly.
6
+ #
7
+ # @see https://proj.org/resource_files.html#proj-db
8
+ class Database
9
+ attr_reader :context
10
+
11
+ # Create a new database instance to query the Proj database
12
+ #
13
+ # @param context [Context] A proj Context
14
+ #
15
+ # @return [Database]
16
+ def initialize(context)
17
+ @context = context
18
+ end
19
+
20
+ # Returns the path the Proj database
21
+ #
22
+ # @see https://proj.org/development/reference/functions.html#c.proj_context_get_database_path
23
+ #
24
+ # return [String]
25
+ def path
26
+ if Api.method_defined?(:proj_context_get_database_path)
27
+ Api.proj_context_get_database_path(self.context)
28
+ end
29
+ end
30
+
31
+ # Sets the path to the Proj database
32
+ #
33
+ # @see https://proj.org/development/reference/functions.html#c.proj_context_set_database_path
34
+ #
35
+ # @param value [String] Path to the proj database
36
+ #
37
+ # @return [Database] Returns reference to the current database instance
38
+ def path=(value)
39
+ result = Api.proj_context_set_database_path(self.context, value, nil, nil)
40
+ unless result == 1
41
+ Error.check_context(self.context)
42
+ end
43
+ self
44
+ end
45
+
46
+ # Returns SQL statements to run to initiate a new valid auxiliary empty database.
47
+ #
48
+ # @see https://proj.org/development/reference/functions.html#c.proj_context_get_database_structure
49
+ #
50
+ # @return [Array<Strings>] List of sql statements
51
+ def structure
52
+ ptr = Api.proj_context_get_database_structure(self.context, nil)
53
+ Strings.new(ptr)
54
+ end
55
+
56
+ # Return a metadata from the database.
57
+ #
58
+ # @see https://proj.org/development/reference/functions.html#c.proj_context_get_database_metadata
59
+ #
60
+ # @param key [String] The name of the metadata item. Must not be nil
61
+ # Available keys:
62
+ # DATABASE.LAYOUT.VERSION.MAJOR
63
+ # DATABASE.LAYOUT.VERSION.MINOR
64
+ # EPSG.VERSION
65
+ # EPSG.DATE
66
+ # ESRI.VERSION
67
+ # ESRI.DATE
68
+ # IGNF.SOURCE
69
+ # IGNF.VERSION
70
+ # IGNF.DATE
71
+ # NKG.SOURCE
72
+ # NKG.VERSION
73
+ # NKG.DATE
74
+ # PROJ.VERSION
75
+ # PROJ_DATA.VERSION
76
+ #
77
+ # @return [String] Returned metadata
78
+ def metadata(key)
79
+ Api.proj_context_get_database_metadata(self.context, key)
80
+ end
81
+
82
+ # Returns the set of authority codes of the given object type.
83
+ #
84
+ # @see https://proj.org/development/reference/functions.html#c.proj_get_codes_from_database
85
+ #
86
+ # @param auth_name [String] Authority name. Must not be nil.
87
+ # @param type [PJ_TYPE] Object type.
88
+ # @param allow_deprecated [Boolean] Specifies if deprecated objects should be returned. Default is false.
89
+ #
90
+ # @return [Strings] Returned authority codes
91
+ def codes(auth_name, type, allow_deprecated = false)
92
+ ptr = Api.proj_get_codes_from_database(self.context, auth_name, type, allow_deprecated ? 1 : 0)
93
+ Strings.new(ptr)
94
+ end
95
+
96
+ # Return a list of authorities used in the database
97
+ #
98
+ # @see https://proj.org/development/reference/functions.html#c.proj_get_authorities_from_database
99
+ #
100
+ # @return [Array<Strings>] List of authorities
101
+ def authorities
102
+ ptr = Api.proj_get_authorities_from_database(self.context)
103
+ Strings.new(ptr)
104
+ end
105
+
106
+ # Enumerate CRS infos from the database, taking into account various criteria.
107
+ #
108
+ # @see https://proj.org/development/reference/functions.html#c.proj_get_crs_info_list_from_database
109
+ #
110
+ # @param auth_name [String] Authority name. Use nil to specify all authorities
111
+ # @param parameters [Parameters] Parameters to specify search criteria. May be nil
112
+ #
113
+ # @return [Array<CrsInfo>] Returned crs infos
114
+ def crs_info(auth_name = nil, parameters = nil)
115
+ out_result_count = FFI::MemoryPointer.new(:int)
116
+ ptr = Api.proj_get_crs_info_list_from_database(self.context, auth_name, parameters, out_result_count)
117
+
118
+ result = out_result_count.read_int.times.map do |index|
119
+ index_ptr = ptr + (index * FFI::Pointer::SIZE)
120
+ struct = Api::PROJ_CRS_INFO.new(index_ptr.read_pointer)
121
+ CrsInfo.from_proj_crs_info(struct)
122
+ end
123
+
124
+ Api.proj_crs_info_list_destroy(ptr)
125
+ result
126
+ end
127
+
128
+ # Returns information about a Grid from the database
129
+ #
130
+ # @see https://proj.org/development/reference/functions.html#c.proj_grid_get_info_from_database
131
+ #
132
+ # @param name [String] The name of the grid
133
+ #
134
+ # @return [Grid]
135
+ def grid(name)
136
+ out_full_name = FFI::MemoryPointer.new(:string)
137
+ out_package_name = FFI::MemoryPointer.new(:string)
138
+ out_url = FFI::MemoryPointer.new(:string)
139
+ out_downloadable = FFI::MemoryPointer.new(:int)
140
+ out_open_license = FFI::MemoryPointer.new(:int)
141
+ out_available = FFI::MemoryPointer.new(:int)
142
+
143
+ result = Api.proj_grid_get_info_from_database(self.context, name,
144
+ out_full_name, out_package_name, out_url,
145
+ out_downloadable, out_open_license, out_available)
146
+
147
+ if result == 1
148
+ full_name_ptr = out_full_name.read_pointer
149
+ package_name_ptr = out_package_name.read_pointer
150
+ url_ptr = out_url.read_pointer
151
+
152
+ downloadable_ptr = out_downloadable
153
+ open_license_ptr = out_open_license
154
+ available_ptr = out_available
155
+
156
+ full_name = full_name_ptr.read_string_to_null
157
+ package_name = package_name_ptr.read_string_to_null
158
+ url = url_ptr.read_string_to_null
159
+
160
+ downloadable = downloadable_ptr.read_int == 1 ? true : false
161
+ open_license = open_license_ptr.read_int == 1 ? true : false
162
+ available = available_ptr.read_int == 1 ? true : false
163
+
164
+ Grid.new(name, self.context,
165
+ full_name: full_name, package_name: package_name,
166
+ url: url ? URI(url) : nil,
167
+ downloadable: downloadable, open_license: open_license, available: available)
168
+ else
169
+ Error.check_context(self.context)
170
+ end
171
+ end
172
+
173
+ # Returns a list of geoid models available
174
+ #
175
+ # @see https://proj.org/development/reference/functions.html#c.proj_get_geoid_models_from_database
176
+ #
177
+ # @param authority [String] Authority name into which the object will be inserted. Must not be nil
178
+ # @param code [Integer] Code with which the object will be inserted.Must not be nil
179
+ #
180
+ # @return [Strings] List of insert statements
181
+ def geoid_models(authority, code)
182
+ ptr = Api.proj_get_geoid_models_from_database(self.context, authority, code, nil)
183
+ Strings.new(ptr)
184
+ end
185
+
186
+ # Returns a list of celestial bodies from the database
187
+ #
188
+ # @see https://proj.org/development/reference/functions.html#c.proj_get_celestial_body_list_from_database
189
+ #
190
+ # @param authority [String] Authority name, used to restrict the search. Set to nil for all authorities.
191
+ #
192
+ # @return [Array<CelestialBody>] List of insert statements
193
+ def celestial_bodies(authority = nil)
194
+ out_result_count = FFI::MemoryPointer.new(:int)
195
+ ptr = Api.proj_get_celestial_body_list_from_database(self.context, authority, out_result_count)
196
+
197
+ body_ptrs = ptr.read_array_of_pointer(out_result_count.read_int)
198
+ result = body_ptrs.map do |body_ptr|
199
+ # First read the pointer to a structure
200
+ struct = Api::ProjCelestialBodyInfo.new(body_ptr)
201
+
202
+ # Now map this to a Ruby Struct
203
+ CelestialBody.new(struct[:auth_name], struct[:name])
204
+ end
205
+
206
+ Api.proj_celestial_body_list_destroy(ptr)
207
+
208
+ result
209
+ end
210
+
211
+ # Return the name of the celestial body of the specified object.
212
+ #
213
+ # @see https://proj.org/development/reference/functions.html#c.proj_get_celestial_body_name
214
+ #
215
+ # @param object [PjObject] Object of type CRS, Datum or Ellipsoid. Must not be nil.
216
+ #
217
+ # @return [String] The name of the celestial body or nil
218
+ def celestial_body_name(object)
219
+ Api.proj_get_celestial_body_name(self.context, object)
220
+ end
221
+
222
+ # Suggests a database code for the specified object.
223
+ #
224
+ # @see https://proj.org/development/reference/functions.html#c.proj_suggests_code_for
225
+ #
226
+ # @param object [PjObject] Object for which to suggest a code.
227
+ # @param authority [String] Authority name into which the object will be inserted.
228
+ # @param numeric_code [Boolean] Whether the code should be numeric, or derived from the object name.
229
+ #
230
+ # @return [String] The suggested code
231
+ def suggest_code_for(object, authority, numeric_code)
232
+ ptr = Api.proj_suggests_code_for(self.context, object, authority, numeric_code ? 1 : 0, nil)
233
+ result = ptr.read_string_to_null
234
+ Api.proj_string_destroy(ptr)
235
+ result
236
+ end
237
+
238
+ # Returns a list of units from the database
239
+ #
240
+ # @see https://proj.org/development/reference/functions.html#c.proj_get_units_from_database
241
+ #
242
+ # @param auth_name [String] Authority name, used to restrict the search. Or nil for all authorities.
243
+ # @param category [String] Filter by category, if this parameter is not nil. Category is one of "linear", "linear_per_time", "angular", "angular_per_time", "scale", "scale_per_time" or "time
244
+ # @param allow_deprecated [Boolean] Whether deprecated units should also be returned. Default false.
245
+ #
246
+ # @return [Array<Unit>] Array of units
247
+ def units(auth_name: nil, category: nil, allow_deprecated: false)
248
+ # Create pointer to read the count output parameter
249
+ out_result_count = FFI::MemoryPointer.new(:int)
250
+
251
+ # Result is an array of pointers to structures
252
+ pp_units = Api.proj_get_units_from_database(Context.current, auth_name, category, allow_deprecated ? 1 : 0, out_result_count)
253
+ count = out_result_count.read(:int)
254
+ array_p_units = pp_units.read_array_of_pointer(count)
255
+
256
+ result = Array.new(count)
257
+ count.times do |i|
258
+ unit_info = Api::PROJ_UNIT_INFO.new(array_p_units[i])
259
+
260
+ result[i] = Unit.new(unit_info[:auth_name],
261
+ unit_info[:code],
262
+ unit_info[:name],
263
+ unit_info[:category],
264
+ unit_info[:conv_factor],
265
+ unit_info[:proj_short_name],
266
+ unit_info[:deprecated])
267
+ end
268
+
269
+ Api.proj_unit_list_destroy(pp_units)
270
+
271
+ result
272
+ end
273
+
274
+ # Returns information for a unit of measure from a database lookup
275
+ #
276
+ # @see https://proj.org/development/reference/functions.html#c.proj_uom_get_info_from_database
277
+ #
278
+ # @param auth_name [String] Authority name
279
+ # @param code [String] Unit of measure code
280
+ #
281
+ # @return [Unit] Unit
282
+ def unit(auth_name, code)
283
+ out_name = FFI::MemoryPointer.new(:string)
284
+ out_conv_factor = FFI::MemoryPointer.new(:double)
285
+ out_category = FFI::MemoryPointer.new(:string)
286
+
287
+ result = Api.proj_uom_get_info_from_database(self.context, auth_name, code,
288
+ out_name, out_conv_factor , out_category)
289
+
290
+ if result == 1
291
+ name_ptr = out_name.read_pointer
292
+ conv_factor_ptr = out_conv_factor
293
+ category_ptr = out_category.read_pointer
294
+
295
+ name = name_ptr.read_string_to_null
296
+ conv_factor = conv_factor_ptr.read_double
297
+ category = category_ptr.read_string_to_null
298
+
299
+ Unit.new(auth_name, code, name, category, conv_factor, nil, false)
300
+ else
301
+ Error.check_context(self.context)
302
+ end
303
+ end
304
+ end
305
+ end
data/lib/proj/datum.rb ADDED
@@ -0,0 +1,32 @@
1
+ module Proj
2
+ class Datum < PjObject
3
+ # Returns the frame reference epoch of a dynamic geodetic or vertical reference frame
4
+ #
5
+ # @see https://proj.org/development/reference/functions.html#c.proj_dynamic_datum_get_frame_reference_epoch
6
+ #
7
+ # @return [Double] The frame reference epoch as decimal year, or -1 in case of error.
8
+ def frame_reference_epoch
9
+ Api.proj_dynamic_datum_get_frame_reference_epoch(self.context, self)
10
+ end
11
+
12
+ # Return the ellipsoid
13
+ #
14
+ # @see https://proj.org/development/reference/functions.html#c.proj_get_ellipsoid
15
+ #
16
+ # @return [PjObject]
17
+ def ellipsoid
18
+ ptr = Api.proj_get_ellipsoid(self.context, self)
19
+ self.class.create_object(ptr, self.context)
20
+ end
21
+
22
+ # Returns the prime meridian
23
+ #
24
+ # @see https://proj.org/development/reference/functions.html#c.proj_get_prime_meridian
25
+ #
26
+ # @return [PjObject]
27
+ def prime_meridian
28
+ ptr = Api.proj_get_prime_meridian(self.context, self)
29
+ self.class.create_object(ptr, self.context)
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,34 @@
1
+ module Proj
2
+ class DatumEnsemble < PjObject
3
+
4
+ # Returns the number of members of a datum ensemble
5
+ #
6
+ # @see https://proj.org/development/reference/functions.html#c.proj_datum_ensemble_get_member_count
7
+ #
8
+ # @return [Integer]
9
+ def count
10
+ Api.proj_datum_ensemble_get_member_count(self.context, self)
11
+ end
12
+
13
+ # Returns a member from a datum ensemble.
14
+ #
15
+ # @see https://proj.org/development/reference/functions.html#c.proj_datum_ensemble_get_member
16
+ #
17
+ # @param index [Integer] Index of the datum member to extract. Should be between 0 and DatumEnsembel#count - 1.
18
+ #
19
+ # @return [Integer]
20
+ def [](index)
21
+ ptr = Api.proj_datum_ensemble_get_member(self.context, self, index)
22
+ self.class.create_object(ptr, self.context)
23
+ end
24
+
25
+ # Returns the positional accuracy of the datum ensemble
26
+ #
27
+ # @see https://proj.org/development/reference/functions.html#c.proj_datum_ensemble_get_accuracy
28
+ #
29
+ # @return [Float] The data ensemble accuracy or -1 in case of error
30
+ def accuracy
31
+ Api.proj_datum_ensemble_get_accuracy(self.context, self)
32
+ end
33
+ end
34
+ end
@@ -1,42 +1,78 @@
1
- module Proj
2
- class Ellipsoid
3
- attr_reader :id, :major, :ell, :name
4
-
5
- def self.list
6
- pointer_to_array = FFI::Pointer.new(Api::PJ_ELLPS, Api.proj_list_ellps)
7
- result = Array.new
8
- 0.step do |i|
9
- ellipse_info = Api::PJ_ELLPS.new(pointer_to_array[i])
10
- break result if ellipse_info[:id].nil?
11
- result << self.new(ellipse_info[:id], ellipse_info[:major], ellipse_info[:ell], ellipse_info[:name])
12
- end
13
- end
14
-
15
- def self.get(id)
16
- self.list.find {|ellipsoid| ellipsoid.id == id}
17
- end
18
-
19
- def initialize(id, major, ell, name)
20
- @id = id
21
- @major = major
22
- @ell = ell
23
- @name = name
24
- end
25
-
26
- def <=>(other)
27
- self.id <=> other.id
28
- end
29
-
30
- def ==(other)
31
- self.id == other.id
32
- end
33
-
34
- def to_s
35
- self.id
36
- end
37
-
38
- def inspect
39
- "#<#{self.class} id=\"#{id}\", major=\"#{major}\", ell=\"#{ell}\", name=\"#{name}\">"
40
- end
41
- end
1
+ module Proj
2
+ class Ellipsoid < PjObject
3
+ # Returns a list of ellipsoids that are built into Proj. A more comprehensive
4
+ # list is stored in the Proj database and can be queried via PjObject#create_from_database
5
+ def self.built_in
6
+ pointer_to_array = FFI::Pointer.new(Api::PJ_ELLPS, Api.proj_list_ellps)
7
+
8
+ result = Array.new
9
+ 0.step do |i|
10
+ pj_ellps = Api::PJ_ELLPS.new(pointer_to_array[i])
11
+ break result if pj_ellps[:id].nil?
12
+ result << pj_ellps
13
+ end
14
+ result
15
+ end
16
+
17
+ # Returns ellipsoid parameters
18
+ #
19
+ # @see https://proj.org/development/reference/functions.html#c.proj_ellipsoid_get_parameters
20
+ #
21
+ # @return [Hash] Hash of ellipsoid parameters. Axes are in meters
22
+ def parameters
23
+ @parameters ||= begin
24
+ out_semi_major_metre = FFI::MemoryPointer.new(:double)
25
+ out_semi_minor_metre = FFI::MemoryPointer.new(:double)
26
+ out_is_semi_minor_computed = FFI::MemoryPointer.new(:int)
27
+ out_inv_flattening = FFI::MemoryPointer.new(:double)
28
+
29
+ result = Api.proj_ellipsoid_get_parameters(self.context, self, out_semi_major_metre, out_semi_minor_metre, out_is_semi_minor_computed, out_inv_flattening)
30
+
31
+ if result != 1
32
+ Error.check_object(self)
33
+ end
34
+
35
+ {semi_major_axis: out_semi_major_metre.read_double,
36
+ semi_minor_axis: out_semi_minor_metre.read_double,
37
+ semi_minor_axis_computed: out_is_semi_minor_computed.read_int == 1 ? true : false,
38
+ inverse_flattening: out_inv_flattening.null? ? nil : out_inv_flattening.read_double}
39
+ end
40
+ end
41
+
42
+ # Returns the semi-major axis in meters
43
+ #
44
+ # @see https://proj.org/development/reference/functions.html#c.proj_ellipsoid_get_parameters
45
+ #
46
+ # @return [Double]
47
+ def semi_major_axis
48
+ self.parameters[:semi_major_axis]
49
+ end
50
+
51
+ # Returns the semi-minor axis in meters
52
+ #
53
+ # @see https://proj.org/development/reference/functions.html#c.proj_ellipsoid_get_parameters
54
+ #
55
+ # @return [Double]
56
+ def semi_minor_axis
57
+ self.parameters[:semi_minor_axis]
58
+ end
59
+
60
+ # Returns whether the semi-minor axis is computed
61
+ #
62
+ # @see https://proj.org/development/reference/functions.html#c.proj_ellipsoid_get_parameters
63
+ #
64
+ # @return [Boolean]
65
+ def semi_minor_axis_computed
66
+ self.parameters[:semi_minor_axis_computed]
67
+ end
68
+
69
+ # Returns the inverse flattening value
70
+ #
71
+ # @see https://proj.org/development/reference/functions.html#c.proj_ellipsoid_get_parameters
72
+ #
73
+ # @return [Double]
74
+ def inverse_flattening
75
+ self.parameters[:inverse_flattening]
76
+ end
77
+ end
42
78
  end
data/lib/proj/error.rb CHANGED
@@ -1,18 +1,71 @@
1
1
  module Proj
2
+ # Represents error thrown by Proj
3
+ #
4
+ # @see https://proj.org/development/errorhandling.html
2
5
  class Error < StandardError
3
- def self.check(errno=nil)
4
- unless errno
5
- errno = Context.current.errno
6
+ # Error codes typically related to coordinate operation initialization
7
+ PROJ_ERR_INVALID_OP = 1024 # Other/unspecified error related to coordinate operation initialization
8
+ PROJ_ERR_INVALID_OP_WRONG_SYNTAX = PROJ_ERR_INVALID_OP + 1 # Invalid pipeline structure, missing +proj argument, etc
9
+ PROJ_ERR_INVALID_OP_MISSING_ARG = PROJ_ERR_INVALID_OP + 2 # Missing required operation parameter
10
+ PROJ_ERR_INVALID_OP_ILLEGAL_ARG_VALUE = PROJ_ERR_INVALID_OP + 3 # One of the operation parameter has an illegal value
11
+ PROJ_ERR_INVALID_OP_MUTUALLY_EXCLUSIVE_ARGS = PROJ_ERR_INVALID_OP + 4 # Mutually exclusive arguments
12
+ PROJ_ERR_INVALID_OP_FILE_NOT_FOUND_OR_INVALID = PROJ_ERR_INVALID_OP + 5 # File not found (particular case of PROJ_ERR_INVALID_OP_ILLEGAL_ARG_VALUE)
13
+
14
+ # Error codes related to transformation on a specific coordinate
15
+ PROJ_ERR_COORD_TRANSFM = 2048 # Other error related to coordinate transformation
16
+ PROJ_ERR_COORD_TRANSFM_INVALID_COORD = PROJ_ERR_COORD_TRANSFM + 1 # For e.g lat > 90deg
17
+ PROJ_ERR_COORD_TRANSFM_OUTSIDE_PROJECTION_DOMAIN = PROJ_ERR_COORD_TRANSFM + 2 # Coordinate is outside of the projection domain. e.g approximate mercator with |longitude - lon_0| > 90deg, or iterative convergence method failed
18
+ PROJ_ERR_COORD_TRANSFM_NO_OPERATION = PROJ_ERR_COORD_TRANSFM + 3 # No operation found, e.g if no match the required accuracy, or if ballpark transformations were asked to not be used and they would be only such candidate
19
+ PROJ_ERR_COORD_TRANSFM_OUTSIDE_GRID = PROJ_ERR_COORD_TRANSFM + 4 # Point to transform falls outside grid or subgrid
20
+ PROJ_ERR_COORD_TRANSFM_GRID_AT_NODATA = PROJ_ERR_COORD_TRANSFM + 5 # Point to transform falls in a grid cell that evaluates to nodata
21
+
22
+ # Other type of errors
23
+ PROJ_ERR_OTHER = 4096
24
+ PROJ_ERR_OTHER_API_MISUSE = PROJ_ERR_OTHER + 1 # Error related to a misuse of PROJ API
25
+ PROJ_ERR_OTHER_NO_INVERSE_OP = PROJ_ERR_OTHER + 2 # No inverse method available
26
+ PROJ_ERR_OTHER_NETWORK_ERROR = PROJ_ERR_OTHER + 3 # Failure when accessing a network resource
27
+
28
+ # Check the context to see if an error occurred. If an error has happened will
29
+ # raise an exception.
30
+ def self.check_context(context)
31
+ unless context.errno == 0
32
+ # raise(self, "#{self.category(context.errno)}: #{self.message(context)}")
33
+ raise(self, self.message(context, context.errno))
6
34
  end
35
+ end
7
36
 
8
- if errno != 0
9
- message = if Api.method_defined?(:proj_errno_string)
10
- Api.proj_errno_string(errno)
11
- else
12
- Api.pj_strerrno(errno)
13
- end
37
+ def self.check_object(pj_object)
38
+ # It would be nice if Proj exposed the proj_context_errno_set method so
39
+ # we don't need a pj_object
40
+ context = pj_object.context
41
+ unless context.errno == 0
42
+ message = self.message(context, context.errno)
43
+ Api.proj_errno_reset(pj_object)
14
44
  raise(self, message)
15
45
  end
16
46
  end
47
+
48
+ # Returns the current error-state of the context. An non-zero error codes indicates an error.
49
+ #
50
+ # See https://proj.org/development/reference/functions.html#c.proj_errno_string proj_errno_string
51
+ #
52
+ # @param context [Context] The context the error occurred in
53
+ # @param errno [Integer] The error number
54
+ #
55
+ # return [String]
56
+ def self.message(context, errno)
57
+ if Api.method_defined?(:proj_context_errno_string)
58
+ Api.proj_context_errno_string(context, errno)
59
+ elsif Api.method_defined?(:proj_errno_string)
60
+ Api.proj_errno_string(errno)
61
+ end
62
+ end
63
+
64
+ # Converts an errno to a error category
65
+ def self.category(errno)
66
+ self.constants.find do |constant|
67
+ self.const_get(constant) == errno
68
+ end
69
+ end
17
70
  end
18
71
  end