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
@@ -1,4 +1,6 @@
1
1
  require_relative '../ffi/gdal'
2
+ require_relative '../ffi/ogr/api_h'
3
+ require_relative 'raster_band_extensions'
2
4
  require_relative 'color_table'
3
5
  require_relative 'major_object'
4
6
  require_relative 'raster_attribute_table'
@@ -6,33 +8,29 @@ require 'narray'
6
8
 
7
9
  module GDAL
8
10
  class RasterBand
9
- include FFI::GDAL
10
11
  include MajorObject
12
+ include GDAL::Logger
13
+ include RasterBandExtensions
11
14
 
12
- attr_reader :dataset
15
+ ALL_VALID = 0x01
16
+ PER_DATASET = 0x02
17
+ ALPHA = 0x04
18
+ NODATA = 0x08
13
19
 
14
- # @param dataset [GDAL::Dataset, FFI::Pointer]
15
- # @param band_id [Fixnum] Requried if not passing in +raster_band_pointer+.
16
- # @param raster_band_pointer [FFI::Pointer] Requried if not passing in
17
- # +band_id+.
18
- def initialize(dataset, band_id: nil, raster_band_pointer: nil)
19
- @dataset = if dataset.is_a? GDAL::Dataset
20
- dataset.c_pointer
21
- else
22
- dataset
23
- end
24
-
25
- @gdal_raster_band = if raster_band_pointer
26
- raster_band_pointer
27
- elsif band_id
28
- GDALGetRasterBand(@dataset, band_id)
29
- else
30
- raise 'Must pass in band_id or the raster_band_pointer.'
31
- end
20
+ # @param raster_band [GDAL::RasterBand, FFI::Pointer]
21
+ def initialize(raster_band=nil)
22
+ @raster_band_pointer = GDAL._pointer(GDAL::RasterBand, raster_band)
32
23
  end
33
24
 
34
25
  def c_pointer
35
- @gdal_raster_band
26
+ @raster_band_pointer
27
+ end
28
+
29
+ # @return [Boolean]
30
+ def flush_cache
31
+ cpl_err = FFI::GDAL.GDALFlushRasterCache(@raster_band_pointer)
32
+
33
+ cpl_err.to_bool
36
34
  end
37
35
 
38
36
  # The raster width in pixels.
@@ -41,7 +39,7 @@ module GDAL
41
39
  def x_size
42
40
  return nil if null?
43
41
 
44
- GDALGetRasterBandXSize(@gdal_raster_band)
42
+ FFI::GDAL.GDALGetRasterBandXSize(@raster_band_pointer)
45
43
  end
46
44
 
47
45
  # The raster height in pixels.
@@ -50,7 +48,7 @@ module GDAL
50
48
  def y_size
51
49
  return nil if null?
52
50
 
53
- GDALGetRasterBandYSize(@gdal_raster_band)
51
+ FFI::GDAL.GDALGetRasterBandYSize(@raster_band_pointer)
54
52
  end
55
53
 
56
54
  # The type of access to the raster band this object currently has.
@@ -59,38 +57,66 @@ module GDAL
59
57
  def access_flag
60
58
  return nil if null?
61
59
 
62
- GDALGetRasterAccess(@gdal_raster_band)
60
+ FFI::GDAL.GDALGetRasterAccess(@raster_band_pointer)
63
61
  end
64
62
 
65
63
  # The number of band within the associated dataset that this band
66
64
  # represents.
67
65
  #
68
66
  # @return [Fixnum]
69
- def band_number
67
+ def number
70
68
  return nil if null?
71
69
 
72
- GDALGetBandNumber(@gdal_raster_band)
70
+ FFI::GDAL.GDALGetBandNumber(@raster_band_pointer)
71
+ end
72
+
73
+ # @return [GDAL::Dataset, nil]
74
+ def dataset
75
+ return @dataset if @dataset
76
+
77
+ dataset_ptr = FFI::GDAL.GDALGetBandDataset(@raster_band_pointer)
78
+ return nil if dataset_ptr.null?
79
+
80
+ @dataset = GDAL::Dataset.new(dataset_ptr)
73
81
  end
74
82
 
75
83
  # @return [Symbol] One of FFI::GDAL::GDALColorInterp.
76
84
  def color_interpretation
