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
@@ -0,0 +1,46 @@
1
+ module Proj
2
+ class Session
3
+ attr_reader :context
4
+
5
+ def self.finalize(context, pointer)
6
+ proc do
7
+ Api.proj_insert_object_session_destroy(context, pointer)
8
+ end
9
+ end
10
+
11
+ def initialize(context = nil)
12
+ @context = context || Context.current
13
+ @pointer = Api.proj_insert_object_session_create(@context)
14
+ ObjectSpace.define_finalizer(self, self.class.finalize(@context, @pointer))
15
+ end
16
+
17
+ def to_ptr
18
+ @pointer
19
+ end
20
+
21
+ # Returns SQL statements needed to insert the passed object into the database.
22
+ #
23
+ # @param object [PjObject] - The object to insert into the database. Currently only PrimeMeridian, Ellipsoid, Datum, GeodeticCRS, ProjectedCRS, VerticalCRS, CompoundCRS or BoundCRS are supported.
24
+ # @param authority [String] - Authority name into which the object will be inserted. Must not be nil
25
+ # @param code [Integer] - Code with which the object will be inserted.Must not be nil
26
+ # @param numeric_codes [Boolean] - Whether intermediate objects that can be created should use numeric codes (true), or may be alphanumeric (false)
27
+ # @param allowed_authorities [Array[String]] - Authorities to which intermediate objects are allowed to refer to. "authority" will be implicitly added to it.
28
+ #
29
+ # @return [Strings] - List of insert statements
30
+ def get_insert_statements(object, authority, code, numeric_codes = false, allowed_authorities = nil)
31
+ allowed_authorities_ptr = if allowed_authorities
32
+ # Add extra item at end for null pointer
33
+ pointer = FFI::MemoryPointer.new(:pointer, allowed_authorities.size + 1)
34
+
35
+ # Convert strings to C chars
36
+ allowed_authorities.each_with_index do |authority, i|
37
+ pointer.put_pointer(i, FFI::MemoryPointer.from_string(authority))
38
+ end
39
+ pointer
40
+ end
41
+
42
+ strings_ptr = Api.proj_get_insert_statements(self.context, self, object, authority, code, numeric_codes ? 1 : 0, allowed_authorities_ptr, nil)
43
+ Strings.new(strings_ptr)
44
+ end
45
+ end
46
+ end
@@ -0,0 +1,32 @@
1
+ # encoding: UTF-8
2
+ require 'forwardable'
3
+
4
+ module Proj
5
+ class Strings
6
+ include Enumerable
7
+ extend Forwardable
8
+
9
+ attr_reader :strings
10
+
11
+ def initialize(pointer)
12
+ @strings = Array.new
13
+ read_strings(pointer)
14
+ Api.proj_string_list_destroy(pointer)
15
+ end
16
+
17
+ private
18
+
19
+ def read_strings(pointer)
20
+ unless pointer.null?
21
+ loop do
22
+ string_ptr = pointer.read_pointer
23
+ break if string_ptr.null?
24
+ @strings << string_ptr.read_string_to_null
25
+ pointer += FFI::Pointer::SIZE
26
+ end
27
+ end
28
+ end
29
+
30
+ def_delegators :@strings, :[], :count, :each, :empty?, :join, :size, :length, :to_s
31
+ end
32
+ end
@@ -1,61 +1,102 @@
1
- module Proj
2
- # Transformation objects convert {Coordinate Coordinates} from one {Crs} to another.
3
- class Transformation < PjObject
4
- # Transforms a {Coordinate} from the source {Crs} to the target {Crs}. Coordinates should be expressed in
5
- # the units and axis order of the definition of the source CRS. The returned transformed coordinate will
6
- # be in the units and axis order of the definition of the target CRS.
7
- #
8
- # For most geographic Crses, the units will be in degrees. For geographic CRS defined by the EPSG authority,
9
- # the order of coordinates is latitude first, longitude second. When using a PROJ initialization string,
10
- # on contrary, the order will be longitude first, latitude second.
11
- #
12
- # For projected CRS, the units may vary (metre, us-foot, etc..).
13
- #
14
- # For projected CRS defined by the EPSG authority, and with EAST / NORTH directions, the axis order might be
15
- # easting first, northing second, or the reverse. When using a PROJ string, the order will be
16
- # easting first, northing second, except if the +axis parameter modifies it.
17
- #
18
- # @param source [Crs | String] - The source Crs. See the Crs documentation for the string format
19
- # @param target [Crs | String] - The target Crs. See the Crs documentation for the string format
20
- # @param context [Context]
21
- def initialize(source, target, context=nil)
22
- pointer = if source.is_a?(Crs) && target.is_a?(Crs)
23
- if Api.method_defined?(:proj_create_crs_to_crs_from_pj)
24
- Api.proj_create_crs_to_crs_from_pj(context, source, target, nil, nil)
25
- else
26
- Api.proj_create_crs_to_crs(context, source.definition, target.definition, nil)
27
- end
28
- else
29
- Api.proj_create_crs_to_crs(context, source, target, nil)
30
- end
31
-
32
- if pointer.null?
33
- Error.check
34
- end
35
-
36
- super(pointer, context)
37
- end
38
-
39
- # Transforms a {Coordinate} from the source {Crs} to the target {Crs}. Coordinates should be expressed in
40
- # the units and axis order of the definition of the source CRS. The returned transformed coordinate will
41
- # be in the units and axis order of the definition of the target CRS.
42
- #
43
- # @param coord [Coordinate]
44
- # @return [Coordinate]
45
- def forward(coord)
46
- struct = Api.proj_trans(self, :PJ_FWD, coord)
47
- Coordinate.from_coord(struct)
48
- end
49
-
50
- # Transforms a {Coordinate} from the target {Crs} to the source {Crs}. Coordinates should be expressed in
51
- # the units and axis order of the definition of the source CRS. The returned transformed coordinate will
52
- # be in the units and axis order of the definition of the target CRS.
53
- #
54
- # @param coord [Coordinate]
55
- # @return [Coordinate]
56
- def inverse(coord)
57
- struct = Api.proj_trans(self, :PJ_INV, coord)
58
- Coordinate.from_coord(struct)
59
- end
60
- end
1
+ module Proj
2
+ # Transformations are {CoordinateOperationMix coordinate operations} that
3
+ # convert {Coordinate coordinates} from one {Crs} to another.
4
+ # In Proj they are defined as operations that exert a change in reference frame
5
+ # while {Conversion conversions } do not.
6
+ class Transformation < PjObject
7
+ include CoordinateOperationMixin
8
+
9
+ # Create a Transformation
10
+ #
11
+ # @param context [Context] Context
12
+ # @param name [String] Name of the transformation. Default is nil.
13
+ # @param auth_name [String] Transformation authority name. Default is nil.
14
+ # @param code [String] Transformation code. Default is nil.
15
+ # @param source_crs [CoordinateSystem] Source CRS
16
+ # @param target_crs [CoordinateSystem] Target CRS
17
+ # @param interpolation_crs [CoordinateSystem] Interpolation. Default is nil
18
+ # @param method_name [String] Method name. Default is nil.
19
+ # @param method_auth_name [String] Method authority name. Default is nil.
20
+ # @param method_code [String] Method code. Default is nil.
21
+ # @param params [Array<Parameter>] Parameter descriptions
22
+ # @param accuracy [Double] Accuracy of the transformation in meters. A negative value means unknown.
23
+ #
24
+ # @return [Transformation]
25
+ def self.create(context, name: nil, auth_name: nil, code: nil,
26
+ source_crs:, target_crs:, interpolation_crs: nil,
27
+ method_name: nil, method_auth_name: nil, method_code: nil,
28
+ params:, accuracy:)
29
+
30
+ params_ptr = FFI::MemoryPointer.new(Api::PJ_PARAM_DESCRIPTION, params.size)
31
+ params.each_with_index do |param, i|
32
+ param_description_target = Api::PJ_PARAM_DESCRIPTION.new(params_ptr[i])
33
+ param_description_source = param.to_description
34
+ param_description_target.to_ptr.__copy_from__(param_description_source.to_ptr, Api::PJ_PARAM_DESCRIPTION.size)
35
+ end
36
+
37
+ ptr = Api.proj_create_transformation(context, name, auth_name, code,
38
+ source_crs, target_crs, interpolation_crs,
39
+ method_name, method_auth_name, method_code,
40
+ params.count, params_ptr, accuracy)
41
+ self.create_object(ptr, context)
42
+ end
43
+
44
+ # Transforms a {Coordinate} from the source {Crs} to the target {Crs}. Coordinates should be expressed in
45
+ # the units and axis order of the definition of the source CRS. The returned transformed coordinate will
46
+ # be in the units and axis order of the definition of the target CRS.
47
+ #
48
+ # For most geographic Crses, the units will be in degrees. For geographic CRS defined by the EPSG authority,
49
+ # the order of coordinates is latitude first, longitude second. When using a PROJ initialization string,
50
+ # on contrary, the order will be longitude first, latitude second.
51
+ #
52
+ # For projected CRS, the units may vary (metre, us-foot, etc..).
53
+ #
54
+ # For projected CRS defined by the EPSG authority, and with EAST / NORTH directions, the axis order might be
55
+ # easting first, northing second, or the reverse. When using a PROJ string, the order will be
56
+ # easting first, northing second, except if the +axis parameter modifies it.
57
+ #
58
+ # @see https://proj.org/development/reference/functions.html#c.proj_create_crs_to_crs_from_pj
59
+ # @see https://proj.org/development/reference/functions.html#c.proj_create_crs_to_crs proj_create_crs_to_crs
60
+ #
61
+ # @param source [Crs | String] The source Crs. See the Crs documentation for the string format
62
+ # @param target [Crs | String] The target Crs. See the Crs documentation for the string format
63
+ # @param area [Area] If an area is specified a more accurate transformation between two given systems can be chosen
64
+ # @param context [Context]
65
+ # @param authority [String] Restricts the authority of coordinate operations looked up in the database
66
+ # @param accuracy [Float] Sets the minimum desired accuracy (in metres) of the candidate coordinate operations
67
+ # @param allow_ballpark [Boolean] Set to false to disallow the use of Ballpark transformation in the candidate coordinate operations.
68
+ # @param only_best [Boolean] Set to true to cause PROJ to error out if the best transformation cannot be used. Requires Proj 9.2 and higher
69
+ #
70
+ # @return [Transformation] A new transformation
71
+ def initialize(source, target, context=nil,
72
+ area: nil, authority: nil, accuracy: nil, allow_ballpark: nil, only_best: nil, force_over: nil)
73
+
74
+ context ||= Context.current
75
+
76
+ options = {"AUTHORITY": authority,
77
+ "ACCURACY": accuracy.nil? ? nil : accuracy.to_s,
78
+ "ALLOW_BALLPARK": allow_ballpark.nil? ? nil : (allow_ballpark ? "YES" : "NO"),
79
+ "ONLY_BEST": only_best.nil? ? nil : (only_best ? "YES" : "NO"),
80
+ "FORCE_OVER": force_over.nil? ? nil : (force_over ? "YES" : "NO")}
81
+ options_ptr = create_options_pointer(options)
82
+
83
+ ptr = if source.is_a?(Crs) && target.is_a?(Crs)
84
+ if Api.method_defined?(:proj_create_crs_to_crs_from_pj)
85
+ Api.proj_create_crs_to_crs_from_pj(context, source, target, area, options_ptr)
86
+ else
87
+ Api.proj_create_crs_to_crs(context, source.definition, target.definition, area)
88
+ end
89
+ else
90
+ Api.proj_create_crs_to_crs(context, source, target, nil)
91
+ end
92
+
93
+ if ptr.null?
94
+ Error.check_context(context)
95
+ # If that does not raise an error then no operation was found
96
+ raise(Error, "No operation found matching criteria")
97
+ end
98
+
99
+ super(ptr, context)
100
+ end
101
+ end
61
102
  end
