Class: GDAL::Dataset

Inherits:
Object
  • Object
show all
Includes:
FFI::GDAL, MajorObject
Defined in:
lib/ffi-gdal/dataset.rb

Overview

A set of associated raster bands and info common to them all. It’s also responsible for the georeferencing transform and coordinate system definition of all bands.

Constant Summary collapse

ACCESS_FLAGS =
{
  'r' => :GA_ReadOnly,
  'w' => :GA_Update
}

Constants included from FFI::GDAL

FFI::GDAL::ALTER_ALL_FLAG, FFI::GDAL::ALTER_NAME_FLAG, FFI::GDAL::ALTER_TYPE_FLAG, FFI::GDAL::ALTER_WIDTH_PRECISION_FLAG, FFI::GDAL::AppDefined, FFI::GDAL::AssertionFailed, FFI::GDAL::CPLES_BackslashQuotable, FFI::GDAL::CPLES_CSV, FFI::GDAL::CPLES_SQL, FFI::GDAL::CPLES_URL, FFI::GDAL::CPLES_XML, FFI::GDAL::CPLES_XML_BUT_QUOTES, FFI::GDAL::CPLE_WrongFormat, FFI::GDAL::CPLErr, FFI::GDAL::CPLValueType, FFI::GDAL::CPL_ENC_ASCII, FFI::GDAL::CPL_ENC_ISO8859_1, FFI::GDAL::CPL_ENC_LOCALE, FFI::GDAL::CPL_ENC_UCS2, FFI::GDAL::CPL_ENC_UCS4, FFI::GDAL::CPL_ENC_UTF16, FFI::GDAL::CPL_ENC_UTF8, FFI::GDAL::CSLT_ALLOWEMPTYTOKENS, FFI::GDAL::CSLT_HONOURSTRINGS, FFI::GDAL::CSLT_PRESERVEESCAPES, FFI::GDAL::CSLT_PRESERVEQUOTES, FFI::GDAL::CSLT_STRIPENDSPACES, FFI::GDAL::CSLT_STRIPLEADSPACES, FFI::GDAL::FileIO, FFI::GDAL::GDALAccess, FFI::GDAL::GDALAsyncStatusType, FFI::GDAL::GDALColorInterp, FFI::GDAL::GDALDataType, FFI::GDAL::GDALMD_AOP_AREA, FFI::GDAL::GDALMD_AOP_POINT, FFI::GDAL::GDALMD_AREA_OR_POINT, FFI::GDAL::GDALPaletteInterp, FFI::GDAL::GDALRATFieldType, FFI::GDAL::GDALRATFieldUsage, FFI::GDAL::GDALRWFlag, FFI::GDAL::GDALTileOrganization, FFI::GDAL::GDAL_DCAP_CREATE, FFI::GDAL::GDAL_DCAP_CREATECOPY, FFI::GDAL::GDAL_DCAP_OPEN, FFI::GDAL::GDAL_DCAP_RASTER, FFI::GDAL::GDAL_DCAP_VECTOR, FFI::GDAL::GDAL_DCAP_VIRTUALIO, FFI::GDAL::GDAL_DMD_CREATIONDATATYPES, FFI::GDAL::GDAL_DMD_CREATIONOPTIONLIST, FFI::GDAL::GDAL_DMD_EXTENSION, FFI::GDAL::GDAL_DMD_EXTENSIONS, FFI::GDAL::GDAL_DMD_HELPTOPIC, FFI::GDAL::GDAL_DMD_LONGNAME, FFI::GDAL::GDAL_DMD_MIMETYPE, FFI::GDAL::GDAL_DMD_OPTIONLIST, FFI::GDAL::GDAL_DMD_SUBDATASETS, FFI::GDAL::GDAL_DS_LAYER_CREATIONOPTIONLIST, FFI::GDAL::GDAL_OF_ALL, FFI::GDAL::GDAL_OF_RASTER, FFI::GDAL::GDAL_OF_READONLY, FFI::GDAL::GDAL_OF_SHARED, FFI::GDAL::GDAL_OF_UPDATE, FFI::GDAL::GDAL_OF_VECTOR, FFI::GDAL::GDAL_OF_VERBOSE_ERROR, FFI::GDAL::GMF_ALL_VALID, FFI::GDAL::GMF_ALPHA, FFI::GDAL::GMF_NODATA, FFI::GDAL::GMF_PER_DATASET, FFI::GDAL::IllegalArg, FFI::GDAL::NoWriteAccess, FFI::GDAL::None, FFI::GDAL::NotSupported, FFI::GDAL::ODrCCreateDataSource, FFI::GDAL::ODrCDeleteDataSource, FFI::GDAL::ODsCCreateGeomFieldAfterCreateLayer, FFI::GDAL::ODsCCreateLayer, FFI::GDAL::ODsCDeleteLayer, FFI::GDAL::OGRAxisOrientation, FFI::GDAL::OGRDatumType, FFI::GDAL::OGRERR_CORRUPT_DATA, FFI::GDAL::OGRERR_FAILURE, FFI::GDAL::OGRERR_INVALID_HANDLE, FFI::GDAL::OGRERR_NONE, FFI::GDAL::OGRERR_NOT_ENOUGH_DATA, FFI::GDAL::OGRERR_NOT_ENOUGH_MEMORY, FFI::GDAL::OGRERR_UNSUPPORTED_GEOMETRY_TYPE, FFI::GDAL::OGRERR_UNSUPPORTED_OPERATION, FFI::GDAL::OGRERR_UNSUPPORTED_SRS, FFI::GDAL::OGRFieldType, FFI::GDAL::OGRJustification, FFI::GDAL::OGRNullFID, FFI::GDAL::OGRStyleToolClassID, FFI::GDAL::OGRStyleToolParamBrushID, FFI::GDAL::OGRStyleToolParamLabelID, FFI::GDAL::OGRStyleToolParamPenID, FFI::GDAL::OGRStyleToolParamSymbolID, FFI::GDAL::OGRStyleToolUnitsID, FFI::GDAL::OGRUnsetMarker, FFI::GDAL::OGR_Z_MARKER, FFI::GDAL::OGRwkbByteOrder, FFI::GDAL::OGRwkbGeometryType, FFI::GDAL::OGRwkbVariant, FFI::GDAL::OLCAlterFieldDefn, FFI::GDAL::OLCCreateField, FFI::GDAL::OLCCreateGeomField, FFI::GDAL::OLCDeleteFeature, FFI::GDAL::OLCDeleteField, FFI::GDAL::OLCFastFeatureCount, FFI::GDAL::OLCFastGetExtent, FFI::GDAL::OLCFastSetNextByIndex, FFI::GDAL::OLCFastSpatialFilter, FFI::GDAL::OLCIgnoreFields, FFI::GDAL::OLCRandomRead, FFI::GDAL::OLCRandomeWrite, FFI::GDAL::OLCReorderFields, FFI::GDAL::OLCSequentialWrite, FFI::GDAL::OLCStringsAsUTF8, FFI::GDAL::OLCTransactions, FFI::GDAL::ObjectNull, FFI::GDAL::OpenFailed, FFI::GDAL::OutOfMemory, FFI::GDAL::UserInterrupt, FFI::GDAL::VERSION, FFI::GDAL::VSI_STAT_EXISTS_FLAG, FFI::GDAL::VSI_STAT_NATURE_FLAG, FFI::GDAL::VSI_STAT_SIZE_FLAG, FFI::GDAL::WKB_25D_BIT