77
- GDALGetRasterColorInterpretation(@gdal_raster_band)
85
+ FFI::GDAL.GDALGetRasterColorInterpretation(@raster_band_pointer)
86
+ end
87
+
88
+ # @return [Boolean]
89
+ def color_interpretation=(new_color_interp)
90
+ cpl_err = FFI::GDAL.GDALSetRasterColorInterpretation(@raster_band_pointer,
91
+ new_color_interp)
92
+
93
+ cpl_err.to_bool
78
94
  end
79
95
 
80
96
  # @return [GDAL::ColorTable]
81
97
  def color_table
82
- gdal_color_table = GDALGetRasterColorTable(@gdal_raster_band)
98
+ return @color_table if @color_table
99
+
100
+ gdal_color_table = FFI::GDAL.GDALGetRasterColorTable(@raster_band_pointer)
83
101
  return nil if gdal_color_table.null?
84
102
 
85
- @color_table ||= ColorTable.new(@gdal_raster_band,
86
- color_table_pointer: gdal_color_table)
103
+ @color_table = ColorTable.new(gdal_color_table)
104
+ end
105
+
106
+ # @param new_color_table [GDAL::ColorTable]
107
+ def color_table=(new_color_table)
108
+ color_table_pointer = GDAL._pointer(GDAL::ColorTable, new_color_table)
109
+ cpl_err = FFI::GDAL.GDALSetRasterColorTable(@raster_band_pointer, color_table_pointer)
110
+ @color_table = ColorTable.new(color_table_pointer)
111
+
112
+ cpl_err.to_bool
87
113
  end
88
114
 
89
115
  # The pixel data type for this band.
90
116
  #
91
117
  # @return [Symbol] One of FFI::GDAL::GDALDataType.
92
118
  def data_type
93
- GDALGetRasterDataType(@gdal_raster_band)
119
+ FFI::GDAL.GDALGetRasterDataType(@raster_band_pointer)
94
120
  end
95
121
 
96
122
  # The natural block size is the block size that is most efficient for
@@ -101,14 +127,14 @@ module GDAL
101
127
  def block_size
102
128
  x_pointer = FFI::MemoryPointer.new(:int)
103
129
  y_pointer = FFI::MemoryPointer.new(:int)
104
- GDALGetBlockSize(@gdal_raster_band, x_pointer, y_pointer)
130
+ FFI::GDAL.GDALGetBlockSize(@raster_band_pointer, x_pointer, y_pointer)
105
131
 
106
132
  { x: x_pointer.read_int, y: y_pointer.read_int }
107
133
  end
108
134
 
109
135
  # @return [Array<String>]
110
136
  def category_names
111
- names = GDALGetRasterCategoryNames(@gdal_raster_band)
137
+ names = FFI::GDAL.GDALGetRasterCategoryNames(@raster_band_pointer)
112
138
  return [] if names.null?
113
139
 
114
140
  names.get_array_of_string(0)
@@ -128,7 +154,7 @@ module GDAL
128
154
  names_pointer[i].put_pointer(0, ptr)
129
155
  end
130
156
 
131
- cpl_err = GDALSetRasterCategoryNames(@gdal_raster_band, names_pointer)
157
+ cpl_err = FFI::GDAL.GDALSetRasterCategoryNames(@raster_band_pointer, names_pointer)
132
158
 
133
159
  cpl_err.to_ruby(warning: [])
134
160
  end
@@ -140,19 +166,29 @@ module GDAL
140
166
  # @return [Hash{value => Float, is_associated => Boolean}]
141
167
  def no_data_value
142
168
  associated = FFI::MemoryPointer.new(:bool)
143
- value = GDALGetRasterNoDataValue(@gdal_raster_band, associated)
169
+ value = FFI::GDAL.GDALGetRasterNoDataValue(@raster_band_pointer, associated)
144
170
 
145
171
  { value: value, is_associated: associated.read_bytes(1).to_bool }
146
172
  end
147
173
 
174
+ # Sets the no data value for this band.
175
+ #
176
+ # @param value [Float]
177
+ # @return [Boolean]
178
+ def no_data_value=(value)
179
+ cpl_err = FFI::GDAL.GDALSetRasterNoDataValue(@raster_band_pointer, value)
180
+
181
+ cpl_err.to_bool
182
+ end
183
+
148
184
  # @return [Fixnum]
149
185
  def overview_count
150
- GDALGetOverviewCount(@gdal_raster_band)
186
+ FFI::GDAL.GDALGetOverviewCount(@raster_band_pointer)
151
187
  end
