proj4rb 1.0.0 → 2.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (87) hide show
  1. checksums.yaml +5 -5
  2. data/ChangeLog +46 -0
  3. data/Gemfile +4 -0
  4. data/README.rdoc +158 -148
  5. data/Rakefile +26 -41
  6. data/lib/area.rb +32 -0
  7. data/lib/config.rb +70 -0
  8. data/lib/context.rb +103 -0
  9. data/lib/coordinate.rb +197 -0
  10. data/lib/crs.rb +206 -0
  11. data/lib/ellipsoid.rb +42 -0
  12. data/lib/error.rb +18 -0
  13. data/lib/operation.rb +43 -0
  14. data/lib/pj_object.rb +82 -0
  15. data/lib/point.rb +72 -0
  16. data/lib/prime_meridian.rb +40 -0
  17. data/lib/proj.rb +31 -0
  18. data/lib/proj4.rb +3 -469
  19. data/lib/projection.rb +207 -0
  20. data/lib/transformation.rb +61 -0
  21. data/lib/unit.rb +54 -0
  22. data/proj4rb.gemspec +31 -0
  23. data/test/abstract_test.rb +7 -0
  24. data/test/context_test.rb +82 -0
  25. data/test/coordinate_test.rb +35 -0
  26. data/test/crs_test.rb +373 -0
  27. data/test/ellipsoid_test.rb +34 -0
  28. data/test/operation_test.rb +29 -0
  29. data/test/prime_meridians_test.rb +33 -0
  30. data/test/proj_test.rb +17 -0
  31. data/test/projection_test.rb +224 -0
  32. data/test/transformation_test.rb +68 -0
  33. data/test/unit_test.rb +47 -0
  34. metadata +82 -77
  35. data/data/GL27 +0 -22
  36. data/data/MD +0 -0
  37. data/data/TN +0 -0
  38. data/data/WI +0 -0
  39. data/data/WO +0 -0
  40. data/data/conus +0 -0
  41. data/data/epsg +0 -5443
  42. data/data/epsg-deprecated +0 -2
  43. data/data/esri +0 -5937
  44. data/data/esri.extra +0 -948
  45. data/data/hawaii +0 -0
  46. data/data/nad.lst +0 -142
  47. data/data/nad27 +0 -809
  48. data/data/nad83 +0 -744
  49. data/data/ntv1_can.dat +0 -0
  50. data/data/null +0 -0
  51. data/data/other.extra +0 -49
  52. data/data/proj_def.dat +0 -17
  53. data/data/prvi +0 -0
  54. data/data/stgeorge +0 -0
  55. data/data/stlrnc +0 -0
  56. data/data/stpaul +0 -0
  57. data/data/world +0 -212
  58. data/example/basic.rb +0 -18
  59. data/example/list-datums.rb +0 -17
  60. data/example/list-ellipsoids.rb +0 -17
  61. data/example/list-errors.rb +0 -11
  62. data/example/list-prime-meridians.rb +0 -17
  63. data/example/list-projection-types.rb +0 -17
  64. data/example/list-units.rb +0 -17
  65. data/example/version.rb +0 -8
  66. data/ext/Makefile +0 -238
  67. data/ext/extconf.rb +0 -16
  68. data/ext/mkmf.log +0 -103
  69. data/ext/out.log +0 -0
  70. data/ext/proj4_ruby-x64-mingw32.def +0 -2
  71. data/ext/proj4_ruby.so +0 -0
  72. data/ext/projrb.c +0 -566
  73. data/ext/projrb.o +0 -0
  74. data/ext/vc/proj4_ruby.sln +0 -19
  75. data/ext/vc/proj4_ruby.vcproj +0 -208
  76. data/test/test_constants.rb +0 -18
  77. data/test/test_create_projection.rb +0 -63
  78. data/test/test_datums.rb +0 -45
  79. data/test/test_ellipsoids.rb +0 -46
  80. data/test/test_errors.rb +0 -66
  81. data/test/test_init_projection.rb +0 -109
  82. data/test/test_prime_meridians.rb +0 -45
  83. data/test/test_projection_type.rb +0 -44
  84. data/test/test_simple_projection.rb +0 -58
  85. data/test/test_suite.rb +0 -14
  86. data/test/test_transform.rb +0 -115
  87. data/test/test_units.rb +0 -46