data/lib/proj/unit.rb CHANGED
@@ -1,54 +1,109 @@
1
- module Proj
2
- class Unit
3
- attr_reader :id, :to_meter, :factor, :name
4
-
5
- def self.list
6
- # First get linear units
7
- pointer_to_array = FFI::Pointer.new(Api::PJ_UNITS, Api.proj_list_units)
8
- result = Array.new
9
- 0.step do |i|
10
- ellipse_info = Api::PJ_UNITS.new(pointer_to_array[i])
11
- break if ellipse_info[:id].nil?
12
- result << self.new(ellipse_info[:id], ellipse_info[:to_meter], ellipse_info[:factor], ellipse_info[:name])
13
- end
14
-
15
- # Now get angular linear units
16
- if Api.method_defined?(:proj_list_angular_units)
17
- pointer_to_array = FFI::Pointer.new(Api::PJ_UNITS, Api.proj_list_angular_units)
18
- 0.step do |i|
19
- ellipse_info = Api::PJ_UNITS.new(pointer_to_array[i])
20
- break result if ellipse_info[:id].nil?
21
- result << self.new(ellipse_info[:id], ellipse_info[:to_meter], ellipse_info[:factor], ellipse_info[:name])
22
- end
23
- end
24
- result
25
- end
26
-
27
- def self.get(id)
28
- self.list.find {|ellipsoid| ellipsoid.id == id}
29
- end
30
-
31
- def initialize(id, to_meter, factor, name)
32
- @id = id
33
- @to_meter = to_meter
34
- @factor = factor
35
- @name = name
36
- end
37
-
38
- def <=>(other)
39
- self.id <=> other.id
40
- end
41
-
42
- def ==(other)
43
- self.id == other.id
44
- end
45
-
46
- def to_s
47
- self.id
48
- end
49
-
50
- def inspect
51
- "#<#{self.class} id=\"#{id}\", to_meter=\"#{to_meter}\", factor=\"#{factor}\", name=\"#{name}\">"
52
- end
53
- end
1
+ module Proj
2
+ class Unit
3
+ # @!attribute [r] auth_name
4
+ # @return [String] Authority name
5
+ # @!attribute [r] code
6
+ # @return [String] Object code
7
+ # @!attribute [r] name
8
+ # @return [String] Object name. For example "metre", "US survey foot", etc
9
+ # @!attribute [r] category
10
+ # @return [String] Category of the unit: one of "linear", "linear_per_time", "angular", "angular_per_time", "scale", "scale_per_time" or "time"
11
+ # @!attribute [r] conv_factor
12
+ # @return [String] Conversion factor to apply to transform from that unit to the corresponding SI unit (metre for "linear", radian for "angular", etc.). It might be 0 in some cases to indicate no known conversion factor
13
+ # @!attribute [r] proj_short_name
14
+ # @return [String] PROJ short name, like "m", "ft", "us-ft", etc... Might be nil
15
+ # @!attribute [r] deprecated
16
+ # @return [Boolean] Whether the object is deprecated
17
+ attr_reader :auth_name, :code, :name, :category, :conv_factor, :proj_short_name, :deprecated
18
+
19
+ # Returns a list of built in Units. This is deprecated. Use Database#units instead
20
+ def self.built_in(auth_name: nil, category: nil, allow_deprecated: false)
21
+ # First get linear units
22
+ pointer_to_array = FFI::Pointer.new(Api::PJ_UNITS, Api.proj_list_units)
23
+ result = Array.new
24
+ 0.step do |i|
25
+ unit_info = Api::PJ_UNITS.new(pointer_to_array[i])
26
+ break if unit_info[:id].nil?
27
+ result << self.new('PROJ', unit_info[:id], unit_info[:name],
28
+ 'length', unit_info[:factor], unit_info[:id], false)
29
+ end
30
+
31
+ # Now get angular linear units
32
+ if Api.method_defined?(:proj_list_angular_units)
33
+ pointer_to_array = FFI::Pointer.new(Api::PJ_UNITS, Api.proj_list_angular_units)
34
+ 0.step do |i|
35
+ unit_info = Api::PJ_UNITS.new(pointer_to_array[i])
36
+ break result if unit_info[:id].nil?
37
+ result << self.new('PROJ', unit_info[:id], unit_info[:name],
38
+ 'angular', unit_info[:factor], unit_info[:id], false)
39
+ end
40
+ end
41
+
42
+ if auth_name
43
+ result = result.find_all {|unit_info| unit_info.auth_name == auth_name}
44
+ end
45
+
46
+ if category
47
+ result = result.find_all {|unit_info| unit_info.category == category}
48
+ end
49
+ result
50
+ end
51
+
52
+ # Create a new Unit
53
+ #
54
+ # @param auth_name [String] Authority name
55
+ # @param code [String] Object code
56
+ # @param name [String] Object name. For example "metre", "US survey foot", etc
57
+ # @param category [String] Category of the unit: one of "linear", "linear_per_time", "angular", "angular_per_time", "scale", "scale_per_time" or "time"
58
+ # @param conv_factor [String] Conversion factor to apply to transform from that unit to the corresponding SI unit (metre for "linear", radian for "angular", etc.). It might be 0 in some cases to indicate no known conversion factor
59
+ # @param proj_short_name [String] PROJ short name, like "m", "ft", "us-ft", etc... Might be nil
60
+ # @param deprecated [Boolean] Whether the object is deprecated
61
+ #
62
+ # @return [Unit]
63
+ def initialize(auth_name, code, name, category, conv_factor, proj_short_name, deprecated)
64
+ @auth_name = auth_name
65
+ @code = code
66
+ @name = name
67
+ @category = category
68
+ @conv_factor = conv_factor
69
+ @proj_short_name = proj_short_name
70
+ @deprecated = deprecated
71
+ end
72
+
73
+ def <=>(other)
74
+ self.name <=> other.name
75
+ end
76
+
77
+ def ==(other)
78
+ self.auth_name == other.auth_name &&
79
+ self.code == other.code
80
+ end
81
+
82
+ def type
83
+ case self.category
84
+ when "linear"
85
+ :PJ_UT_LINEAR
86
+ when "linear_per_time"
87
+ :PJ_UT_LINEAR
88
+ when "angular"
89
+ :PJ_UT_ANGULAR
90
+ when "angular_per_time"
91
+ :PJ_UT_ANGULAR
92
+ when "scale"
93
+ :PJ_UT_SCALE
94
+ when "scale_per_time"
95
+ :PJ_UT_SCALE
96
+ when "time"
97
+ :PJ_UT_TIME
98
+ end
99
+ end
100
+
101
+ def to_s
102
+ self.name
103
+ end
104
+
105
+ def inspect
106
+ "#<#{self.class} authority=\"#{auth_name}\", code=\"#{code}\", name=\"#{name}\">"
107
+ end
108
+ end
54
109
  end