Class Method Summary collapse

Instance Method Summary collapse

Methods included from MajorObject

#all_metadata, #description, #description=, #metadata_domain_list, #metadata_for_domain, #metadata_item, #null?

Methods included from FFI::GDAL

#CPLFree, #cpla_assert, find_lib, #gdal_check_version, gdal_library_path, search_paths, #srcval, #validate_pointer0, #validate_pointer1, #validate_pointer_err

Constructor Details

#initialize(dataset_pointer) ⇒ Dataset

Returns a new instance of Dataset.

Parameters:

  • dataset_pointer (FFI::Pointer)

    Pointer to the dataset in memory.



142
143
144
145
146
147
148
# File 'lib/ffi-gdal/dataset.rb', line 142

def initialize(dataset_pointer)
  @gdal_dataset = dataset_pointer
  @last_known_file_list = []
  @open = true
  close_me = -> { self.close }
  ObjectSpace.define_finalizer self, close_me
end

Class Method Details

.calculate_ndvi(red_band_array, nir_band_array) ⇒ NArray

Parameters:

  • red_band_array (NArray)
  • nir_band_array (NArray)

Returns:

  • (NArray)


120
121
122
# File 'lib/ffi-gdal/dataset.rb', line 120

def self.calculate_ndvi(red_band_array, nir_band_array)
  (nir_band_array - red_band_array) / (nir_band_array + red_band_array)