@@ -0,0 +1,32 @@
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
@@ -0,0 +1,70 @@
1
+ require 'singleton'
2
+
3
+ module Proj
4
+ class Config
5
+ include Singleton
6
+
7
+ def set_search_paths
8
+ p_paths = self.search_paths_pointer
9
+ items = p_paths.type_size/p_paths.size
10
+
11
+ # Set search paths on default context - any new contexts will inherit from this
12
+ if Api.method_defined?(:proj_context_set_search_paths)
13
+ Api.proj_context_set_search_paths(nil, items, p_paths)
14
+ end
15
+
16
+ if Api.method_defined?(:pj_set_searchpath)
17
+ Api.pj_set_searchpath(items, p_paths)
18
+ end
19
+ end
20
+
21
+ def search_paths
22
+ ['/usr/share/proj',
23
+ '/usr/local/share/proj',
24
+ '/opt/share/proj',
25
+ '/opt/local/share/proj',
26
+ 'c:/msys64/mingw64/share/proj',
27
+ 'c:/mingw64/share/proj',
28
+ '/opt/local/lib/proj6/share/proj',
29
+ '/opt/local/lib/proj5/share/proj',
30
+ '/opt/local/lib/proj49/share/proj']
31
+ end
32
+
33
+ def data_path
34
+ if ENV['PROJ_LIB'] && File.directory?(ENV['PROJ_LIB'])
35
+ ENV['PROJ_LIB']
36
+ else
37
+ result = self.search_paths.detect do |path|
38
+ File.directory?(path)
39
+ end
40
+
41
+ unless result
42
+ raise(Error, "Could not find Proj data directory. Please set the PROJ_LIB environmental variable to correct directory")
43
+ end
44
+
45
+ result
46
+ end
47
+ end
48
+
49
+ def search_paths_pointer
50
+ p_path = FFI::MemoryPointer.from_string(self.data_path)
51
+ p_paths = FFI::MemoryPointer.new(:pointer, 1)
52
+ p_paths[0].write_pointer(p_path)
53
+ p_paths
54
+ end
55
+
56
+ def db_path
57
+ result = self.search_paths.map do |path|
58
+ File.join(path, 'proj.db')
59
+ end.detect do |path|
60
+ File.exists?(path)
61
+ end
62
+
63
+ unless result
64
+ raise(Error, "Could not find Proj database (proj.db). Please set the PROJ_LIB environmental variable to directory that contains it")
65
+ end
66
+
67
+ result
68
+ end
69
+ end
70
+ end
@@ -0,0 +1,103 @@
1
+ module Proj
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).
4
+ class Context
5
+ # The context for the current thread
6
+ #
7
+ # @return [Context]
8
+ def self.current
9
+ Thread.current[:proj_context] ||= Context.new
10
+ end
11
+
12
+ def self.finalize(pointer)
13
+ proc do
14
+ Api.proj_context_destroy(pointer)
15
+ end
16
+ end
17
+
18
+ def initialize
19
+ @pointer = Api.proj_context_create
20
+ ObjectSpace.define_finalizer(self, self.class.finalize(@pointer))
21
+
22
+ set_database_path
23
+ end
24
+
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
29
+
30
+ self.database_path = Config.instance.db_path
31
+ end
32
+
33
+ def to_ptr
34
+ @pointer
35
+ end
36
+
37
+ # Get the last error number
38
+ #
39
+ # return [Integer]
40
+ def errno
41
+ Api.proj_context_errno(self)
42
+ end
43
+
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
+ # Sets a custom log function
60
+ #
61
+ # @example
62
+ # context.set_log_function(data) do |pointer, int, message|
63
+ # ... do stuff...
64
+ # end
65
+ #
66
+ # @param pointer [FFI::MemoryPointer] Optional pointer to custom data
67
+ # @param proc [Proc] Custom logging procedure
68
+ # @return [nil]
69
+ def set_log_function(pointer = nil, &proc)
70
+ Api.proj_log_func(self, pointer, proc)
71
+ end
72
+
73
+ # Gets the current log level
74
+ #
75
+ # @return [:PJ_LOG_LEVEL]
76
+ def log_level
77
+ Api.proj_log_level(self, :PJ_LOG_TELL)
78
+ end
79
+
80
+ # Sets the current log level
81
+ #
82
+ # @param value [:PJ_LOG_LEVEL]
83
+ # @return [nil]
84
+ def log_level=(value)
85
+ Api.proj_log_level(self, value)
86
+ end
87
+
88
+ # Gets if proj4 init rules are being used (i.e., support +init parameters)
89
+ #
90
+ # @return [Boolean]
91
+ def use_proj4_init_rules
92
+ Api.proj_context_get_use_proj4_init_rules(self, 0)
93
+ end
94
+
95
+ # Sets if proj4 init rules should be used
96
+ #
97
+ # @param value [Boolean]
98
+ # @return [nil]
99
+ def use_proj4_init_rules=(value)
100
+ Api.proj_context_use_proj4_init_rules(self, value ? 1 : 0)
101
+ end
102
+ end
103
+ end
@@ -0,0 +1,197 @@
1
+ # encoding: UTF-8
2
+
3
+ module Proj
4
+ # A four dimensional coordinate of double values.
5
+ #
6
+ # For most geographic Crses, the units will be in degrees.
7
+ class Coordinate
8
+ def self.from_coord(pj_coord)
9
+ result = self.allocate
10
+ result.instance_variable_set(:@coord, pj_coord)
11
+ result
12
+ end
13
+
14
+ # Creates a new coordinate.
15
+ #
16
+ # @example
17
+ #
18
+ # coord = Proj::Coordinate.new(:x => 1, :y => 2, :z => 3, :t => 4)
19
+ # coord = Proj::Coordinate.new(:u => 5, :v => 6, :w => 7, :t => 8)
20
+ # coord = Proj::Coordinate.new(:lam => 9, :phi => 10, :z => 11, :t => 12)
21
+ # coord = Proj::Coordinate.new(:s => 13, :a1 => 14, :a2 => 15)
22
+ # coord = Proj::Coordinate.new(:o => 16, :p => 17, :k => 18)
23
+ # coord = Proj::Coordinate.new(:e => 19, :n => 20, :u => 21)
24
+
25
+ def initialize(x: nil, y: nil, z: nil, t: nil,
26
+ u: nil, v: nil, w: nil, # t: nil
27
+ lam: nil, phi: nil, # z: nil, t: nil,
28
+ s: nil, a1: nil, a2: nil,
29
+ o: nil, p: nil, k: nil,
30
+ e: nil, n: nil) #u: nil
31
+
32
+ @coord = Api::PJ_COORD.new
33
+
34
+ keys = if x && y && z && t
35
+ [:x, :y, :z, :t]
36
+ elsif x && y && z
37
+ [:x, :y, :z]
38
+ elsif x && y
39
+ [:x, :y]
40
+ elsif u && v && w && t
41
+ [:u, :v, :w, :t]
42
+ elsif u && v && w
43
+ [:u, :v, :w]
44
+ elsif u && v
45
+ [:u, :v]
46
+ elsif lam && phi && z && t
47
+ [:lam, :phi, :z, :t]
48
+ elsif lam && phi && z
49
+ [:lam, :phi, :z]
50
+ elsif lam && phi
51
+ [:lam, :phi]
52
+ elsif s && a1 && a2
53
+ [:s, :a1, :a2]
54
+ elsif e && n && u
55
+ [:e, :n, :u]
56
+ elsif o && p && k
57
+ [:o, :p, :k]
58
+ end
59
+
60
+ coord_struct = @coord[:v]
61
+ keys.each_with_index do |key, index|
62
+ coord_struct[index] = binding.local_variable_get(key)
63
+ end
64
+ end
65
+
66
+ def to_ptr
67
+ @coord.to_ptr
68
+ end
69
+
70
+ # Returns x coordinate
71
+ #
72
+ # @return [Float]
73
+ def x
74
+ @coord[:v][0]
75
+ end
76
+
77
+ # Returns y coordinate
78
+ #
79
+ # @return [Float]
80
+ def y
81
+ @coord[:v][1]
82
+ end
83
+
84
+ # Returns z coordinate
85
+ #
86
+ # @return [Float]
87
+ def z
88
+ @coord[:v][2]
89
+ end
90
+
91
+ # Returns t coordinate
92
+ #
93
+ # @return [Float]
94
+ def t
95
+ @coord[:v][3]
96
+ end
97
+
98
+ # Returns u coordinate
99
+ #
100
+ # @return [Float]
101
+ # TODO - This could be u in uvw or enu. Going to ignore that
102
+ def u
103
+ @coord[:v][0]
104
+ end
105
+
106
+ # Returns v coordinate
107
+ #
108
+ # @return [Float]
109
+ def v
110
+ @coord[:v][1]
111
+ end
112
+
113
+ # Returns w coordinate
114
+ #
115
+ # @return [Float]
116
+ def w
117
+ @coord[:v][2]
118
+ end
119
+
120
+ # Returns lam coordinate
121
+ #
122
+ # @return [Float]
123
+ def lam
124
+ @coord[:v][0]
125
+ end
126
+
127
+ # Returns phi coordinate
128
+ #
129
+ # @return [Float]
130
+ def phi
131
+ @coord[:v][1]
132
+ end
133
+
134
+ # Returns o coordinate
135
+ #
136
+ # @return [Float]
137
+ def o
138
+ @coord[:v][0]
139
+ end
140
+
141
+ # Returns p coordinate
142
+ #
143
+ # @return [Float]
144
+ def p
145
+ @coord[:v][1]
146
+ end
147
+
148
+ # Returns k coordinate
149
+ #
150
+ # @return [Float]
151
+ def k
152
+ @coord[:v][3]
153
+ end
154
+
155
+ # Returns e coordinate
156
+ #
157
+ # @return [Float]
158
+ def e
159
+ @coord[:v][0]
160
+ end
161
+
162
+ # Returns n coordinate
163
+ #
164
+ # @return [Float]
165
+ def n
166
+ @coord[:v][1]
167
+ end
168
+
169
+ # Returns s coordinate
170
+ #
171
+ # @return [Float]
172
+ def s
173
+ @coord[:v][0]
174
+ end
175
+
176
+ # Returns a1 coordinate
177
+ #
178
+ # @return [Float]
179
+ def a1
180
+ @coord[:v][1]
181
+ end
182
+
183
+ # Returns a2 coordinate
184
+ #
185
+ # @return [Float]
186
+ def a2
187
+ @coord[:v][2]
188
+ end
189
+
190
+ # Returns nice printout of coordinate contents
191
+ #
192
+ # @return [String]
193
+ def to_s
194
+ "v0: #{self.x}, v1: #{self.y}, v2: #{self.z}, v3: #{self.t}"
195
+ end
196
+ end
197
+ end
@@ -0,0 +1,206 @@
1
+ # encoding: UTF-8
2
+ require 'stringio'
3
+
4
+ module Proj
5
+ # Represents a coordinate reference system.
6
+ class Crs < PjObject
7
+ # To create a coordinate system, you can use CRS codes, well-known text (WKT) strings
8
+ # or old-style Proj4 strings (which are deprecated).
9
+ #
10
+ # @example
11
+ # crs1 = Proj::Crs.new('EPSG:4326')
12
+ # crs2 = Proj::Crs.new('urn:ogc:def:crs:EPSG::4326')
13
+ # crs3 = Proj::Crs.new('+proj=longlat +datum=WGS84 +no_defs +type=crs')
14
+ # crs4 = Proj::Crs.new(<<~EOS)
15
+ # GEOGCRS["WGS 84",
16
+ # DATUM["World Geodetic System 1984",
17
+ # ELLIPSOID["WGS 84",6378137,298.257223563,
18
+ # LENGTHUNIT["metre",1]]],
19
+ # PRIMEM["Greenwich",0,
20
+ # ANGLEUNIT["degree",0.0174532925199433]],
21
+ # CS[ellipsoidal,2],
22
+ # AXIS["geodetic latitude (Lat)",north,
23
+ # ORDER[1],
24
+ # ANGLEUNIT["degree",0.0174532925199433]],
25
+ # AXIS["geodetic longitude (Lon)",east,
26
+ # ORDER[2],
27
+ # ANGLEUNIT["degree",0.0174532925199433]],
28
+ # USAGE[
29
+ # SCOPE["unknown"],
30
+ # AREA["World"],
31
+ # BBOX[-90,-180,90,180]],
32
+ # ID["EPSG",4326]]
33
+ # EOS
34
+ #
35
+ # Notice when using the old-style Proj4 string, the addition of the "+type=crs" value.
36
+ #
37
+ # @param value [String]. See above
38
+ # @param context [Context]. An optional Context that the Crs will use for calculations.
39
+ def initialize(value, context=nil)
40
+ pointer = Api.proj_create(context || Context.current, value)
41
+
42
+ if pointer.null?
43
+ Error.check
44
+ end
45
+
46
+ super(pointer, context)
47
+
48
+ if Api.method_defined?(:proj_is_crs) && !Api.proj_is_crs(pointer)
49
+ raise(Error, "Invalid crs definition. Proj created an instance of: #{self.proj_type}.")
50
+ end
51
+ end
52
+
53
+ # Get the geodeticCRS / geographicCRS from a CRS.
54
+ #
55
+ # @return [Crs]
56
+ def geodetic_crs
57
+ PjObject.new(Api.proj_crs_get_geodetic_crs(self.context, self))
58
+ end
59
+
60
+ # Get a CRS component from a CompoundCRS.
61
+ #
62
+ # @return [Crs]
63
+ def sub_crs(index)
64
+ PjObject.new(Api.proj_crs_get_sub_crs(self.context, self, index))
65
+ end
66
+
67
+ # Returns the datum of a SingleCRS.
68
+ #
69
+ # @return [Crs]
70
+ def datum
71
+ PjObject.new(Api.proj_crs_get_datum(self.context, self))
72
+ end
73
+
74
+ # Get the horizontal datum from a CRS.
75
+ #
76
+ # @return [Crs]
77
+ def horizontal_datum
78
+ PjObject.new(Api.proj_crs_get_horizontal_datum(self.context, self))
79
+ end
80
+
81
+ # Returns the coordinate system of a SingleCRS.
82
+ #
83
+ # @return [Crs]
84
+ def coordinate_system
85
+ PjObject.new(Api.proj_crs_get_coordinate_system(self.context, self))
86
+ end
87
+
88
+ # Returns the number of axis of the coordinate system.
89
+ #
90
+ # @return [Integer]
91
+ def axis_count
92
+ foo = Api.proj_crs_get_coordinate_system(self.context, self)
93
+ result = Api.proj_cs_get_axis_count(self.context, self.coordinate_system)
94
+ if result == -1
95
+ Error.check
96
+ end
97
+ result
98
+ end
99
+
100
+ # Returns information on an axis.
101
+ #
102
+ # @return [Array<Hash>]
103
+ def axis_info
104
+ self.axis_count.times.map do |index|
105
+ p_name = FFI::MemoryPointer.new(:pointer)
106
+ p_abbreviation = FFI::MemoryPointer.new(:pointer)
107
+ p_direction = FFI::MemoryPointer.new(:pointer)
108
+ p_unit_conv_factor = FFI::MemoryPointer.new(:double)
109
+ p_unit_name = FFI::MemoryPointer.new(:pointer)
110
+ p_unit_auth_name = FFI::MemoryPointer.new(:pointer)
111
+ p_unit_code = FFI::MemoryPointer.new(:pointer)
112
+
113
+ result = Api.proj_cs_get_axis_info(self.context, self.coordinate_system, index,
114
+ p_name, p_abbreviation, p_direction, p_unit_conv_factor, p_unit_name, p_unit_auth_name, p_unit_code)
115
+
116
+ unless result
117
+ Error.check
118
+ end
119
+
120
+ {:name => p_name.read_pointer.read_string,
121
+ :abbreviation => p_abbreviation.read_pointer.read_string_to_null,
122
+ :direction => p_direction.read_pointer.read_string_to_null,
123
+ :unit_conv_factor => p_unit_conv_factor.read_double,
124
+ :unit_name => p_unit_name.read_pointer.read_string_to_null,
125
+ :unit_auth_name => p_unit_auth_name.read_pointer.read_string_to_null,
126
+ :unit_code => p_unit_code.read_pointer.read_string_to_null}
127
+ end
128
+ end
129
+
130
+ # Returns the type of the coordinate system.
131
+ #
132
+ # @return [:PJ_COORDINATE_SYSTEM_TYPE]
133
+ def crs_type
134
+ foo = Api.proj_crs_get_coordinate_system(self.context, self)
135
+ result = Api.proj_cs_get_type(self.context, self.coordinate_system)
136
+ if result == :PJ_CS_TYPE_UNKNOWN
137
+ Error.check
138
+ end
139
+ result
140
+ end
141
+
142
+ # Return the area of use of an object.
143
+ #
144
+ # @return [Area]
145
+ def area
146
+ @area ||= Area.for_object(self)
147
+ end
148
+
149
+ # Get the ellipsoid from a CRS or a GeodeticReferenceFrame.
150
+ #
151
+ # @return [PjObject]
152
+ def ellipsoid
153
+ PjObject.new(Api.proj_get_ellipsoid(self.context, self))
154
+ end
155
+
156
+ # Return the Conversion of a DerivedCRS (such as a ProjectedCRS), or the Transformation from
157
+ # the baseCRS to the hubCRS of a BoundCRS.
158
+ #
159
+ # @return [PjObject]
160
+ def operation
161
+ pointer = Api.proj_crs_get_coordoperation(self.context, self)
162
+ if pointer.null?
163
+ Error.check
164
+ end
165
+ PjObject.new(pointer)
166
+ end
167
+
168
+ # Get the prime meridian of a CRS or a GeodeticReferenceFrame.
169
+ #
170
+ # @return [PjObject]
171
+ def prime_meridian
172
+ PjObject.new(Api.proj_get_prime_meridian(self.context, self))
173
+ end
174
+
175
+ # A nicely printed out description
176
+ #
177
+ # @return [String]
178
+ def inspect
179
+ result = StringIO.new
180
+ result.set_encoding('UTF-8')
181
+ result << <<~EOS
182
+ <#{self.class.name}>: #{self.auth(0)}
183
+ #{self.description}
184
+ Axis Info [#{self.crs_type}]:
185
+ EOS
186
+
187
+ self.axis_info.each do |axis_info|
188
+ result << "- #{axis_info[:abbreviation]}[#{axis_info[:direction]}]: #{axis_info[:name]} (#{axis_info[:unit_name]})" << "\n"
189
+ end
190
+
191
+ result << <<~EOS
192
+ Area of Use:
193
+ - name: #{self.area.name}
194
+ - bounds: (#{self.area.west_lon_degree}, #{self.area.south_lat_degree}, #{self.area.east_lon_degree}, #{self.area.north_lat_degree})
195
+ Coordinate operation:
196
+ - name: ?
197
+ - method: ?
198
+ Datum: #{self.datum.name}
199
+ - Ellipsoid: #{self.ellipsoid.name}
200
+ - Prime Meridian: #{self.prime_meridian.name}
201
+ EOS
202
+
203
+ result.string
204
+ end
205
+ end
206
+ end