data/lib/proj.rb CHANGED
@@ -1,31 +1,132 @@
1
1
  # encoding: UTF-8
2
2
 
3
3
  require_relative 'api/api'
4
- require_relative 'proj/config'
4
+
5
+ require_relative 'proj/pj_object'
6
+ require_relative 'proj/pj_objects'
7
+ require_relative 'proj/coordinate_operation_mixin'
8
+ require_relative 'proj/projection'
9
+ require_relative 'proj/conversion'
10
+ require_relative 'proj/crs'
11
+ require_relative 'proj/transformation'
5
12
 
6
13
  require_relative 'proj/area'
14
+ require_relative 'proj/axis_info'
15
+ require_relative 'proj/bounds'
16
+ require_relative 'proj/coordinate_system'
17
+ require_relative 'proj/crs_info'
7
18
  require_relative 'proj/context'
8
19
  require_relative 'proj/coordinate'
20
+ require_relative 'proj/database'
21
+ require_relative 'proj/datum'
22
+ require_relative 'proj/datum_ensemble'
9
23
  require_relative 'proj/ellipsoid'
10
24
  require_relative 'proj/error'
11
- require_relative 'proj/point'
25
+ require_relative 'proj/file_api'
26
+ require_relative 'proj/grid'
27
+ require_relative 'proj/grid_cache'
28
+ require_relative 'proj/grid_info'
29
+ require_relative 'proj/network_api'
30
+ require_relative 'proj/parameter'
31
+ require_relative 'proj/operation'
32
+ require_relative 'proj/operation_factory_context'
33
+ require_relative 'proj/parameters'
12
34
  require_relative 'proj/prime_meridian'