end

.extract_gndvi(source, destination, driver_name: 'GTiff') ⇒ Object



63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
# File 'lib/ffi-gdal/dataset.rb', line 63

def self.extract_gndvi(source, destination, driver_name: 'GTiff')
  extract_8bit(source, destination, driver_name) do |original, gndvi_dataset|
    green = original.green_band
    nir = original.undefined_band

    if green.nil?
      fail RequiredBandNotFound, 'Green band not found.'
    elsif nir.nil?
      fail RequiredBandNotFound, 'Near-infrared'
    end

    the_array = calculate_ndvi(green.to_a, nir.to_a)

    gndvi_band = gndvi_dataset.raster_band(1)
    gndvi_band.write_array(the_array)
  end
end

.extract_natural_color(source, destination, driver_name: 'GTiff') ⇒ Object



91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
# File 'lib/ffi-gdal/dataset.rb', line 91

def self.extract_natural_color(source, destination, driver_name: 'GTiff')
  original_dataset = open(source, 'r')
  geo_transform = original_dataset.geo_transform
  projection = original_dataset.projection
  rows = original_dataset.raster_y_size
  columns = original_dataset.raster_x_size

  driver = GDAL::Driver.by_name(driver_name)
  driver.create_dataset(destination, columns, rows, bands: 3) do |new_dataset|
    new_dataset.geo_transform = geo_transform
    new_dataset.projection = projection
    original_red_band = original_dataset.red_band
    original_green_band = original_dataset.green_band
    original_blue_band = original_dataset.blue_band

    new_red_band = new_dataset.raster_band(1)
    new_red_band.write_array(original_red_band.to_a)

    new_green_band = new_dataset.raster_band(2)
    new_green_band.write_array(original_green_band.to_a)

    new_blue_band = new_dataset.raster_band(3)
    new_blue_band.write_array(original_blue_band.to_a)
  end
end

.extract_ndvi(source, destination, driver_name: 'GTiff') ⇒ Object

Computes NDVI from the red and near-infrared bands in the dataset. Raises a GDAL::RequiredBandNotFound if one of those band types isn’t found.

Parameters:

  • source (String)

    Path to the dataset that contains the red and NIR bands.

  • destination (String)

    Path to output the new dataset to.

  • driver_name (String) (defaults to: 'GTiff')

    The type of dataset to create.



45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
# File 'lib/ffi-gdal/dataset.rb', line 45

def self.extract_ndvi(source, destination, driver_name: 'GTiff')
  extract_8bit(source, destination, driver_name) do |original, ndvi_dataset|
    red = original.red_band
    nir = original.undefined_band

    if red.nil?
      fail RequiredBandNotFound, 'Red band not found.'
    elsif nir.nil?
      fail RequiredBandNotFound, 'Near-infrared'
    end

    the_array = calculate_ndvi(red.to_a, nir.to_a)

    ndvi_band = ndvi_dataset.raster_band(1)
    ndvi_band.write_array(the_array)
  end
end

.extract_nir(source, destination, driver_name: 'GTiff') ⇒ Object



81
82
83
84
85
86
87
88
89
# File 'lib/ffi-gdal/dataset.rb', line 81

def self.extract_nir(source, destination, driver_name: 'GTiff')
  extract_8bit(source, destination, driver_name) do |original, nir_dataset|
    nir = original.undefined_band
    fail RequiredBandNotFound, 'Near-infrared' if nir.nil?

    nir_band = nir_dataset.raster_band(1)
    nir_band.write_array(nir.to_a)
  end