152
188
 
153
189
  # @return [Boolean]
154
190
  def arbitrary_overviews?
155
- GDALHasArbitraryOverviews(@gdal_raster_band).zero? ? false : true
191
+ FFI::GDAL.GDALHasArbitraryOverviews(@raster_band_pointer).zero? ? false : true
156
192
  end
157
193
 
158
194
  # @param index [Fixnum] Must be between 0 and (#overview_count - 1).
@@ -160,10 +196,10 @@ module GDAL
160
196
  def overview(index)
161
197
  return nil if overview_count.zero?
162
198
 
163
- overview_pointer = GDALGetOverview(@gdal_raster_band, index)
199
+ overview_pointer = FFI::GDAL.GDALGetOverview(@raster_band_pointer, index)
164
200
  return nil if overview_pointer.null?
165
201
 
166
- self.class.new(dataset, raster_band_pointer: overview_pointer)
202
+ self.class.new(overview_pointer)
167
203
  end
168
204
 
169
205
  # @param desired_samples [Fixnum] The returned band will have at least this
@@ -171,23 +207,23 @@ module GDAL
171
207
  # @return [GDAL::RasterBand] An optimal overview or the same raster band if
172
208
  # the raster band has no overviews.
173
209
  def raster_sample_overview(desired_samples=0)
174
- band_pointer = GDALGetRasterSampleOverview(@gdal_raster_band, desired_samples)
210
+ band_pointer = FFI::GDAL.GDALGetRasterSampleOverview(@raster_band_pointer, desired_samples)
175
211
  return nil if band_pointer.null?
176
212
 
177
- self.class.new(dataset, raster_band_pointer: band_pointer)
213
+ self.class.new(band_pointer)
178
214
  end
179
215
 
180
216
  # @return [GDAL::RasterBand]
181
217
  def mask_band
182
- band_pointer = GDALGetMaskBand(@gdal_raster_band)
218
+ band_pointer = FFI::GDAL.GDALGetMaskBand(@raster_band_pointer)
183
219
  return nil if band_pointer.null?
184
220
 
185
- self.class.new(dataset, raster_band_pointer: band_pointer)
221
+ self.class.new(band_pointer)
186
222
  end
187
223
 
188
224
  # @return [Array<Symbol>]
189
225
  def mask_flags
190
- flag_list = GDALGetMaskFlags(@gdal_raster_band).to_s(2).scan(/\d/)
226
+ flag_list = FFI::GDAL.GDALGetMaskFlags(@raster_band_pointer).to_s(2).scan(/\d/)
191
227
  flags = []
192
228
 
193
229
  flag_list.reverse.each_with_index do |flag, i|
@@ -205,6 +241,24 @@ module GDAL
205
241
  flags
206
242
  end
207
243
 
244
+ # @return [Boolean]
245
+ def create_mask_band(flags)
246
+ cpl_err = FFI::GDAL.GDALCreateMaskBand(@raster_band_pointer, flags)
247
+
248
+ cpl_err.to_bool
249
+ end
250
+
251
+ # Fill this band with constant value. Useful for clearing a band and
252
+ # setting to a default value.
253
+ #
254
+ # @param real_value [Float]
255
+ # @param imaginary_value [Float]
256
+ def fill(real_value, imaginary_value=0)
257
+ cpl_err = FFI::GDAL.GDALFillRaster(@raster_band_pointer, real_value, imaginary_value)
258
+
259
+ cpl_err.to_bool
260
+ end
261
+
208
262
  # Returns minimum, maximum, mean, and standard deviation of all pixel values
209
263
  # in this band.
210
264
  #
@@ -212,7 +266,7 @@ module GDAL
212
266
  # overviews or a subset of all tiles.
213
267
  # @param force [Boolean] If +false+, stats will only be returned if the
214
268
  # calculating can be done without rescanning the image.
215
- # @return [Hash{mininum: Float, maximum: Float, mean: Float,
269
+ # @return [Hash{minimum: Float, maximum: Float, mean: Float,
216
270
  # standard_deviation: Float}]
217
271
  def statistics(approx_ok=true, force=true)
218
272
  min = FFI::MemoryPointer.new(:double)
@@ -220,7 +274,7 @@ module GDAL
220
274
  mean = FFI::MemoryPointer.new(:double)
