ffi-gdal 0.0.4 → 1.0.0.beta1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (138) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +7 -1
  3. data/Rakefile +12 -1
  4. data/TODO.md +11 -0
  5. data/ffi-gdal.gemspec +2 -2
  6. data/lib/ext/error_symbols.rb +59 -0
  7. data/lib/ext/float_ext.rb +15 -0
  8. data/lib/ext/narray_ext.rb +16 -0
  9. data/lib/ext/to_bool.rb +2 -0
  10. data/lib/ffi-gdal.rb +139 -4
  11. data/lib/ffi/{gdal/cpl_conv.rb → cpl/conv_h.rb} +2 -3
  12. data/lib/ffi/{gdal/cpl_error.rb → cpl/error_h.rb} +1 -25
  13. data/lib/ffi/cpl/minixml_h.rb +14 -0
  14. data/lib/ffi/{gdal/cpl_string.rb → cpl/string_h.rb} +0 -25
  15. data/lib/ffi/{gdal/cpl_vsi.rb → cpl/vsi_h.rb} +0 -0
  16. data/lib/ffi/cpl/xml_node.rb +13 -0
  17. data/lib/ffi/gdal.rb +57 -593
  18. data/lib/ffi/gdal/alg_h.rb +127 -0
  19. data/lib/ffi/gdal/gdal_grid_data_metrics_options.rb +14 -0
  20. data/lib/ffi/gdal/gdal_grid_inverse_distance_to_a_power_options.rb +19 -0
  21. data/lib/ffi/gdal/gdal_grid_moving_average_options.rb +14 -0
  22. data/lib/ffi/gdal/gdal_grid_nearest_neighbor_options.rb +13 -0
  23. data/lib/ffi/gdal/gdal_h.rb +683 -0
  24. data/lib/ffi/gdal/gdal_rpc_info.rb +27 -0
  25. data/lib/ffi/gdal/gdal_transformer_info.rb +14 -0
  26. data/lib/ffi/gdal/gdal_warp_options.rb +43 -0
  27. data/lib/ffi/gdal/grid_h.rb +51 -0
  28. data/lib/ffi/gdal/version.rb +1 -1
  29. data/lib/ffi/gdal/warper_h.rb +48 -0
  30. data/lib/ffi/ogr.rb +12 -0
  31. data/lib/ffi/ogr/api_h.rb +553 -0
  32. data/lib/ffi/ogr/core_h.rb +148 -0
  33. data/lib/ffi/ogr/featurestyle_h.rb +22 -0
  34. data/lib/ffi/ogr/geocoding_h.rb +21 -0
  35. data/lib/ffi/ogr/ogr_contour_writer_info.rb +14 -0
  36. data/lib/ffi/ogr/ogr_envelope.rb +12 -0
  37. data/lib/ffi/ogr/ogr_envelope_3d.rb +14 -0
  38. data/lib/ffi/ogr/ogr_field.rb +50 -0
  39. data/lib/ffi/ogr/ogr_style_param.rb +12 -0
  40. data/lib/ffi/ogr/ogr_style_value.rb +13 -0
  41. data/lib/ffi/ogr/srs_api_h.rb +325 -0
  42. data/lib/gdal/color_entry.rb +47 -0
  43. data/lib/gdal/color_entry_extensions.rb +30 -0
  44. data/lib/gdal/color_interpretation.rb +15 -0
  45. data/lib/gdal/color_table.rb +146 -0
  46. data/lib/gdal/color_table_extensions.rb +47 -0
  47. data/lib/gdal/color_table_types/cmyk.rb +25 -0
  48. data/lib/gdal/color_table_types/gray.rb +9 -0
  49. data/lib/gdal/color_table_types/hls.rb +21 -0
  50. data/lib/gdal/color_table_types/rgb.rb +25 -0
  51. data/lib/gdal/data_type.rb +38 -0
  52. data/lib/gdal/dataset.rb +437 -0
  53. data/lib/gdal/dataset_extensions.rb +496 -0
  54. data/lib/gdal/driver.rb +244 -0
  55. data/lib/gdal/driver_extensions.rb +56 -0
  56. data/lib/gdal/environment_methods.rb +43 -0
  57. data/lib/{ffi-gdal → gdal}/exceptions.rb +4 -1
  58. data/lib/gdal/geo_transform.rb +188 -0
  59. data/lib/gdal/geo_transform_extensions.rb +90 -0
  60. data/lib/gdal/logger.rb +7 -0
  61. data/lib/{ffi-gdal → gdal}/major_object.rb +15 -14
  62. data/lib/gdal/options.rb +49 -0
  63. data/lib/gdal/raster_attribute_table.rb +185 -0
  64. data/lib/gdal/raster_attribute_table_extensions.rb +40 -0
  65. data/lib/{ffi-gdal → gdal}/raster_band.rb +227 -99
  66. data/lib/gdal/raster_band_extensions.rb +198 -0
  67. data/lib/{ffi-gdal → gdal}/version_info.rb +8 -0
  68. data/lib/gdal/warp_operation.rb +96 -0
  69. data/lib/ogr/coordinate_transformation.rb +108 -0
  70. data/lib/ogr/data_source.rb +172 -0
  71. data/lib/ogr/data_source_extensions.rb +32 -0
  72. data/lib/ogr/driver.rb +119 -0
  73. data/lib/ogr/envelope.rb +80 -0
  74. data/lib/ogr/envelope_extensions.rb +92 -0
  75. data/lib/ogr/exceptions.rb +35 -0
  76. data/lib/ogr/feature.rb +212 -0
  77. data/lib/ogr/feature_definition.rb +120 -0
  78. data/lib/ogr/feature_definition_extensions.rb +36 -0
  79. data/lib/ogr/feature_extensions.rb +31 -0
  80. data/lib/ogr/field.rb +91 -0
  81. data/lib/ogr/field_extensions.rb +23 -0
  82. data/lib/ogr/geocoding_session.rb +84 -0
  83. data/lib/ogr/geometry.rb +617 -0
  84. data/lib/ogr/geometry_extensions.rb +60 -0
  85. data/lib/ogr/geometry_types/collection.rb +45 -0
  86. data/lib/ogr/geometry_types/curve.rb +120 -0
  87. data/lib/ogr/geometry_types/surface.rb +20 -0
  88. data/lib/ogr/layer.rb +226 -0
  89. data/lib/ogr/layer_extensions.rb +55 -0
  90. data/lib/ogr/line_string.rb +7 -0
  91. data/lib/ogr/linear_ring.rb +6 -0
  92. data/lib/ogr/multi_line_string.rb +9 -0
  93. data/lib/ogr/multi_point.rb +7 -0
  94. data/lib/ogr/multi_polygon.rb +14 -0
  95. data/lib/ogr/point.rb +89 -0
  96. data/lib/ogr/polygon.rb +9 -0
  97. data/lib/ogr/spatial_reference.rb +723 -0
  98. data/lib/ogr/spatial_reference_extensions.rb +32 -0
  99. data/lib/ogr/style_table.rb +17 -0
  100. data/lib/ogr/style_table_extensions.rb +16 -0
  101. data/spec/{ffi-gdal/integration → integration}/color_table_info_spec.rb +1 -1
  102. data/spec/{ffi-gdal/integration → integration}/dataset_info_spec.rb +0 -0
  103. data/spec/{ffi-gdal/integration → integration}/driver_info_spec.rb +1 -1
  104. data/spec/{ffi-gdal/integration → integration}/geo_transform_info_spec.rb +0 -0
  105. data/spec/{ffi-gdal/integration → integration}/raster_attribute_table_info_spec.rb +1 -1
  106. data/spec/{ffi-gdal/integration → integration}/raster_band_info_spec.rb +5 -5
  107. data/spec/spec_helper.rb +4 -1
  108. data/spec/support/shapefiles/states_21basic/states.prj +1 -0
  109. data/spec/support/shapefiles/states_21basic/states.sbn +0 -0
  110. data/spec/support/shapefiles/states_21basic/states.sbx +0 -0
  111. data/spec/support/shapefiles/states_21basic/states.shp +0 -0
  112. data/spec/support/worldfiles/SR_50M/SR_50M.VERSION.txt +1 -0
  113. data/spec/support/worldfiles/SR_50M/SR_50M.prj +1 -0
  114. data/spec/support/worldfiles/SR_50M/SR_50M.tfw +6 -0
  115. data/spec/{ext/cpl_error_symbols_spec.rb → unit/ext/error_symbols_spec.rb} +1 -1
  116. data/spec/unit/gdal/color_table_spec.rb +146 -0
  117. data/spec/unit/ogr/layer_spec.rb +97 -0
  118. data/spec/unit/ogr/linear_ring_spec.rb +111 -0
  119. data/spec/unit/ogr/point_spec.rb +321 -0
  120. data/spec/{ffi-gdal/unit → unit}/version_info_spec.rb +1 -1
  121. data/testing_gdal.rb +168 -0
  122. data/testing_gdalwarp.rb +91 -0
  123. data/testing_layer_to_layer.rb +35 -0
  124. data/testing_ndvi.rb +76 -0
  125. data/testing_nir.rb +77 -0
  126. data/testing_ogr.rb +63 -0
  127. metadata +167 -59
  128. data/lib/ext/cpl_error_symbols.rb +0 -37
  129. data/lib/ffi-gdal/color_table.rb +0 -59
  130. data/lib/ffi-gdal/dataset.rb +0 -359
  131. data/lib/ffi-gdal/driver.rb +0 -151
  132. data/lib/ffi-gdal/geo_transform.rb +0 -137
  133. data/lib/ffi-gdal/raster_attribute_table.rb +0 -78
  134. data/lib/ffi/gdal/ogr_api.rb +0 -21
  135. data/lib/ffi/gdal/ogr_core.rb +0 -195
  136. data/lib/ffi/gdal/ogr_srs_api.rb +0 -44
  137. data/meow.rb +0 -144
  138. data/rubby.rb +0 -224