end

.open(path, access_flag) ⇒ Object

Parameters:

  • path (String)

    Path to the file that contains the dataset. Can be a local file or a URL.

  • access_flag (String)

    ‘r’ or ‘w’.

Raises:



28
29
30
31
32
33
34
35
36
# File 'lib/ffi-gdal/dataset.rb', line 28

def self.open(path, access_flag)
  uri = URI.parse(path)
  file_path = uri.scheme.nil? ? ::File.expand_path(path) : path

  pointer = FFI::GDAL.GDALOpen(file_path, ACCESS_FLAGS[access_flag])
  raise OpenFailure.new(file_path) if pointer.null?

  new(pointer)
end

Instance Method Details

#access_flagSymbol

Returns:



251
252
253
254
255
256
257
# File 'lib/ffi-gdal/dataset.rb', line 251

def access_flag
  return nil if null?

  flag = GDALGetAccess(@gdal_dataset)

  GDALAccess[flag]
end

#blue_bandGDAL::RasterBand

Returns:



342
343
344
345
346
347
348
# File 'lib/ffi-gdal/dataset.rb', line 342

def blue_band
  band = find_band do |band|
    band.color_interpretation == :GCI_BlueBand
  end

  band.is_a?(GDAL::RasterBand) ? band : nil
end

#c_pointerFFI::Pointer

this Ruby object.

Returns:

  • (FFI::Pointer)

    Pointer to the GDALDatasetH that’s represented by



152
153
154
# File 'lib/ffi-gdal/dataset.rb', line 152

def c_pointer
  @gdal_dataset
end

#closeObject

Close the dataset.



157
158
159
160
161
# File 'lib/ffi-gdal/dataset.rb', line 157

def close
  @last_known_file_list = file_list
  GDALClose(@gdal_dataset)
  @open = false
end

#driverGDAL::Driver

Returns The driver to be used for working with this dataset.

Returns:

  • (GDAL::Driver)

    The driver to be used for working with this dataset.



181
182
183
184
185
186
187
188
189
# File 'lib/ffi-gdal/dataset.rb', line 181

def driver
  return @driver if @driver

  @driver = if @gdal_dataset && !null?
    Driver.new(dataset: @gdal_dataset)
  else
    Driver.new
  end
end

#each_bandObject

Iterates raster bands from 1 to #raster_count and yields them to the given block.



303
304
305
306
307
# File 'lib/ffi-gdal/dataset.rb', line 303

def each_band
  1.upto(raster_count) do |i|
    yield(raster_band(i))
  end
end

#file_listArray<String>

Fetches all files that form the dataset.

Returns:



193
194
195
196
197
198
199
# File 'lib/ffi-gdal/dataset.rb', line 193

def file_list
  list_pointer = GDALGetFileList(c_pointer)
  file_list = list_pointer.get_array_of_string(0)
  CSLDestroy(list_pointer)

  file_list
end

#find_bandGDAL::RasterBand

Returns the first raster band for which the block returns true. Ex.

dataset.find_band do |band|
  band.color_interpretation == :GCI_RedBand
end

Returns:



316
317
318
319
320
321
# File 'lib/ffi-gdal/dataset.rb', line 316

def find_band
  each_band do |band|
    result = yield(band)
    return band if result
  end
end

#gcp_countFixnum

Returns:



275
276
277
278
279
# File 'lib/ffi-gdal/dataset.rb', line 275

def gcp_count
  return 0 if null?

  GDALGetGCPCount(@gdal_dataset)
end

#gcp_projectionString

Returns:



282
283
284
285
286
# File 'lib/ffi-gdal/dataset.rb', line 282

def gcp_projection
  return '' if null?

  GDALGetGCPProjection(@gdal_dataset)
end

#gcpsFFI::GDAL::GDALGCP

Returns:



289
290
291
292
293
294
295
296
297
298
299
# File 'lib/ffi-gdal/dataset.rb', line 289

def gcps
  return GDALGCP.new if null?

  gcp_array_pointer = GDALGetGCPs(@gdal_dataset)

  if gcp_array_pointer.null?
    GDALGCP.new
  else
    GDALGCP.new(gcp_array_pointer)
  end