221
275
  standard_deviation = FFI::MemoryPointer.new(:double)
222
276
 
223
- cpl_err = GDALGetRasterStatistics(@gdal_raster_band,
277
+ cpl_err = FFI::GDAL.GDALGetRasterStatistics(@raster_band_pointer,
224
278
  approx_ok,
225
279
  force,
226
280
  min,
@@ -228,8 +282,6 @@ module GDAL
228
282
  mean,
229
283
  standard_deviation)
230
284
 
231
- minimum = min.null? ? 0.0 : min.read_double
232
-
233
285
  case cpl_err.to_ruby
234
286
  when :none, :debug
235
287
  {
@@ -240,6 +292,7 @@ module GDAL
240
292
  }
241
293
  when :warning then {}
242
294
  when :failure, :fatal then raise CPLErrFailure
295
+ else raise CPLErrFailure
243
296
  end
244
297
  end
245
298
 
@@ -256,15 +309,17 @@ module GDAL
256
309
  # @return [Hash{value => Float, is_meaningful => Boolean}]
257
310
  def scale
258
311
  meaningful = FFI::MemoryPointer.new(:bool)
259
- result = GDALGetRasterScale(@gdal_raster_band, meaningful)
312
+ result = FFI::GDAL.GDALGetRasterScale(@raster_band_pointer, meaningful)
260
313
 
261
314
  { value: result, is_meaningful: meaningful.read_bytes(1).to_bool }
262
315
  end
263
316
 
264
317
  # @param new_scale [Float]
265
- # @return [FFI::GDAL::CPLErr]
318
+ # @return [Boolean]
266
319
  def scale=(new_scale)
267
- GDALSetRasterScale(@gdal_raster_band, new_scale.to_f)
320
+ cpl_err = FFI::GDAL.GDALSetRasterScale(@raster_band_pointer, new_scale.to_f)
321
+
322
+ cpl_err.to_bool
268
323
  end
269
324
 
270
325
  # This value (in combination with the GetScale() value) is used to
@@ -280,28 +335,32 @@ module GDAL
280
335
  # @return [Hash{value => Float, is_meaningful => Boolean}]
281
336
  def offset
282
337
  meaningful = FFI::MemoryPointer.new(:bool)
283
- result = GDALGetRasterOffset(@gdal_raster_band, meaningful)
338
+ result = FFI::GDAL.GDALGetRasterOffset(@raster_band_pointer, meaningful)
284
339
 
285
340
  { value: result, is_meaningful: meaningful.read_bytes(1).to_bool }
286
341
  end
287
342
 
288
343
  # @param new_offset [Float]
289
- # @return [FFI::GDAL::CPLErr]
344
+ # @return [Boolean]
290
345
  def offset=(new_offset)
291
- GDALSetRasterOffset(@gdal_raster_band, new_offset)
346
+ cpl_err = FFI::GDAL.GDALSetRasterOffset(@raster_band_pointer, new_offset)
347
+
348
+ cpl_err.to_bool
292
349
  end
293
350
 
294
351
  # @return [String]
295
352
  def unit_type
296
- GDALGetRasterUnitType(@gdal_raster_band)
353
+ FFI::GDAL.GDALGetRasterUnitType(@raster_band_pointer)
297
354
  end
298
355
 
299
356
  # @param new_unit_type [String] "" indicates unknown, "m" is meters, "ft"
300
357
  # is feet; other non-standard values are allowed.
301
- # @return [FFI::GDAL::CPLErr]
358
+ # @return [Boolean]
302
359
  def unit_type=(new_unit_type)
303
360
  if defined? FFI::GDAL::GDALSetRasterUnitType
304
- GDALSetRasterUnitType(@gdal_raster_band, new_unit_type)
361
+ cpl_err = FFI::GDAL.GDALSetRasterUnitType(@raster_band_pointer, new_unit_type)
362
+
363
+ cpl_err.to_bool
305
364
  else
306
365
  warn "GDALSetRasterUnitType is not defined. Can't call RasterBand#unit_type="
307
366
  end
@@ -309,11 +368,21 @@ module GDAL
309
368
 
310
369
  # @return [GDAL::RasterAttributeTable]
311
370
  def default_raster_attribute_table
312
- rat_pointer = GDALGetDefaultRAT(c_pointer)
371
+ return @default_raster_attribute_table if @default_raster_attribute_table
372
+
373
+ rat_pointer = FFI::GDAL.GDALGetDefaultRAT(@raster_band_pointer)
313
374
  return nil if rat_pointer.null?
314
375
 
315
- GDAL::RasterAttributeTable.new(c_pointer,
316
- raster_attribute_table_pointer: rat_pointer)
376
+ @default_raster_attribute_table = GDAL::RasterAttributeTable.new(rat_pointer)
377
+ end
378
+
379
+ # @return [GDAL::RasterAttributeTable]
380
+ def default_raster_attribute_table=(rat_table)
381
+ rat_table_ptr = GDAL._pointer(GDAL::RasterAttributeTable, rat_table)
382
+ cpl_err = FFI::GDAL.GDALSetDefaultRAT(@raster_band_pointer, rat_table_ptr)
383
+ @default_raster_attribute_table = GDAL::RasterAttributeTable.new(rat_table_pointer)
384
+
385
+ cpl_err.to_bool
317
386
  end
318
387
 
319
388
  # Gets the default raster histogram. Results are returned as a Hash so some
@@ -364,7 +433,7 @@ module GDAL
364
433
  histogram_pointer = FFI::MemoryPointer.new(:pointer)
365
434
  progress_proc = block || nil
366
435
 
367
- cpl_err = GDALGetDefaultHistogram(@gdal_raster_band,
436
+ cpl_err = FFI::GDAL.GDALGetDefaultHistogram(@raster_band_pointer,
368
437
  min_pointer,
369
438
  max_pointer,
370
439
  buckets_pointer,
@@ -374,6 +443,7 @@ module GDAL
374
443
  nil
375
444
  )
376
445
 
446
+ cpl_err.to_bool
377
447
  min = min_pointer.read_double
378
448
  max = max_pointer.read_double
379
449
  buckets = buckets_pointer.read_int
@@ -384,7 +454,7 @@ module GDAL
384
454
  histogram_pointer.get_pointer(0).read_array_of_int(buckets)
385
455
  end
386
456
 
387
- formated_buckets(cpl_err, min, max, buckets, totals)
457
+ formatted_buckets(cpl_err, min, max, buckets, totals)
388
458
  end
389
459
 
390
460
  # Computes a histogram using the given inputs. If you just want the default
@@ -395,7 +465,7 @@ module GDAL
395
465
  # @param buckets [Fixnum]
396
466
  # @param include_out_of_range [Boolean]
397
467
  # @param approx_ok [Boolean]
398
- # @param block [Proc] No required, but can be used to output progess info
468
+ # @param block [Proc] No required, but can be used to output progress info
399
469
  # during processing.
400
470
  #
401
471
  # @yieldparam completion [Float] The ration completed as a decimal.
@@ -410,7 +480,7 @@ module GDAL
410
480
  histogram_pointer = FFI::MemoryPointer.new(:pointer, buckets)
411
481
  progress_proc = block || nil
412
482
 
413
- cpl_err = GDALGetRasterHistogram(@gdal_raster_band,
483
+ cpl_err = FFI::GDAL.GDALGetRasterHistogram(@raster_band_pointer,
414
484
  min.to_f,
415
485
  max.to_f,
416
486
  buckets,
@@ -420,26 +490,57 @@ module GDAL
420
490
  progress_proc,
421
491
  'doing things')
422
492
 
493
+ cpl_err.to_bool
494
+
423
495
  totals = if buckets.zero?
424
496
  []
425
497
  else
426
498
  histogram_pointer.read_array_of_int(buckets)
427
499
  end
428
500
 
429
- formated_buckets(cpl_err, min, max, buckets, totals)
501
+ formatted_buckets(cpl_err, min, max, buckets, totals)
502
+ end
503
+
504
+ # Copies the contents of one raster to another similarly configure band.
505
+ # The two bands must have the same width and height but do not have to be
506
+ # the same data type.
507
+ #
508
+ # Options:
509
+ # * :compressed
510
+ # * 'YES': forces alignment on the destination_band to acheive the best
511
+ # compression.
512
+ #
513
+ # @param destination_band [GDAL::RasterBand]
514
+ # @param options [Hash]
515
+ # @option options compress [String] Only 'YES' is supported.
516
+ # @return [Boolean]
517
+ def copy_whole_raster(destination_band, **options, &progress)
518
+ destination_pointer = GDAL._pointer(GDAL::RasterBand, destination_band)
519
+ options_ptr = GDAL::Options.pointer(options)
520
+ cpl_err = FFI::GDAL.GDALRasterBandCopyWholeRaster(@raster_band_pointer,
521
+ destination_pointer,
522
+ options_ptr,
523
+ progress,
524
+ nil)
525
+
526
+ cpl_err.to_bool
430
527
  end
431
528
 
432
- # TODO: Something about the pointer allocation smells here...
433
- #def read(x_offset: 0, y_offset: 0, x_size: x_size, y_size: 1, pixel_space: 0, line_space: 0)
434
- def readlines
529
+ # Reads the raster line-by-line and returns as an NArray. Will yield each
530
+ # line and the line number if a block is given.
531
+ #
532
+ # @yieldparam pixel_line [Array]
533
+ # @yieldparam line_number [Fixnum]
534
+ # @return [NArray]
535
+ def readlines(data_type: :GDT_Byte)
435
536
  x_offset = 0
436
537
  line_size = 1
437
538
  pixel_space = 0
438
539
  line_space = 0
439
- scan_line = FFI::MemoryPointer.new(:float, x_size)
540
+ scan_line = GDAL._pointer_from_data_type(data_type, x_size)
440
541
 
441
- 0.upto(y_size - 1) do |y|
442
- GDALRasterIO(@gdal_raster_band,
542
+ the_array = 0.upto(y_size - 1).map do |y|
543
+ FFI::GDAL.GDALRasterIO(@raster_band_pointer,
443
544
  :GF_Read,
444
545
  x_offset,
445
546
  y,
@@ -453,8 +554,18 @@ module GDAL
453
554
  line_space
454
555
  )
455
556
 
456
- yield scan_line.read_array_of_float(x_size).dup
557
+ line_array = if data_type == :GDT_Byte
558
+ scan_line.read_array_of_uint8(x_size)
559
+ else
560
+ scan_line.read_array_of_float(x_size)
561
+ end
562
+
563
+ yield(line_array, y) if block_given?
564
+
565
+ line_array
457
566
  end
567
+
568
+ NArray.to_na(the_array)
458
569
  end
459
570
 
460
571
  # @param pixel_array [NArray] The NArray of pixels.
@@ -474,13 +585,15 @@ module GDAL
474
585
 
475
586
  columns_to_write = x_size - x_offset
476
587
  lines_to_write = y_size - y_offset
477
- scan_line = FFI::MemoryPointer.new(:float, columns_to_write)
588
+ scan_line = GDAL._pointer_from_data_type(data_type, columns_to_write)
478
589
 
479
590
  (y_offset).upto(lines_to_write - 1) do |y|
480
591
  pixels = pixel_array[true, y]
481
- scan_line.write_array_of_float(pixels.to_a)
592
+ ffi_type = GDAL._gdal_data_type_to_ffi(data_type)
593
+ meth = "write_array_of_#{ffi_type}".to_sym
594
+ scan_line.send(meth, pixels.to_a)
482
595
 
483
- GDALRasterIO(@gdal_raster_band,
596
+ FFI::GDAL.GDALRasterIO(@raster_band_pointer,
484
597
  :GF_Write,
485
598
  x_offset, # nXOff
486
599
  y,
@@ -495,7 +608,7 @@ module GDAL
495
608
  )
496
609
  end
497
610
 
498
- GDALFlushRasterCache(@gdal_raster_band)
611
+ flush_cache
499
612
  end
500
613
 
501
614
  # Read a block of image data, more efficiently than #read. Doesn't
@@ -507,25 +620,19 @@ module GDAL
507
620
  # top-most block, 1 the next block, etc.
508
621
  def read_block(x_offset, y_offset, image_buffer=nil)
509
622
  image_buffer ||= FFI::MemoryPointer.new(:void)
510
- #puts "x offset: #{x_offset}"
511
- #puts "y offset: #{y_offset}"
623
+ result = FFI::GDAL.GDALReadBlock(@raster_band_pointer, x_offset, y_offset, image_buffer)
512
624
 
513
- result = GDALReadBlock(@gdal_raster_band, x_offset, y_offset, image_buffer)
514
-
515
- if result == :none
516
- elsif result == :failure
517
-
518
- end
625
+ result.to_bool
519
626
  end
520
627
 
521
628
  # The minimum and maximum values for this band.
522
629
  #
523
630
  # @return [Array{min => Float, max => Float}]
524
- def compute_min_max
631
+ def min_max
525
632
  @min_max = if minimum_value[:value] && maximum_value[:value]
526
633
  min_max = FFI::MemoryPointer.new(:double, 2)
527
634
  min_max.put_array_of_double 0, [minimum_value[:value], maximum_value[:value]]
528
- GDALComputeRasterMinMax(@gdal_raster_band, 1, min_max)
635
+ FFI::GDAL.GDALComputeRasterMinMax(@raster_band_pointer, 1, min_max)
529
636
 
530
637
  [min_max[0].read_double, min_max[1].read_double]
531
638
  else
@@ -536,7 +643,7 @@ module GDAL
536
643
  # @return [Hash{value => Float, it_tight => Boolean}]
537
644
  def minimum_value
538
645
  is_tight = FFI::MemoryPointer.new(:bool)
539
- value = GDALGetRasterMinimum(@gdal_raster_band, is_tight)
646
+ value = FFI::GDAL.GDALGetRasterMinimum(@raster_band_pointer, is_tight)
540
647
 
541
648
  { value: value, is_tight: is_tight.read_bytes(1).to_bool }
542
649
  end
@@ -544,22 +651,43 @@ module GDAL
544
651
  # @return [Hash{value => Float, it_tight => Boolean}]
545
652
  def maximum_value
546
653
  is_tight = FFI::MemoryPointer.new(:double)
547
- value = GDALGetRasterMaximum(@gdal_raster_band, is_tight)
654
+ value = FFI::GDAL.GDALGetRasterMaximum(@raster_band_pointer, is_tight)
548
655
 
549
656
  { value: value, is_tight: is_tight.read_bytes(1).to_bool }
550
657
  end
551
658
 
552
- # Iterates through all lines and builds an NArray of pixels.
659
+ # Creates vector polygons for all connected regions of pixels in the raster
660
+ # that share a common pixel value.
553
661
  #
554
- # @return [NArray]
555
- def to_a
556
- lines = []
557
-
558
- readlines do |line|
559
- lines << line
560
- end
662
+ # @param layer [OGR::Layer, FFI::Pointer] The layer to write the polygons
663
+ # to.
664
+ # @param mask_band [GDAL::RasterBand, FFI::Pointer] Optional band, where all
665
+ # pixels in the mask with a value other than zero will be considered
666
+ # suitable for collection as polygons.
667
+ # @param pixel_value_field [Fixnum] Index of the feature attribute into
668
+ # which the pixel value of the polygon should be written.
669
+ # @param options [Hash]
670
+ # @param progress [Proc]
671
+ # @return [OGR::Layer]
672
+ def polygonize(layer, mask_band: nil, pixel_value_field: -1, **options, &progress)
673
+ mask_band_ptr = GDAL._pointer(GDAL::RasterBand, mask_band, false)
674
+
675
+ layer_ptr = GDAL._pointer(OGR::Layer, layer)
676
+ raise "Invalid layer: #{layer.inspect}" if layer_ptr.null?
677
+
678
+ options_ptr = GDAL::Options.pointer(options)
679
+
680
+ cpl_err = FFI::GDAL.GDALFPolygonize(@raster_band_pointer, # hSrcBand
681
+ mask_band_ptr, # hMaskBand
682
+ layer_ptr, # hOutLayer
683
+ pixel_value_field, # iPixValField
684
+ options_ptr, # papszOptions
685
+ progress, # pfnProgress
686
+ nil # pProgressArg
687
+ )
688
+ cpl_err.to_ruby
561
689
 
562
- NArray.to_na(lines)
690
+ OGR::Layer.new(layer_ptr)
563
691
  end
564
692
 
565
693
  #---------------------------------------------------------------------------
@@ -568,7 +696,7 @@ module GDAL
568
696
 
569
697
  private
570
698
 
571
- def formated_buckets(cpl_err, min, max, buckets, totals)
699
+ def formatted_buckets(cpl_err, min, max, buckets, totals)
572
700
  case cpl_err.to_ruby
573
701
  when :none
574
702
  {
@@ -579,8 +707,8 @@ module GDAL
579
707
  }
580
708
  when :warning then return nil
581
709
  when :failure then raise CPLError
710
+ else raise CPLError
582
711
  end
583
712
  end
584
-
585
713
  end
586
714
  end