35
+ require_relative 'proj/session'
36
+ require_relative 'proj/strings'
13
37
  require_relative 'proj/unit'
14
38
 
15
- require_relative 'proj/pj_object'
16
- require_relative 'proj/operation'
17
- require_relative 'proj/crs'
18
- require_relative 'proj/projection'
19
- require_relative 'proj/transformation'
20
-
21
39
  module Proj
40
+ # Returns information about the Proj library
41
+ #
42
+ # @see https://proj.org/development/reference/functions.html#c.proj_info proj_info
22
43
  def self.info
23
44
  Api.proj_info
24
45
  end
25
46
 
47
+ # Returns the Proj version
48
+ #
49
+ # @see https://proj.org/development/reference/functions.html#c.proj_info proj_info
26
50
  def self.version
27
51
  self.info[:version]
28
52
  end
53
+
54
+ # Returns default search paths
55
+ #
56
+ # @see https://proj.org/development/reference/functions.html#c.proj_info proj_info
57
+ #
58
+ # @return Array<string> List of search paths
59
+ def self.search_paths
60
+ self.info[:searchpath].split(";")
61
+ end
62
+
63
+ # Return information about the specific init file
64
+ #
65
+ # @see https://proj.org/development/reference/functions.html#c.proj_init_info proj_init_info
66
+ #
67
+ # @param file_name [String] The name of the init file (not the path)
68
+ #
69
+ # @return [PJ_INIT_INFO]
70
+ def self.init_file_info(file_name)
71
+ Api.proj_init_info(file_name)
72
+ end
73
+
74
+ # Converts degrees to radians
75
+ #
76
+ # see https://proj.org/development/reference/functions.html#c.proj_torad proj_torad
77
+ #
78
+ # @param value [Double] Value in degrees to convert
79
+ #
80
+ # @return [Double]
81
+ def self.degrees_to_radians(value)
82
+ Api.proj_torad(value)
83
+ end
84
+
85
+ # Converts radians degrees
86
+ #
87
+ # see https://proj.org/development/reference/functions.html#c.proj_todeg proj_todeg
88
+ #
89
+ # @param value [Double] Value in radians to convert
90
+ #
91
+ # @return [Double]
92
+ def self.radians_to_degrees(value)
93
+ Api.proj_todeg(value)
94
+ end
95
+
96
+ # Convert string of degrees, minutes and seconds to radians.
97
+ #
98
+ # see https://proj.org/development/reference/functions.html#c.proj_dmstor proj_dmstor
99
+ #
100
+ # @param value [String] Value to be converted to radians
101
+ #
102
+ # @return [Double]
103
+ def self.degrees_minutes_seconds_to_radians(value)
104
+ ptr = FFI::MemoryPointer.new(:string)
105
+ Api.proj_dmstor(value, ptr)
106
+ end
107
+
108
+ # Convert radians to a string representation of degrees, minutes and seconds
109
+ #
110
+ # @see https://proj.org/development/reference/functions.html#c.proj_rtodms proj_rtodms
111
+ # @see https://proj.org/development/reference/functions.html#c.proj_rtodms2 proj_rtodms2
112
+ #
113
+ # @param value [Double] Value to be converted in radians
114
+ # @param positive [String] Character denoting positive direction, typically 'N' or 'E'. Default 'N'
115
+ # @param negative [String] Character denoting negative direction, typically 'S' or 'W'. Default 'S'
116
+ #
117
+ # @return [String]
118
+ def self.radians_to_degrees_minutes_seconds(value, positive='N', negative='S')
119
+ ptr = FFI::MemoryPointer.new(:char, 100)
120
+ if Api::PROJ_VERSION < Gem::Version.new('9.2.0')
121
+ Api.proj_rtodms(ptr, value, positive.ord, negative.ord)
122
+ else
123
+ Api.proj_rtodms2(ptr, ptr.size, value, positive.ord, negative.ord)
124
+ end
125
+ ptr.read_string_to_null
126
+ end
29
127
  end