@@ -0,0 +1,55 @@
1
+ require 'json'
2
+
3
+ module OGR
4
+ module LayerExtensions
5
+
6
+ # @return [Array<OGR::Feature>]
7
+ def features
8
+ feature_list = 0.upto(feature_count - 1).map do |i|
9
+ feature(i)
10
+ end
11
+
12
+ @features = feature_list
13
+ end
14
+
15
+ # @return [OGR::Geometry] A convex hull geometry derived from a LineString
16
+ # that connects the 4 bounding box points (from the extent).
17
+ def geometry_from_extent
18
+ sr = spatial_reference
19
+ geometry = OGR::Geometry.create(:wkbLineString)
20
+ geometry.spatial_reference = sr
21
+
22
+ geometry.add_point(extent.x_min, extent.y_min)
23
+ geometry.add_point(extent.x_min, extent.y_max)
24
+ geometry.add_point(extent.x_max, extent.y_max)
25
+ geometry.add_point(extent.x_max, extent.y_min)
26
+ geometry.add_point(extent.x_min, extent.y_min)
27
+
28
+ geometry.convex_hull
29
+ end
30
+
31
+ # @return [Hash]
32
+ def as_json
33
+ {
34
+ layer: {
35
+ extent: extent.as_json,
36
+ feature_count: feature_count,
37
+ feature_definition: feature_definition.as_json,
38
+ features: features.map(&:as_json),
39
+ fid_column: fid_column,
40
+ geometry_column: geometry_column,
41
+ geometry_type: geometry_type,
42
+ name: name,
43
+ spatial_reference: spatial_reference.as_json,
44
+ style_table: style_table ? style_table.as_json : nil
45
+ },
46
+ metadata: nil #all_metadata
47
+ }
48
+ end
49
+
50
+ # @return [String]
51
+ def to_json
52
+ as_json.to_json
53
+ end
54
+ end
55
+ end
@@ -0,0 +1,7 @@
1
+ require_relative 'geometry_types/curve'
2
+
3
+ module OGR
4
+ class LineString < Geometry
5
+ include GeometryTypes::Curve
6
+ end
7
+ end
@@ -0,0 +1,6 @@
1
+ require_relative 'line_string'
2
+
3
+ module OGR
4
+ class LinearRing < LineString
5
+ end
6
+ end
@@ -0,0 +1,9 @@
1
+ require_relative 'geometry_types/curve'
2
+ require_relative 'geometry_types/collection'
3
+
4
+ module OGR
5
+ class MultiLineString < Geometry
6
+ include GeometryTypes::Curve
7
+ include GeometryTypes::Collection
8
+ end
9
+ end
@@ -0,0 +1,7 @@
1
+ require_relative 'geometry_types/collection'
2
+
3
+ module OGR
4
+ class MultiPoint < Geometry
5
+ include GeometryTypes::Collection
6
+ end
7
+ end
@@ -0,0 +1,14 @@
1
+ require_relative 'geometry_types/collection'
2
+ require_relative 'geometry_types/surface'
3
+
4
+ module OGR
5
+ class MultiPolygon < Geometry
6
+ include GeometryTypes::Collection
7
+ include GeometryTypes::Surface
8
+
9
+ # @return [OGR::Geometry]
10
+ def union_cascaded
11
+ build_geometry { |ptr| FFI::GDAL.OGR_G_UnionCascaded(ptr) }
12
+ end
13
+ end
14
+ end
data/lib/ogr/point.rb ADDED
@@ -0,0 +1,89 @@
1
+ module OGR
2
+ class Point < Geometry
3
+ # def area
4
+ # 0.0
5
+ # end
6
+
7
+ # @return [Float]
8
+ def x
9
+ return nil if empty?
10
+
11
+ FFI::GDAL.OGR_G_GetX(@geometry_pointer, 0)
12
+ end
13
+
14
+ # @return [Float]
15
+ def y
16
+ return nil if empty?
17
+
18
+ FFI::GDAL.OGR_G_GetY(@geometry_pointer, 0)
19
+ end
20
+
21
+ # @return [Float]
22
+ def z
23
+ return nil if empty?
24
+
25
+ FFI::GDAL.OGR_G_GetZ(@geometry_pointer, 0)
26
+ end
27
+
28
+ # @return [Array<Float, Float, Float>] [x, y] if 2d or [x, y, z] if 3d.
29
+ def point
30
+ return [] if empty?
31
+
32
+ x_ptr = FFI::MemoryPointer.new(:double)
33
+ y_ptr = FFI::MemoryPointer.new(:double)
34
+ z_ptr = FFI::MemoryPointer.new(:double)
35
+
36
+ FFI::GDAL.OGR_G_GetPoint(@geometry_pointer, 0, x_ptr, y_ptr, z_ptr)
37
+
38
+ if coordinate_dimension == 2
39
+ [x_ptr.read_double, y_ptr.read_double]
40
+ else
41
+ [x_ptr.read_double, y_ptr.read_double, z_ptr.read_double]
42
+ end
43
+ end
44
+
45
+ def set_point(x, y, z=0)
46
+ FFI::GDAL.OGR_G_SetPoint(@geometry_pointer, 0, x, y, z)
47
+ end
48
+
49
+ # Adds a point to a LineString or Point geometry.
50
+ #
51
+ # @param x [Float]
52
+ # @param y [Float]
53
+ # @param z [Float]
54
+ def add_point(x, y, z=0)
55
+ FFI::GDAL.OGR_G_AddPoint(@geometry_pointer, x, y, z)
56
+ end
57
+
58
+ # @return [Array<Array>] An array of (x, y) or (x, y, z) points.
59
+ def points
60
+ return [[]] if empty?
61
+
62
+ x_stride = 2
63
+ y_stride = 2
64
+ z_stride = coordinate_dimension == 3 ? 1 : 0
65
+
66
+ buffer_size = FFI::Type::DOUBLE.size * 2 * point_count
67
+
68
+ x_buffer = FFI::MemoryPointer.new(:buffer_out, buffer_size)
69
+ y_buffer = FFI::MemoryPointer.new(:buffer_out, buffer_size)
70
+
71
+ z_buffer = if coordinate_dimension == 3
72
+ z_size = FFI::Type::DOUBLE.size * point_count
73
+ FFI::MemoryPointer.new(:buffer_out, z_size)
74
+ else
75
+ nil
76
+ end
77
+
78
+ num_points = FFI::GDAL.OGR_G_GetPoints(@geometry_pointer,
79
+ x_buffer,
80
+ x_stride,
81
+ y_buffer,
82
+ y_stride,
83
+ z_buffer,
84
+ z_stride)
85
+
86
+ [point]
87
+ end
88
+ end
89
+ end
@@ -0,0 +1,9 @@
1
+ require_relative 'geometry_types/surface'
2
+ require_relative 'geometry_types/collection'
3
+
4
+ module OGR
5
+ class Polygon < Geometry
6
+ include GeometryTypes::Surface
7
+ include GeometryTypes::Collection
8
+ end
9
+ end
@@ -0,0 +1,723 @@
1
+ require_relative '../ffi/ogr'
2
+ require_relative 'spatial_reference_extensions'
3
+
4
+ module OGR
5
+ # Represents a geographic coordinate system. There are two primary types:
6
+ # 1. "geographic", where positions are measured in long/lat.
7
+ # 2. "projected", where positions are measure in meters or feet.
8
+ class SpatialReference
9
+ include SpatialReferenceExtensions
10
+
11
+ # @return [Array<String>]
12
+ def self.projection_methods
13
+ return @projection_methods if @projection_methods
14
+
15
+ methods_ptr_ptr = FFI::GDAL.OPTGetProjectionMethods
16
+ count = FFI::GDAL.CSLCount(methods_ptr_ptr)
17
+
18
+ # For some reason #get_array_of_string leaves off the first 6.
19
+ pointer_array = methods_ptr_ptr.get_array_of_pointer(0, count)
20
+
21
+ pointer_array.map(&:read_string).sort
22
+ end
23
+
24
+ # @param projection_method [String] One of
25
+ # OGR::SpatialReference.projection_methods.
26
+ # @return [Hash{parameter => Array<String>, user_visible_name => String}]
27
+ def self.parameter_list(projection_method)
28
+ name_ptr = FFI::MemoryPointer.new(:string)
29
+ name_ptr_ptr = FFI::MemoryPointer.new(:pointer)
30
+ name_ptr_ptr.write_pointer(name_ptr)
31
+
32
+ params_ptr_ptr = FFI::GDAL.OPTGetParameterList(projection_method,
33
+ name_ptr_ptr)
34
+ count = FFI::GDAL.CSLCount(params_ptr_ptr)
35
+
36
+ # For some reason #get_array_of_string leaves off the first 6.
37
+ pointer_array = params_ptr_ptr.get_array_of_pointer(0, count)
38
+
39
+ name = if !name_ptr_ptr.read_pointer.null?
40
+ name_ptr_ptr.read_pointer.read_string
41
+ else
42
+ nil
43
+ end
44
+
45
+ {
46
+ parameters: pointer_array.map(&:read_string).sort,
47
+ user_visible_name: name
48
+ }
49
+ end
50
+
51
+ def self.parameter_info(projection_method, parameter_name)
52
+ name_ptr = FFI::MemoryPointer.new(:string)
53
+ name_ptr_ptr = FFI::MemoryPointer.new(:pointer)
54
+ name_ptr_ptr.write_pointer(name_ptr)
55
+
56
+ type_ptr = FFI::MemoryPointer.new(:string)
57
+ type_ptr_ptr = FFI::MemoryPointer.new(:pointer)
58
+ type_ptr_ptr.write_pointer(type_ptr)
59
+
60
+ default_value_ptr = FFI::MemoryPointer.new(:double)
61
+
62
+ result = FFI::GDAL.OPTGetParameterInfo(projection_method, parameter_name,
63
+ name_ptr_ptr, type_ptr_ptr, default_value_ptr)
64
+
65
+ return {} unless result
66
+
67
+ name = if !name_ptr_ptr.read_pointer.null?
68
+ name_ptr_ptr.read_pointer.read_string
69
+ else
70
+ nil
71
+ end
72
+
73
+ type = if !type_ptr_ptr.read_pointer.null?
74
+ type_ptr_ptr.read_pointer.read_string
75
+ else
76
+ nil
77
+ end
78
+
79
+ {
80
+ type: type,
81
+ default_value: default_value_ptr.read_double,
82
+ user_visible_name: name
83
+ }
84
+ end
85
+
86
+ # @param code [Fixnum]
87
+ # @return [OGR::SpatialReference]
88
+ def self.new_from_epsg(code)
89
+ build_spatial_ref do |spatial_ref|
90
+ FFI::GDAL.OSRImportFromEPSG(spatial_ref.c_pointer, code)
91
+ end
92
+ end
93
+
94
+ # @param code [Fixnum]
95
+ # @return [OGR::SpatialReference]
96
+ def self.new_from_epsga(code)
97
+ build_spatial_ref do |spatial_ref|
98
+ FFI::GDAL.OSRImportFromEPSGA(spatial_ref.c_pointer, code)
99
+ end
100
+ end
101
+
102
+ # @param projection_name [String] I.e. "NUTM11" or "GEOGRAPHIC".
103
+ # @param datum_name [String] I.e. "NAD83".
104
+ # @param linear_unit_name [String] Plural form of linear units, i.e. "FEET".
105
+ # @return [OGR::SpatialReference]
106
+ def self.new_from_erm(projection_name, datum_name, linear_unit_name)
107
+ build_spatial_ref do |spatial_ref|
108
+ FFI::GDAL.OSRImportFromERM(spatial_ref.c_pointer, projection_name,
109
+ datum_name, linear_unit_name)
110
+ end
111
+ end
112
+
113
+ # @param prj_text [Array<String>]
114
+ # @return [OGR::SpatialReference]
115
+ def self.new_from_esri(prj_text)
116
+ build_spatial_ref do |spatial_ref|
117
+ prj_ptr = FFI::MemoryPointer.new(:string, prj_text.size)
118
+ prj_ptr_ptr = FFI::MemoryPointer.new(:pointer)
119
+ prj_ptr_ptr.write_pointer(prj_ptr)
120
+
121
+ FFI::GDAL.OSRImportFromESRI(spatial_ref.c_pointer, prj_ptr_ptr)
122
+ end
123
+ end
124
+
125
+ # @param coord_sys [String] The Mapinfo style CoordSys definition string.
126
+ # @return [OGR::SpatialReference]
127
+ def self.new_from_mapinfo(coord_sys)
128
+ build_spatial_ref do |spatial_ref|
129
+ FFI::GDAL.OSRImportFromMICoordSys(spatial_ref.c_pointer, coord_sys)
130
+ end
131
+ end
132
+
133
+ # @param proj [String]
134
+ # @param units [String]
135
+ # @param proj_params [Array<String>]
136
+ # @return [OGR::SpatialReference]
137
+ def self.new_from_pci(proj, units, *proj_params)
138
+ build_spatial_ref do |spatial_ref|
139
+ if proj_params.empty?
140
+ proj_ptr = nil
141
+ else
142
+ proj_ptr = FFI::MemoryPointer.new(:double, proj_params.size)
143
+ proj_ptr.write_array_of_double(proj_params)
144
+ end
145
+
146
+ FFI::GDAL.OSRImportFromPCI(spatial_ref.c_pointer, proj, units, proj_ptr)
147
+ end
148
+ end
149
+
150
+ # @param proj4 [String]
151
+ # @return [OGR::SpatialReference]
152
+ def self.new_from_proj4(proj4)
153
+ build_spatial_ref do |spatial_ref|
154
+ FFI::GDAL.OSRImportFromProj4(spatial_ref.c_pointer, proj4)
155
+ end
156
+ end
157
+
158
+ # @param url [String] URL to fetch the spatial reference from.
159
+ # @return [OGR::SpatialReference]
160
+ def self.new_from_url(url)
161
+ build_spatial_ref do |spatial_ref|
162
+ FFI::GDAL.OSRImportFromUrl(spatial_ref.c_pointer, url)
163
+ end
164
+ end
165
+
166
+ def self.new_from_user_input(definition)
167
+ build_spatial_ref do |spatial_ref|
168
+ FFI::GDAL.OSRSetFromUserInput(spatial_ref.c_pointer, definition)
169
+ end
170
+ end
171
+
172
+ # @param projection_system_code
173
+ # @return [OGR::SpatialReference]
174
+ def self.new_from_usgs(projection_system_code, zone, datum, *proj_params)
175
+ build_spatial_ref do |spatial_ref|
176
+ if proj_params.empty?
177
+ proj_ptr = nil
178
+ else
179
+ proj_ptr = FFI::MemoryPointer.new(:double, proj_params.size)
180
+ proj_ptr.write_array_of_double(proj_params)
181
+ end
182
+
183
+ FFI::GDAL.OSRImportFromUSGS(spatial_ref.c_pointer,
184
+ projection_system_code, zone, proj_ptr, datum)
185
+ end
186
+ end
187
+
188
+ # This wipes the existing SRS definition and reassigns it based on the
189
+ # contents of +wkt+.
190
+ #
191
+ # @param wkt [String]
192
+ # @return [OGR::SpatialReference]
193
+ def self.new_from_wkt(wkt)
194
+ build_spatial_ref do |spatial_ref|
195
+ wkt_ptr = FFI::MemoryPointer.from_string(wkt)
196
+ wkt_ptr_ptr = FFI::MemoryPointer.new(:pointer)
197
+ wkt_ptr_ptr.write_pointer(wkt_ptr)
198
+
199
+ FFI::GDAL.OSRImportFromWkt(spatial_ref.c_pointer, wkt_ptr_ptr)
200
+ end
201
+ end
202
+
203
+ # Use for importing a GML coordinate system.
204
+ #
205
+ # @param xml [String]
206
+ # @return [OGR::SpatialReference]
207
+ def self.new_from_xml(xml)
208
+ build_spatial_ref do |spatial_ref|
209
+ FFI::GDAL.OSRImportFromXML(spatial_ref.c_pointer, xml)
210
+ end
211
+ end
212
+
213
+ # @return [OGR::SpatialReference]
214
+ def self.build_spatial_ref(spatial_reference_or_wkt=nil)
215
+ object = new(spatial_reference_or_wkt)
216
+ ogr_err = yield object
217
+ ogr_err.to_ruby
218
+
219
+ object
220
+ end
221
+ private_class_method :build_spatial_ref
222
+
223
+ # Builds a spatial reference object using either the passed-in WKT string,
224
+ # OGR::SpatialReference object, or a pointer to an in-memory
225
+ # SpatialReference object. If nothing is passed in, an empty
226
+ # SpatialReference object is created, in which case you'll need to populate
227
+ # relevant attributes.
228
+ #
229
+ # @param spatial_reference_or_wkt [OGR::SpatialReference, FFI::Pointer,
230
+ # String]
231
+ def initialize(spatial_reference_or_wkt=nil)
232
+ @ogr_spatial_ref_pointer = if spatial_reference_or_wkt.is_a? OGR::SpatialReference
233
+ spatial_reference_or_wkt.c_pointer
234
+ elsif spatial_reference_or_wkt.is_a? String
235
+ FFI::GDAL.OSRNewSpatialReference(spatial_reference_or_wkt)
236
+ elsif spatial_reference_or_wkt.is_a? FFI::Pointer
237
+ spatial_reference_or_wkt
238
+ else
239
+ FFI::GDAL.OSRNewSpatialReference(nil)
240
+ end
241
+
242
+ close_me = -> { destroy! }
243
+ ObjectSpace.define_finalizer self, close_me
244
+ end
245
+
246
+ def c_pointer
247
+ @ogr_spatial_ref_pointer
248
+ end
249
+
250
+ def destroy!
251
+ FFI::GDAL.OSRDestroySpatialReference(@ogr_spatial_ref_pointer)
252
+ end
253
+
254
+ # Uses the C-API to clone this spatial reference object.
255
+ def clone
256
+ new_spatial_ref_ptr = FFI::GDAL.OSRClone(@ogr_spatial_ref_pointer)
257
+
258
+ self.class.new(new_spatial_ref_ptr)
259
+ end
260
+
261
+ # Makes a duplicate of the GEOGCS node of this spatial reference.
262
+ #
263
+ # @return [OGR::SpatialReference]
264
+ def clone_geogcs
265
+ new_spatial_ref_ptr = FFI::GDAL.OSRCloneGeogCS(@ogr_spatial_ref_pointer)
266
+
267
+ self.class.new(new_spatial_ref_ptr)
268
+ end
269
+
270
+ # @return +true+ if successful, otherwise raises an OGR exception.
271
+ def validate
272
+ ogr_err = FFI::GDAL.OSRValidate(@ogr_spatial_ref_pointer)
273
+
274
+ ogr_err.to_ruby
275
+ end
276
+
277
+ # @return +true+ if successful, otherwise raises an OGR exception.
278
+ def fixup_ordering!
279
+ ogr_err = FFI::GDAL.OSRFixupOrdering(@ogr_spatial_ref_pointer)
280
+
281
+ ogr_err.to_ruby
282
+ end
283
+
284
+ # @return +true+ if successful, otherwise raises an OGR exception.
285
+ def fixup!
286
+ ogr_err = FFI::GDAL.OSRFixup(@ogr_spatial_ref_pointer)
287
+
288
+ ogr_err.to_ruby
289
+ end
290
+
291
+ # @return +true+ if successful, otherwise raises an OGR exception.
292
+ def strip_ct_parameters!
293
+ ogr_err = FFI::GDAL.OSRStripCTParms(@ogr_spatial_ref_pointer)
294
+
295
+ ogr_err.to_ruby
296
+ end
297
+
298
+ # @param name [String] The case-insensitive tree node to look for.
299
+ # @param child [Fixnum] The child of the node to fetch.
300
+ # @return [String, nil]
301
+ def attribute_value(name, child=0)
302
+ FFI::GDAL.OSRGetAttrValue(@ogr_spatial_ref_pointer, name, child)
303
+ end
304
+
305
+ # @return [Hash{unit_name: String, value: Float}]
306
+ def angular_units
307
+ name = FFI::MemoryPointer.new(:string)
308
+ name_ptr = FFI::MemoryPointer.new(:pointer)
309
+ name_ptr.write_pointer(name)
310
+
311
+ value = FFI::GDAL.OSRGetAngularUnits(@ogr_spatial_ref_pointer, name_ptr)
312
+
313
+ { unit_name: name_ptr.read_pointer.read_string, value: value }
314
+ end
315
+
316
+ # @return [Hash{unit_name: String, value: Float}]
317
+ def linear_units
318
+ name = FFI::MemoryPointer.new(:string)
319
+ name_ptr = FFI::MemoryPointer.new(:pointer)
320
+ name_ptr.write_pointer(name)
321
+
322
+ value = FFI::GDAL.OSRGetLinearUnits(@ogr_spatial_ref_pointer, name_ptr)
323
+
324
+ { unit_name: name_ptr.read_pointer.read_string, value: value }
325
+ end
326
+
327
+ # @param target_key [String] I.e. "PROJCS" or "VERT_CS".
328
+ # @return [Hash]
329
+ def target_linear_units(target_key)
330
+ name = FFI::MemoryPointer.new(:string)
331
+ name_ptr = FFI::MemoryPointer.new(:pointer)
332
+ name_ptr.write_pointer(name)
333
+
334
+ value = FFI::GDAL.OSRGetTargetLinearUnits(@ogr_spatial_ref_pointer, target_key, name_ptr)
335
+
336
+ { unit_name: name_ptr.read_pointer.read_string, value: value }
337
+ end
338
+
339
+ # @return [Hash]
340
+ def prime_meridian
341
+ pm = FFI::MemoryPointer.new(:string)
342
+ pm_ptr = FFI::MemoryPointer.new(:pointer)
343
+ pm_ptr.write_pointer(pm)
344
+
345
+ value = FFI::GDAL.OSRGetPrimeMeridian(@ogr_spatial_ref_pointer, pm_ptr)
346
+
347
+ { name: pm_ptr.read_pointer.read_string, value: value }
348
+ end
349
+
350
+ # @param projection_name [String]
351
+ # @return +true+ if successful, otherwise raises an OGR exception.
352
+ def projection=(projection_name)
353
+ ogr_err = FFI::GDAL.OSRSetProjection(@ogr_spatial_ref_pointer, projection_name)
354
+
355
+ ogr_err.to_ruby
356
+ end
357
+
358
+ # Sets the EPSG authority info if possible.
359
+ #
360
+ # @return +true+ if successful, otherwise raises an OGR exception.
361
+ def auto_identify_epsg!
362
+ ogr_err = FFI::GDAL.OSRAutoIdentifyEPSG(@ogr_spatial_ref_pointer)
363
+
364
+ ogr_err.to_ruby
365
+ end
366
+
367
+ # @return [Boolean] +true+ if this coordinate system should be treated as
368
+ # having lat/long coordinate ordering.
369
+ def epsg_treats_as_lat_long?
370
+ FFI::GDAL.OSREPSGTreatsAsLatLong(@ogr_spatial_ref_pointer)
371
+ end
372
+
373
+ # @return [Boolean] +true+ if this coordinate system should be treated as
374
+ # having northing/easting coordinate ordering.
375
+ def epsg_treats_as_northing_easting?
376
+ FFI::GDAL.OSREPSGTreatsAsNorthingEasting(@ogr_spatial_ref_pointer)
377
+ end
378
+
379
+ # @return [Array<Float>]
380
+ def towgs84
381
+ coefficients = FFI::MemoryPointer.new(:double, 7)
382
+ ogr_err = FFI::GDAL.OSRGetTOWGS84(@ogr_spatial_ref_pointer, coefficients, 7)
383
+ ogr_err.to_ruby
384
+
385
+ coefficients.read_array_of_double(0)
386
+ end
387
+
388
+ # @param target_key [String] The partial or complete path to the node to get
389
+ # an authority from ("PROJCS", "GEOCS", "GEOCS|UNIT"). Leave empty to
390
+ # search at the root element.
391
+ # @return [String, nil]
392
+ def authority_code(target_key=nil)
393
+ FFI::GDAL.OSRGetAuthorityCode(@ogr_spatial_ref_pointer, target_key)
394
+ end
395
+
396
+ # @param target_key [String] The partial or complete path to the node to get
397
+ # an authority from ("PROJCS", "GEOCS", "GEOCS|UNIT"). Leave empty to
398
+ # search at the root element.
399
+ # @return [String, nil]
400
+ def authority_name(target_key=nil)
401
+ FFI::GDAL.OSRGetAuthorityName(@ogr_spatial_ref_pointer, target_key)
402
+ end
403
+
404
+ # @param axis_number [Fixnum] The Axis to query (0 or 1.)
405
+ # @param target_key [String]
406
+ # @return [String, nil]
407
+ def axis(axis_number, target_key=nil)
408
+ axis_orientation_ptr = FFI::MemoryPointer.new(:int)
409
+
410
+ name = FFI::GDAL.OSRGetAxis(@ogr_spatial_ref_pointer, target_key, axis_number, axis_orientation_ptr)
411
+ ao_value = axis_orientation_ptr.read_int
412
+
413
+ { name: name, orientation: OGRAxisOrientation[ao_value] }
414
+ end
415
+
416
+ # @return [Float]
417
+ def spheroid_inverse_flattening
418
+ err_ptr = FFI::MemoryPointer.new(:int)
419
+ value = FFI::GDAL.OSRGetInvFlattening(@ogr_spatial_ref_pointer, err_ptr)
420
+ ogr_err = FFI::GDAL::OGRErr[err_ptr.read_int]
421
+
422
+ if ogr_err == :OGRERR_FAILURE && value.is_a?(Float)
423
+ # noinspection RubyQuotedStringsInspection
424
+ warn 'WARN: #spheroid_inverse_flattening received error _and_ a value. Something is fishy...'
425
+ end
426
+
427
+ ogr_err.to_ruby
428
+
429
+ value
430
+ end
431
+
432
+ # @return [Float]
433
+ def semi_major
434
+ err_ptr = FFI::MemoryPointer.new(:int)
435
+ value = FFI::GDAL.OSRGetSemiMajor(@ogr_spatial_ref_pointer, err_ptr)
436
+ ogr_err = FFI::GDAL::OGRErr[err_ptr.read_int]
437
+
438
+ if ogr_err == :OGRERR_FAILURE && value.is_a?(Float)
439
+ # noinspection RubyQuotedStringsInspection
440
+ warn 'WARN: #semi_major received error _and_ a value. Something is fishy...'
441
+ end
442
+
443
+ ogr_err.to_ruby
444
+
445
+ value
446
+ end
447
+
448
+ # @param hemisphere [Symbol] :north or :south.
449
+ # @return [Fixnum] The zone, or 0 if this isn't a UTM definition.
450
+ def utm_zone(hemisphere=:north)
451
+ north = case hemisphere
452
+ when :north then 1
453
+ when :south then 0
454
+ else raise "Unknown hemisphere type #{hemisphere}. Please choose :north or :south."
455
+ end
456
+ north_ptr = FFI::MemoryPointer.new(:bool)
457
+ north_ptr.write_bytes(north.to_s)
458
+
459
+ FFI::GDAL.OSRGetUTMZone(@ogr_spatial_ref_pointer, north_ptr)
460
+ end
461
+
462
+ # @return [Float]
463
+ def semi_minor
464
+ err_ptr = FFI::MemoryPointer.new(:int)
465
+ value = FFI::GDAL.OSRGetSemiMinor(@ogr_spatial_ref_pointer, err_ptr)
466
+ ogr_err = FFI::GDAL::OGRErr[err_ptr.read_int]
467
+
468
+ if ogr_err == :OGRERR_FAILURE && value.is_a?(Float)
469
+ # noinspection RubyQuotedStringsInspection
470
+ warn "WARN: #semi_minor received error _and_ a value. Something is fishy..."
471
+ end
472
+
473
+ ogr_err.to_ruby
474
+
475
+ value
476
+ end
477
+
478
+ # Set the user-visible LOCAL_CS name.
479
+ #
480
+ # @param name [String]
481
+ # @return +true+ if successful, otherwise raises an OGR exception.
482
+ def local_cs=(name)
483
+ ogr_err = FFI::GDAL.OSRSetLocalCS(@ogr_spatial_ref_pointer, name)
484
+
485
+ ogr_err.to_ruby
486
+ end
487
+
488
+ # Set the user-visible GEOCCS name.
489
+ #
490
+ # @param name [String]
491
+ # @return +true+ if successful, otherwise raises an OGR exception.
492
+ def geoccs=(name)
493
+ ogr_err = FFI::GDAL.OSRSetGeocCS(@ogr_spatial_ref_pointer, name)
494
+
495
+ ogr_err.to_ruby
496
+ end
497
+
498
+ # Set the GEOCCS based on a well-knon name.
499
+ #
500
+ # @param name [String]
501
+ # @return +true+ if successful, otherwise raises an OGR exception.
502
+ def well_known_geoccs=(name)
503
+ if GDAL._supported? :OSRSetWellKnownGeocCS
504
+ ogr_err = FFI::GDAL.OSRSetWellKnownGeocCS(@ogr_spatial_ref_pointer, name)
505
+
506
+ ogr_err.to_ruby
507
+ end
508
+ end
509
+
510
+ # Set the user-visible PROJCS name.
511
+ #
512
+ # @param name [String]
513
+ # @return +true+ if successful, otherwise raises an OGR exception.
514
+ def projcs=(name)
515
+ ogr_err = FFI::GDAL.OSRSetProjCS(@ogr_spatial_ref_pointer, name)
516
+
517
+ ogr_err.to_ruby
518
+ end
519
+
520
+ # @return [Hash]
521
+ def to_erm
522
+ projection_name = FFI::MemoryPointer.new(:string)
523
+ datum_name = FFI::MemoryPointer.new(:string)
524
+ units = FFI::MemoryPointer.new(:string)
525
+
526
+ ogr_err = FFI::GDAL.OSRExportToERM(@ogr_spatial_ref_pointer, projection_name,
527
+ datum_name, units)
528
+ ogr_err.to_ruby
529
+
530
+ {
531
+ projection_name: projection_name.read_string,
532
+ datum_name: datum_name.read_string,
533
+ units: units.read_string
534
+ }
535
+ end
536
+
537
+ # @return [Array<String>]
538
+ def to_mapinfo
539
+ return_ptr = FFI::MemoryPointer.new(:string)
540
+ return_ptr_ptr = FFI::MemoryPointer.new(:pointer)
541
+ return_ptr_ptr.write_pointer(return_ptr)
542
+
543
+ ogr_err = FFI::GDAL.OSRExportToMICoordSys(@ogr_spatial_ref_pointer,
544
+ return_ptr_ptr)
545
+ ogr_err.to_ruby
546
+
547
+ return_ptr_ptr.get_array_of_string(0)
548
+ end
549
+
550
+ # @return [Hash]
551
+ def to_pci
552
+ proj = FFI::MemoryPointer.new(:string)
553
+ proj_ptr = FFI::MemoryPointer.new(:pointer)
554
+ proj_ptr.write_pointer(proj)
555
+
556
+ units = FFI::MemoryPointer.new(:string)
557
+ units_ptr = FFI::MemoryPointer.new(:pointer)
558
+ units_ptr.write_pointer(units)
559
+
560
+ prj_params = FFI::MemoryPointer.new(:double)
561
+ prj_params_ptr = FFI::MemoryPointer.new(:pointer)
562
+ prj_params_ptr.write_pointer(prj_params)
563
+
564
+ ogr_err = FFI::GDAL.OSRExportToPCI(@ogr_spatial_ref_pointer, proj_ptr,
565
+ units_ptr, prj_params_ptr)
566
+ ogr_err.to_ruby
567
+
568
+ {
569
+ projection: proj_ptr.read_pointer.read_string,
570
+ units: units_ptr.read_pointer.read_string,
571
+ projection_parameters: prj_params_ptr.read_array_of_double(0)
572
+ }
573
+ end
574
+
575
+ # @return [String]
576
+ def to_proj4
577
+ proj4 = FFI::MemoryPointer.new(:string)
578
+ proj4_ptr = FFI::MemoryPointer.new(:pointer)
579
+ proj4_ptr.write_pointer(proj4)
580
+
581
+ ogr_err = FFI::GDAL.OSRExportToProj4(@ogr_spatial_ref_pointer, proj4_ptr)
582
+ ogr_err.to_ruby
583
+
584
+ proj4_ptr.read_pointer.read_string
585
+ end
586
+
587
+ # @return [Hash]
588
+ def to_usgs
589
+ proj_sys = FFI::MemoryPointer.new(:long)
590
+ zone = FFI::MemoryPointer.new(:long)
591
+ datum = FFI::MemoryPointer.new(:long)
592
+ prj_params = FFI::MemoryPointer.new(:double)
593
+ prj_params_ptr = FFI::MemoryPointer.new(:pointer)
594
+ prj_params_ptr.write_pointer(prj_params)
595
+
596
+ ogr_err = FFI::GDAL.OSRExportToUSGS(@ogr_spatial_ref_pointer, proj_sys,
597
+ zone, prj_params_ptr, datum)
598
+ ogr_err.to_ruby
599
+
600
+ {
601
+ projection_system_code: proj_sys.read_long,
602
+ zone: zone.read_long,
603
+ projection_parameters: prj_params_ptr.read_array_of_double(0),
604
+ datum: datum.read_long
605
+ }
606
+ end
607
+
608
+ # @return [String]
609
+ def to_wkt
610
+ wkt_ptr = FFI::MemoryPointer.new(:string)
611
+ wkt_ptr_ptr = FFI::MemoryPointer.new(:pointer)
612
+ wkt_ptr_ptr.write_pointer(wkt_ptr)
613
+
614
+ ogr_err = FFI::GDAL.OSRExportToWkt(@ogr_spatial_ref_pointer, wkt_ptr_ptr)
615
+ ogr_err.to_ruby
616
+
617
+ wkt_ptr_ptr.read_pointer.read_string
618
+ end
619
+
620
+ # @param simplify [Boolean] +true+ strips off +AXIS+, +AUTHORITY+ and
621
+ # +EXTENSION+ nodes.
622
+ def to_pretty_wkt(simplify=false)
623
+ wkt_ptr = FFI::MemoryPointer.new(:string)
624
+ wkt_ptr_ptr = FFI::MemoryPointer.new(:pointer)
625
+ wkt_ptr_ptr.write_pointer(wkt_ptr)
626
+
627
+ ogr_err = FFI::GDAL.OSRExportToPrettyWkt(@ogr_spatial_ref_pointer,
628
+ wkt_ptr_ptr, simplify)
629
+ ogr_err.to_ruby
630
+
631
+ wkt_ptr_ptr.read_pointer.read_string
632
+ end
633
+
634
+ # @return [Hash]
635
+ def to_xml
636
+ xml_ptr = FFI::MemoryPointer.new(:string)
637
+ xml_ptr_ptr = FFI::MemoryPointer.new(:pointer)
638
+ xml_ptr_ptr.write_pointer(xml_ptr)
639
+ dialect = FFI::MemoryPointer.new(:string)
640
+
641
+ ogr_err = FFI::GDAL.OSRExportToXML(@ogr_spatial_ref_pointer, xml_ptr_ptr,
642
+ dialect)
643
+ ogr_err.to_ruby
644
+
645
+ {
646
+ dialect: dialect.read_string,
647
+ xml: xml_ptr_ptr.get_array_of_string(0)
648
+ }
649
+ end
650
+
651
+ # Converts, in place, to ESRI WKT format.
652
+ def morph_to_esri!
653
+ FFI::GDAL.OSRMorphToESRI(@ogr_spatial_ref_pointer)
654
+ end
655
+
656
+ # Converts, in place, from ESRI WKT format.
657
+ def morph_from_esri!
658
+ FFI::GDAL.OSRMorphFromESRI(@ogr_spatial_ref_pointer)
659
+ end
660
+
661
+ # @return [Boolean]
662
+ def geographic?
663
+ FFI::GDAL.OSRIsGeographic(@ogr_spatial_ref_pointer)
664
+ end
665
+
666
+ # @return [Boolean]
667
+ def local?
668
+ FFI::GDAL.OSRIsLocal(@ogr_spatial_ref_pointer)
669
+ end
670
+
671
+ # @return [Boolean]
672
+ def projected?
673
+ FFI::GDAL.OSRIsProjected(@ogr_spatial_ref_pointer)
674
+ end
675
+
676
+ # @return [Boolean]
677
+ def compound?
678
+ FFI::GDAL.OSRIsCompound(@ogr_spatial_ref_pointer)
679
+ end
680
+
681
+ # @return [Boolean]
682
+ def geocentric?
683
+ FFI::GDAL.OSRIsGeocentric(@ogr_spatial_ref_pointer)
684
+ end
685
+
686
+ # @return [Boolean]
687
+ def vertical?
688
+ FFI::GDAL.OSRIsVertical(@ogr_spatial_ref_pointer)
689
+ end
690
+
691
+ # @param other_spatial_ref [OGR::SpatialReference, FFI::Pointer]
692
+ # @return [Boolean]
693
+ def same?(other_spatial_ref)
694
+ spatial_ref_ptr = GDAL._pointer(other_spatial_ref)
695
+
696
+ FFI::GDAL.OSRIsSame(@ogr_spatial_ref_pointer, spatial_ref_ptr)
697
+ end
698
+ alias_method :==, :same?
699
+
700
+ # @param other_spatial_ref [OGR::SpatialReference, FFI::Pointer]
701
+ # @return [Boolean]
702
+ def geoccs_is_same?(other_spatial_ref)
703
+ spatial_ref_ptr = GDAL._pointer(other_spatial_ref)
704
+
705
+ FFI::GDAL.OSRIsSameGeogCS(@ogr_spatial_ref_pointer, spatial_ref_ptr)
706
+ end
707
+
708
+ # @param other_spatial_ref [OGR::SpatialReference, FFI::Pointer]
709
+ # @return [Boolean]
710
+ def vertcs_is_same?(other_spatial_ref)
711
+ spatial_ref_ptr = GDAL._pointer(other_spatial_ref)
712
+
713
+ FFI::GDAL.OSRIsSameVertCS(@ogr_spatial_ref_pointer, spatial_ref_ptr)
714
+ end
715
+
716
+ # @return [FFI::Pointer] Pointer to an OGRCreateCoordinateTransformation.
717
+ def create_coordinate_transformation(destination_spatial_ref)
718
+ dest_ptr = GDAL._pointer(OGR::SpatialReference, destination_spatial_ref)
719
+
720
+ FFI::GDAL.OGRCreateCoordinateTransformation(@ogr_spatial_ref_pointer, dest_ptr)
721
+ end
722
+ end
723
+ end