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