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,496 @@
1
+ require 'json'
2
+
3
+ module GDAL
4
+ # Methods not originally supplied with GDAL, but enhance it.
5
+ module DatasetExtensions
6
+
7
+ # Computes NDVI from the red and near-infrared bands in the dataset. Raises
8
+ # a GDAL::RequiredBandNotFound if one of those band types isn't found.
9
+ #
10
+ # @param destination [String] Path to output the new dataset to.
11
+ # @param driver_name [String] The type of dataset to create.
12
+ # @param band_order [Array<String>] The list of band types, i.e. ['red',
13
+ # 'green', 'blue'].
14
+ def extract_ndvi(destination, driver_name: 'GTiff', band_order: nil,
15
+ data_type: :GDT_Float32, remove_negatives: false, no_data_value: -9999.0,
16
+ **options)
17
+ original_bands = if band_order
18
+ bands_with_labels(band_order)
19
+ else
20
+ {
21
+ red: red_band,
22
+ green: green_band,
23
+ blue: blue_band,
24
+ nir: undefined_band
25
+ }
26
+ end
27
+
28
+ red = original_bands[:red]
29
+ nir = original_bands[:nir]
30
+
31
+ if red.nil?
32
+ fail RequiredBandNotFound, 'Red band not found.'
33
+ elsif nir.nil?
34
+ fail RequiredBandNotFound, 'Near-infrared'
35
+ end
36
+
37
+ the_array = calculate_ndvi(red.to_na(data_type), nir.to_na(data_type),
38
+ no_data_value, remove_negatives, data_type)
39
+ driver = GDAL::Driver.by_name(driver_name)
40
+
41
+ driver.create_dataset(destination, raster_x_size, raster_y_size, data_type: data_type, **options) do |ndvi_dataset|
42
+
43
+ ndvi_dataset.geo_transform = geo_transform
44
+ ndvi_dataset.projection = projection
45
+
46
+ ndvi_band = ndvi_dataset.raster_band(1)
47
+ ndvi_band.write_array(the_array, data_type: data_type)
48
+ ndvi_band.no_data_value = no_data_value
49
+ end
50
+ end
51
+
52
+ # Computes GNDVI from the green and near-infrared bands in the dataset.
53
+ # Raises a GDAL::RequiredBandNotFound if one of those band types isn't
54
+ # found.
55
+ #
56
+ # @param destination [String] Path to output the new dataset to.
57
+ # @param driver_name [String] The type of dataset to create.
58
+ # @param band_order [Array<String>] The list of band types, i.e. ['red',
59
+ # 'green', 'blue'].
60
+ def extract_gndvi(destination, driver_name: 'GTiff', band_order: nil,
61
+ data_type: :GDT_Float32, remove_negatives: false, no_data_value: -9999.0,
62
+ **options)
63
+ original_bands = if band_order
64
+ bands_with_labels(band_order)
65
+ else
66
+ {
67
+ red: red_band,
68
+ green: green_band,
69
+ blue: blue_band,
70
+ nir: undefined_band
71
+ }
72
+ end
73
+
74
+ green = original_bands[:green]
75
+ nir = original_bands[:nir]
76
+
77
+ if green.nil?
78
+ fail RequiredBandNotFound, 'Green band not found.'
79
+ elsif nir.nil?
80
+ fail RequiredBandNotFound, 'Near-infrared'
81
+ end
82
+
83
+ the_array = calculate_ndvi(green.to_na(data_type), nir.to_na(data_type),
84
+ no_data_value, remove_negatives, data_type)
85
+ driver = GDAL::Driver.by_name(driver_name)
86
+
87
+ driver.create_dataset(destination, raster_x_size, raster_y_size, data_type: data_type, **options) do |gndvi_dataset|
88
+ gndvi_dataset.geo_transform = geo_transform
89
+ gndvi_dataset.projection = projection
90
+
91
+ gndvi_band = gndvi_dataset.raster_band(1)
92
+ gndvi_band.write_array(the_array, data_type: data_type)
93
+ gndvi_band.no_data_value = no_data_value
94
+ end
95
+ end
96
+
97
+ # Extracts the NIR band and writes to a new file. NOTE: be sure to close
98
+ # the dataset object that gets returned or your data will not get written
99
+ # to the file.
100
+ #
101
+ # @param destination [String] The destination file path.
102
+ # @param band_number [Fixnum] The number of the band that is the NIR band.
103
+ # Remember that raster bands are 1-indexed, not 0-indexed.
104
+ # @param driver_name [String] the GDAL::Driver short name to use for the
105
+ # new dataset.
106
+ # @return [GDAL::Dataset]
107
+ def extract_nir(destination, band_number, driver_name: 'GTiff', data_type: :GDT_Byte)
108
+ driver = GDAL::Driver.by_name(driver_name)
109
+ original_nir_band = raster_band(band_number)
110
+
111
+ driver.create_dataset(destination, raster_x_size, raster_y_size, data_type: data_type) do |nir_dataset|
112
+ nir_dataset.geo_transform = geo_transform
113
+ nir_dataset.projection = projection
114
+
115
+ nir_band = nir_dataset.raster_band(1)
116
+ original_nir_band.copy_whole_raster(nir_band)
117
+ end
118
+ end
119
+
120
+ # Extracts the RGB bands and writes to a new file. NOTE: be sure to close
121
+ # the dataset object that gets returned or your data will not get written
122
+ # to the file.
123
+ #
124
+ # @param destination [String] The destination file path.
125
+ # @param driver_name [String] the GDAL::Driver short name to use for the
126
+ # new dataset.
127
+ # @param band_order [Array<String>] The list of band types, i.e. ['red',
128
+ # 'green', 'blue'].
129
+ # @return [GDAL::Dataset]
130
+ def extract_natural_color(destination, driver_name: 'GTiff', band_order: nil)
131
+ rows = raster_y_size
132
+ columns = raster_x_size
133
+ driver = GDAL::Driver.by_name(driver_name)
134
+
135
+ original_bands = if band_order
136
+ bands_with_labels(band_order)
137
+ else
138
+ {
139
+ red: red_band,
140
+ green: green_band,
141
+ blue: blue_band
142
+ }
143
+ end
144
+
145
+ driver.create_dataset(destination, columns, rows, bands: 3) do |new_dataset|
146
+ new_dataset.geo_transform = geo_transform
147
+ new_dataset.projection = projection
148
+
149
+ new_red_band = new_dataset.raster_band(1)
150
+ original_bands[:red].copy_whole_raster(new_red_band)
151
+
152
+ new_green_band = new_dataset.raster_band(2)
153
+ original_bands[:green].copy_whole_raster(new_green_band)
154
+
155
+ new_blue_band = new_dataset.raster_band(3)
156
+ original_bands[:blue].copy_whole_raster(new_blue_band)
157
+ end
158
+ end
159
+
160
+ # @param red_band_array [NArray]
161
+ # @param nir_band_array [NArray]
162
+ # @param remove_negatives [Fixnum] Value to replace negative values with.
163
+ # @return [NArray]
164
+ def calculate_ndvi(red_band_array, nir_band_array, no_data_value,
165
+ remove_negatives=false, data_type=nil)
166
+
167
+ # convert based on data type
168
+ if data_type != :GDT_Float32
169
+ nir_band_array = nir_band_array.to_type(NArray::DFLOAT)
170
+ red_band_array = red_band_array.to_type(NArray::DFLOAT)
171
+ end
172
+
173
+ numerator = nir_band_array - red_band_array
174
+ denominator = (nir_band_array + red_band_array)
175
+ ndvi = numerator / denominator
176
+
177
+ # Remove NaNs
178
+ 0.upto(ndvi.size - 1) do |i|
179
+ ndvi[i] = no_data_value if ndvi[i].is_a?(Float) && ndvi[i].nan?
180
+ end
181
+
182
+ final_array = case data_type
183
+ when :GDT_Byte
184
+ calculate_ndvi_byte(ndvi)
185
+ when :GDT_UInt16
186
+ calculate_ndvi_uint16(ndvi)
187
+ else
188
+ ndvi
189
+ end
190
+
191
+ remove_negatives ? remove_negatives_from(final_array) : final_array
192
+ end
193
+
194
+ # Map raster bands to a label, as a hash. Useful for when bands don't match
195
+ # the color_interpretation that's returned from GDAL. This simply maps the
196
+ # list of labels you pass in to the raster bands.
197
+ #
198
+ # Valid labels:
199
+ # * Near-infrared: 'N', :nir
200
+ # * Red: 'R', :red
201
+ # * Green: 'G', :green
202
+ # * Blue: 'B', :blue
203
+ # * Alpha: 'A', :alpha
204
+ #
205
+ # @param order [Array<Object>]
206
+ # @return [Hash{<Object> => GDAL::RasterBand}]
207
+ def bands_with_labels(order)
208
+ order.each_with_object({}).each_with_index do |(band_label, obj), i|
209
+ label = case band_label.to_s
210
+ when 'N', 'nir' then :nir
211
+ when 'R', 'red' then :red
212
+ when 'G', 'green' then :green
213
+ when 'B', 'blue' then :blue
214
+ else
215
+ band_label
216
+ end
217
+
218
+ obj[label] = raster_band(i + 1)
219
+ end
220
+ end
221
+
222
+ # @return [Array<GDAL::RasterBand>]
223
+ def raster_bands
224
+ 1.upto(raster_count).map do |i|
225
+ raster_band(i)
226
+ end
227
+ end
228
+
229
+ # Iterates raster bands from 1 to #raster_count and yields them to the given
230
+ # block.
231
+ def each_band
232
+ 1.upto(raster_count) do |i|
233
+ yield(raster_band(i))
234
+ end
235
+ end
236
+
237
+ # Returns the first raster band for which the block returns true. Ex.
238
+ #
239
+ # dataset.find_band do |band|
240
+ # band.color_interpretation == :GCI_RedBand
241
+ # end
242
+ #
243
+ # @return [GDAL::RasterBand]
244
+ def find_band
245
+ each_band do |band|
246
+ result = yield(band)
247
+ return band if result
248
+ end
249
+ end
250
+
251
+ # @return [GDAL::RasterBand]
252
+ def red_band
253
+ band = find_band do |band|
254
+ band.color_interpretation == :GCI_RedBand
255
+ end
256
+
257
+ band.is_a?(GDAL::RasterBand) ? band : nil
258
+ end
259
+
260
+ # @return [GDAL::RasterBand]
261
+ def green_band
262
+ band = find_band do |band|
263
+ band.color_interpretation == :GCI_GreenBand
264
+ end
265
+
266
+ band.is_a?(GDAL::RasterBand) ? band : nil
267
+ end
268
+
269
+ # @return [GDAL::RasterBand]
270
+ def blue_band
271
+ band = find_band do |band|
272
+ band.color_interpretation == :GCI_BlueBand
273
+ end
274
+
275
+ band.is_a?(GDAL::RasterBand) ? band : nil
276
+ end
277
+
278
+ # @return [GDAL::RasterBand]
279
+ def undefined_band
280
+ band = find_band do |band|
281
+ band.color_interpretation == :GCI_Undefined
282
+ end
283
+
284
+ band.is_a?(GDAL::RasterBand) ? band : nil
285
+ end
286
+
287
+ # Creates a OGR::SpatialReference object from the dataset's projection.
288
+ #
289
+ # @return [OGR::SpatialReference]
290
+ def spatial_reference
291
+ return @spatial_reference if @spatial_reference
292
+
293
+ return nil if projection.empty?
294
+
295
+ @spatial_reference = OGR::SpatialReference.new(projection)
296
+ end
297
+
298
+ # Converts raster band number +band_number+ to the vector format
299
+ # +vector_driver_name+. Similar to gdal_polygonize.py. If block format is
300
+ # used, the new DataSource will be closed/flushed when the block returns. If
301
+ # the non-block format is used, you need to call #close on the DataSource.
302
+ #
303
+ # @param file_name [String] Path to write the vector file to.
304
+ # @param vector_driver_name [String] One of OGR::Driver.names.
305
+ # @param geometry_type [FFI::GDAL::OGRwkbGeometryType] The type of geometry
306
+ # to use when turning the raster into a vector image.
307
+ # @param layer_name_prefix [String] Prefix of the name to give the new
308
+ # vector layer.
309
+ # @param band_numbers [Array<Fixnum>,Fixnum] Number of the raster band or
310
+ # bands from this dataset to vectorize. Can be a single Fixnum or array
311
+ # of Fixnums.
312
+ # @return [OGR::DataSource]
313
+ def to_vector(file_name, vector_driver_name, geometry_type: :wkbPolygon,
314
+ layer_name_prefix: 'band_number', band_numbers: [1],
315
+ field_name_prefix: 'field')
316
+ band_numbers = band_numbers.is_a?(Array) ? band_numbers : [band_numbers]
317
+
318
+ ogr_driver = OGR::Driver.by_name(vector_driver_name)
319
+ spatial_ref = OGR::SpatialReference.new(projection)
320
+ spatial_ref.auto_identify_epsg!
321
+
322
+ data_source = ogr_driver.create_data_source(file_name)
323
+ band_numbers.each_with_index do |band_number, i|
324
+ log "Starting to polygonize raster band #{band_number}..."
325
+
326
+ layer_name = "#{layer_name_prefix}-#{band_number}"
327
+ layer = data_source.create_layer(layer_name, geometry_type: geometry_type,
328
+ spatial_reference: spatial_ref)
329
+
330
+ unless layer
331
+ raise OGR::InvalidLayer, "Unable to create layer '#{layer_name}'."
332
+ end
333
+
334
+ field_name = "#{field_name_prefix}#{i}"
335
+ layer.create_field(field_name, :OFTInteger)
336
+
337
+ band = raster_band(band_number)
338
+ band.no_data_value = -9999
339
+
340
+ unless band
341
+ raise GDAL::InvalidBandNumber, "Unknown band number: #{band_number}"
342
+ end
343
+
344
+ pixel_value_field = layer.feature_definition.field_index(field_name)
345
+ band.polygonize(layer, pixel_value_field: pixel_value_field)
346
+ end
347
+
348
+ if block_given?
349
+ yield data_source
350
+ data_source.close
351
+ end
352
+
353
+ data_source
354
+ end
355
+
356
+ # Converts the dataset to an in-memory vector, then creates a OGR::Geometry
357
+ # from its extent (i.e. from the boundary of the image).
358
+ #
359
+ # @return [OGR::Geometry] A convex hull geometry.
360
+ def to_geometry
361
+ raster_data_source = to_vector('memory', 'Memory', geometry_type: :wkbLinearRing)
362
+
363
+ raster_data_source.layer(0).geometry_from_extent
364
+ end
365
+
366
+ # @param wkt_geometry_string [String]
367
+ # @param wkt_srid [Fixnum]
368
+ # @return [Boolean]
369
+ def contains_geometry?(wkt_geometry_string, wkt_srid=4326)
370
+ source_srs = OGR::SpatialReference.new_from_epsg(wkt_srid)
371
+ source_geometry = OGR::Geometry.create_from_wkt(wkt_geometry_string, source_srs)
372
+ @raster_geometry ||= to_geometry
373
+
374
+ coordinate_transformation = OGR::CoordinateTransformation.create(source_srs,
375
+ @raster_geometry.spatial_reference)
376
+ source_geometry.transform!(coordinate_transformation)
377
+
378
+ @raster_geometry.contains? source_geometry
379
+ end
380
+
381
+ def image_warp(destination_file, driver, band_numbers, **warp_options)
382
+ raise NotImplementedError, '#image_warp not yet implemented.'
383
+
384
+ options_ptr = GDAL::Options.pointer(warp_options)
385
+ driver = GDAL::Driver.by_name(driver)
386
+ destination_dataset = driver.create_dataset(destination_file, raster_x_size, raster_y_size)
387
+
388
+ band_numbers = band_numbers.is_a?(Array) ? band_numbers : [band_numbers]
389
+ log "band numbers: #{band_numbers}"
390
+
391
+ bands_ptr = FFI::MemoryPointer.new(:pointer, band_numbers.size)
392
+ bands_ptr.write_array_of_int(band_numbers)
393
+ log "band numbers ptr null? #{bands_ptr.null?}"
394
+
395
+ warp_options_struct = FFI::GDAL::GDALWarpOptions.new
396
+
397
+ warp_options.each do |k, _|
398
+ warp_options_struct[k] = warp_options[k]
399
+ end
400
+
401
+ warp_options[:source_dataset] = c_pointer
402
+ warp_options[:destination_dataset] = destination_dataset.c_pointer
403
+ warp_options[:band_count] = band_numbers.size
404
+ warp_options[:source_bands] = bands_ptr
405
+ warp_options[:transformer] = transformer
406
+ warp_options[:transformer_arg] = transformer_arg
407
+
408
+ log "transformer: #{transformer}"
409
+ error_threshold = 0.0
410
+ order = 0
411
+
412
+ transformer_ptr = FFI::GDAL.GDALCreateGenImgProjTransformer(@dataset_pointer,
413
+ projection,
414
+ destination_dataset.c_pointer,
415
+ destination.projection,
416
+ false,
417
+ error_threshold,
418
+ order)
419
+
420
+ warp_operation = GDAL::WarpOperation.new(warp_options)
421
+ warp_operation.chunk_and_warp_image(0, 0, raster_x_size, raster_y_size)
422
+ transformer.destroy!
423
+ warp_operation.destroy!
424
+
425
+ destination = GDAL::Dataset.new(destination_dataset_ptr)
426
+ destination.close
427
+
428
+ destination
429
+ end
430
+
431
+ # Retrieves pixels from each raster band and converts this to an array of
432
+ # points per pixel. For example:
433
+ #
434
+ # # If the arrays for each band look like:
435
+ # red_band_array = [0, 0, 0]
436
+ # green_band_array = [10, 10, 10]
437
+ # blue_band_array = [99, 99, 99]
438
+ # alpha_band_array = [250, 150, 2]
439
+ #
440
+ # # This array would look like:
441
+ # [[0, 10, 99, 2], [0, 10, 99, 150], [0, 10, 99, 250]]
442
+ # @return NArray
443
+ def to_na
444
+ na = NMatrix.to_na(raster_bands.map { |raster_band| raster_band.to_na })
445
+
446
+ NArray[*na.transpose]
447
+ end
448
+
449
+ def as_json
450
+ {
451
+ dataset: {
452
+ driver: driver.long_name,
453
+ file_list: file_list,
454
+ gcp_count: gcp_count,
455
+ gcp_projection: gcp_projection,
456
+ geo_transform: geo_transform.as_json,
457
+ projection: projection,
458
+ raster_count: raster_count,
459
+ raster_bands: raster_bands.map(&:as_json),
460
+ spatial_reference: spatial_reference.as_json
461
+ },
462
+ metadata: all_metadata
463
+ }
464
+ end
465
+
466
+ def to_json
467
+ as_json.to_json
468
+ end
469
+
470
+ private
471
+
472
+ # @param ndvi [NArray]
473
+ # @return [NArray]
474
+ def calculate_ndvi_byte(ndvi)
475
+ (ndvi + 1) * (127.5)
476
+ end
477
+
478
+ # @param ndvi [NArray]
479
+ # @return [NArray]
480
+ def calculate_ndvi_uint16(ndvi)
481
+ (ndvi + 1) * (2**15 - 1)
482
+ end
483
+
484
+ # Sets any negative values in the NArray to 0.
485
+ #
486
+ # @param narray [NArray]
487
+ # @return [NArray]
488
+ def remove_negatives_from(narray, replace_with=0)
489
+ 0.upto(narray.size - 1) do |i|
490
+ narray[i] = replace_with if narray[i] < 0
491
+ end
492
+
493
+ narray
494
+ end
495
+ end
496
+ end