end

#geo_transformGDAL::GeoTransform

Returns:



260
261
262
# File 'lib/ffi-gdal/dataset.rb', line 260

def geo_transform
  @geo_transform ||= GeoTransform.new(@gdal_dataset)
end

#geo_transform=(new_transform) ⇒ GDAL::GeoTransform

Parameters:

Returns:



266
267
268
269
270
271
272
# File 'lib/ffi-gdal/dataset.rb', line 266

def geo_transform=(new_transform)
  new_pointer = new_transform.c_pointer.dup
  cpl_err = GDALSetGeoTransform(@gdal_dataset, new_pointer)
  cpl_err.to_bool

  @geo_transform = GeoTransform.new(@gdal_dataset, geo_transform_pointer: new_pointer)
end

#green_bandGDAL::RasterBand

Returns:



333
334
335
336
337
338
339
# File 'lib/ffi-gdal/dataset.rb', line 333

def green_band
  band = find_band do |band|
    band.color_interpretation == :GCI_GreenBand
  end

  band.is_a?(GDAL::RasterBand) ? band : nil
end

#open?Boolean

Returns:

  • (Boolean)


175
176
177
# File 'lib/ffi-gdal/dataset.rb', line 175

def open?
  @open
end

#projectionString

Returns:



236
237
238
239
240
# File 'lib/ffi-gdal/dataset.rb', line 236

def projection
  return '' if null?

  GDALGetProjectionRef(@gdal_dataset)
end

#projection=(new_projection) ⇒ Boolean

Parameters:

Returns:

  • (Boolean)


244
245
246
247
248
# File 'lib/ffi-gdal/dataset.rb', line 244

def projection=(new_projection)
  cpl_err = GDALSetProjection(@gdal_dataset, new_projection)

  cpl_err.to_bool
end

#raster_band(raster_index) ⇒ GDAL::RasterBand

Parameters:

Returns:



224
225
226
227
228
229
230
231
232
233
# File 'lib/ffi-gdal/dataset.rb', line 224

def raster_band(raster_index)
  @raster_bands ||= Array.new(raster_count)

  if @raster_bands[raster_index] && !@raster_bands[raster_index].null?
    return @raster_bands[raster_index]
  end

  @raster_bands[raster_index] =
    GDAL::RasterBand.new(@gdal_dataset, band_id: raster_index)
end

#raster_countFixnum

Returns:



216
217
218
219
220
# File 'lib/ffi-gdal/dataset.rb', line 216

def raster_count
  return 0 if null?

  GDALGetRasterCount(@gdal_dataset)
end

#raster_x_sizeFixnum

Returns:



202
203
204
205
206
# File 'lib/ffi-gdal/dataset.rb', line 202

def raster_x_size
  return nil if null?

  GDALGetRasterXSize(@gdal_dataset)
end

#raster_y_sizeFixnum

Returns:



209
210
211
212
213
# File 'lib/ffi-gdal/dataset.rb', line 209

def raster_y_size
  return nil if null?

  GDALGetRasterYSize(@gdal_dataset)
end

#red_bandGDAL::RasterBand

Returns:



324
325
326
327
328
329
330
# File 'lib/ffi-gdal/dataset.rb', line 324

def red_band
  band = find_band do |band|
    band.color_interpretation == :GCI_RedBand
  end

  band.is_a?(GDAL::RasterBand) ? band : nil
end

#reopen(access_flag) ⇒ Boolean

Tries to reopen the dataset using the first item from #file_list before the dataset was closed.

Parameters:

Returns:

  • (Boolean)


168
169
170
171
172
# File 'lib/ffi-gdal/dataset.rb', line 168

def reopen(access_flag)
  @gdal_dataset = GDALOpen(@last_known_file_list.first, access_flag)

  @open = true unless @gdal_dataset.null?
end

#undefined_bandGDAL::RasterBand

Returns:



351
352
353
354
355
356
357
# File 'lib/ffi-gdal/dataset.rb', line 351

def undefined_band
  band = find_band do |band|
    band.color_interpretation == :GCI_Undefined
  end

  band.is_a?(GDAL::RasterBand) ? band : nil
end