30
128
 
31
- Proj::Config.instance.set_search_paths
129
+ at_exit do
130
+ # Clean up any Proj allocated resources on exit. See https://proj.org/development/reference/functions.html#c.proj_cleanup
131
+ Proj::Api.proj_cleanup
132
+ end
data/proj4rb.gemspec CHANGED
@@ -1,17 +1,17 @@
1
1
  Gem::Specification.new do |spec|
2
2
  spec.name = 'proj4rb'
3
- spec.version = '3.0.0'
4
- spec.summary = 'Ruby bindings for the Proj.4 Carthographic Projection library'
3
+ spec.version = '4.0.0'
4
+ spec.summary = 'Ruby bindings for the Proj coordinate transformation library'
5
5
  spec.description = <<-EOF
6
- Proj4rb is a ruby binding for the Proj.4 Carthographic Projection library, that supports conversions between a very large number of geographic coordinate systems and datumspec.
6
+ Ruby bindings for the Proj coordinate transformation library
7
7
  EOF
8
8
  spec.platform = Gem::Platform::RUBY
9
9
  spec.authors = ['Guilhem Vellut', 'Jochen Topf', 'Charlie Savage']
10
10
  spec.homepage = 'https://github.com/cfis/proj4rb'
11
- spec.required_ruby_version = '>= 2.4.1'
11
+ spec.required_ruby_version = '>= 2.7'
12
12
  spec.license = 'MIT'
13
13
 
14
- spec.requirements << 'Proj (Proj4) Library'
14
+ spec.requirements << 'Proj Library'
15
15
  spec.require_path = 'lib'
16
16
  spec.files = Dir['ChangeLog',
17
17
  'Gemfile',
@@ -3,5 +3,27 @@ require 'minitest/autorun'
3
3
  require 'proj'
4
4
 
5
5
  class AbstractTest < Minitest::Test
6
- end
6
+ def self.proj7?
7
+ Proj::Api::PROJ_VERSION >= Gem::Version.new("7.0.0")
8
+ end
7
9
 
10
+ def self.proj8?
11
+ Proj::Api::PROJ_VERSION >= Gem::Version.new("8.0.0")
12
+ end
13
+
14
+ def self.proj9?
15
+ Proj::Api::PROJ_VERSION >= Gem::Version.new("9.0.0")
16
+ end
17
+
18
+ def proj7?
19
+ self.class.proj7?
20
+ end
21
+
22
+ def proj8?
23
+ self.class.proj8?
24
+ end
25
+
26
+ def proj9?
27
+ self.class.proj9?
28
+ end
29
+ end