ffi-gdal 1.0.0.beta3 → 1.0.0.beta4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.gitignore +3 -0
- data/.rubocop.yml +62 -0
- data/Gemfile +1 -1
- data/History.md +53 -28
- data/README.md +6 -0
- data/Rakefile +23 -1
- data/examples/extract_and_colorize.rb +21 -22
- data/examples/geometries.rb +2 -2
- data/examples/gridding.rb +106 -0
- data/examples/ogr_layer_to_layer.rb +1 -1
- data/examples/points.txt +127 -0
- data/examples/testing_gdal.rb +3 -4
- data/ffi-gdal.gemspec +3 -2
- data/lib/ext/error_symbols.rb +2 -57
- data/lib/ext/ffi_library_function_checks.rb +26 -0
- data/lib/ext/float_ext.rb +2 -2
- data/lib/ext/narray_ext.rb +2 -0
- data/lib/ext/numeric_as_data_type.rb +19 -0
- data/lib/ext/to_bool.rb +4 -4
- data/lib/ffi/cpl/conv.rb +132 -0
- data/lib/ffi/cpl/error.rb +67 -0
- data/lib/ffi/cpl/hash_set.rb +39 -0
- data/lib/ffi/cpl/http.rb +25 -0
- data/lib/ffi/cpl/http_result.rb +18 -0
- data/lib/ffi/cpl/list.rb +38 -0
- data/lib/ffi/cpl/mime_part.rb +11 -0
- data/lib/ffi/cpl/minixml.rb +47 -0
- data/lib/ffi/cpl/port.rb +23 -0
- data/lib/ffi/cpl/quad_tree.rb +51 -0
- data/lib/ffi/{ogr/ogr_envelope.rb → cpl/rect_obj.rb} +3 -3
- data/lib/ffi/cpl/string.rb +95 -0
- data/lib/ffi/cpl/vsi.rb +115 -0
- data/lib/ffi/cpl/xml_node.rb +6 -6
- data/lib/ffi/gdal/alg.rb +385 -0
- data/lib/ffi/gdal/{gdal_color_entry.rb → color_entry.rb} +1 -2
- data/lib/ffi/gdal/exceptions.rb +6 -0
- data/lib/ffi/gdal/{gdal_gcp.rb → gcp.rb} +1 -3
- data/lib/ffi/gdal/{gdal_h.rb → gdal.rb} +253 -252
- data/lib/ffi/gdal/grid.rb +58 -0
- data/lib/ffi/gdal/{gdal_grid_data_metrics_options.rb → grid_data_metrics_options.rb} +1 -2
- data/lib/ffi/gdal/{gdal_grid_inverse_distance_to_a_power_options.rb → grid_inverse_distance_to_a_power_options.rb} +1 -2
- data/lib/ffi/gdal/{gdal_grid_moving_average_options.rb → grid_moving_average_options.rb} +1 -2
- data/lib/ffi/gdal/{gdal_grid_nearest_neighbor_options.rb → grid_nearest_neighbor_options.rb} +1 -2
- data/lib/ffi/gdal/matching.rb +20 -0
- data/lib/ffi/gdal/{gdal_rpc_info.rb → rpc_info.rb} +1 -2
- data/lib/ffi/gdal/{gdal_transformer_info.rb → transformer_info.rb} +1 -2
- data/lib/ffi/gdal/version.rb +1 -1
- data/lib/ffi/gdal/vrt.rb +92 -0
- data/lib/ffi/gdal/{gdal_warp_options.rb → warp_options.rb} +8 -4
- data/lib/ffi/gdal/warper.rb +70 -0
- data/lib/ffi/gdal.rb +56 -69
- data/lib/ffi/ogr/api.rb +567 -0
- data/lib/ffi/ogr/{ogr_contour_writer_info.rb → contour_writer_info.rb} +2 -3
- data/lib/ffi/ogr/core.rb +181 -0
- data/lib/ffi/ogr/envelope.rb +12 -0
- data/lib/ffi/ogr/{ogr_envelope_3d.rb → envelope_3d.rb} +2 -2
- data/lib/ffi/ogr/featurestyle.rb +29 -0
- data/lib/ffi/ogr/field.rb +63 -0
- data/lib/ffi/ogr/geocoding.rb +30 -0
- data/lib/ffi/ogr/srs_api.rb +407 -0
- data/lib/ffi/ogr/style_param.rb +13 -0
- data/lib/ffi/ogr/{ogr_style_value.rb → style_value.rb} +4 -3
- data/lib/ffi/ogr.rb +7 -7
- data/lib/ffi-gdal.rb +7 -145
- data/lib/gdal/color_entry.rb +18 -14
- data/lib/gdal/color_entry_mixins/extensions.rb +32 -0
- data/lib/gdal/color_interpretation.rb +2 -2
- data/lib/gdal/color_table.rb +37 -32
- data/lib/gdal/color_table_mixins/extensions.rb +48 -0
- data/lib/gdal/cpl_error_handler.rb +119 -0
- data/lib/gdal/data_type.rb +7 -7
- data/lib/gdal/dataset.rb +131 -238
- data/lib/gdal/dataset_mixins/algorithm_methods.rb +182 -0
- data/lib/gdal/dataset_mixins/extensions.rb +542 -0
- data/lib/gdal/dataset_mixins/matching.rb +26 -0
- data/lib/gdal/driver.rb +68 -92
- data/lib/gdal/driver_mixins/extensions.rb +93 -0
- data/lib/gdal/exceptions.rb +32 -4
- data/lib/gdal/geo_transform.rb +63 -43
- data/lib/gdal/geo_transform_mixins/extensions.rb +57 -0
- data/lib/gdal/grid.rb +144 -0
- data/lib/gdal/grid_types/data_metrics_base.rb +14 -0
- data/lib/gdal/grid_types/inverse_distance_to_a_power.rb +19 -0
- data/lib/gdal/grid_types/metric_average_distance.rb +12 -0
- data/lib/gdal/grid_types/metric_average_distance_pts.rb +12 -0
- data/lib/gdal/grid_types/metric_count.rb +12 -0
- data/lib/gdal/grid_types/metric_maximum.rb +12 -0
- data/lib/gdal/grid_types/metric_minimum.rb +12 -0
- data/lib/gdal/grid_types/metric_range.rb +12 -0
- data/lib/gdal/grid_types/moving_average.rb +19 -0
- data/lib/gdal/grid_types/nearest_neighbor.rb +19 -0
- data/lib/gdal/grid_types.rb +22 -0
- data/lib/gdal/internal_helpers.rb +94 -0
- data/lib/gdal/major_object.rb +4 -7
- data/lib/gdal/options.rb +14 -7
- data/lib/gdal/raster_attribute_table.rb +38 -47
- data/lib/gdal/raster_attribute_table_mixins/extensions.rb +41 -0
- data/lib/gdal/raster_band.rb +193 -227
- data/lib/gdal/raster_band_classifier.rb +107 -0
- data/lib/gdal/raster_band_mixins/algorithm_methods.rb +292 -0
- data/lib/gdal/raster_band_mixins/extensions.rb +238 -0
- data/lib/gdal/rpc_info.rb +35 -0
- data/lib/gdal/transformer.rb +15 -0
- data/lib/gdal/transformers/approximate_transformer.rb +48 -0
- data/lib/gdal/transformers/base_general_image_projection_transformer.rb +45 -0
- data/lib/gdal/transformers/gcp_transformer.rb +55 -0
- data/lib/gdal/transformers/general_image_projection_transformer.rb +31 -0
- data/lib/gdal/transformers/general_image_projection_transformer2.rb +52 -0
- data/lib/gdal/transformers/general_image_projection_transformer3.rb +25 -0
- data/lib/gdal/transformers/geolocation_transformer.rb +42 -0
- data/lib/gdal/transformers/reprojection_transformer.rb +39 -0
- data/lib/gdal/transformers/rpc_transformer.rb +56 -0
- data/lib/gdal/transformers/tps_transformer.rb +40 -0
- data/lib/gdal/virtual_dataset.rb +96 -0
- data/lib/gdal/warp_operation.rb +20 -23
- data/lib/gdal.rb +17 -0
- data/lib/ogr/coordinate_transformation.rb +16 -41
- data/lib/ogr/data_source.rb +103 -58
- data/lib/ogr/data_source_extensions.rb +5 -6
- data/lib/ogr/data_source_mixins/capability_methods.rb +27 -0
- data/lib/ogr/driver.rb +61 -33
- data/lib/ogr/driver_mixins/capability_methods.rb +16 -0
- data/lib/ogr/envelope.rb +29 -18
- data/lib/ogr/envelope_extensions.rb +70 -49
- data/lib/ogr/error_handling.rb +46 -0
- data/lib/ogr/exceptions.rb +58 -12
- data/lib/ogr/feature.rb +334 -86
- data/lib/ogr/feature_definition.rb +94 -51
- data/lib/ogr/feature_definition_extensions.rb +36 -13
- data/lib/ogr/feature_extensions.rb +62 -11
- data/lib/ogr/field.rb +175 -54
- data/lib/ogr/field_definition.rb +110 -0
- data/lib/ogr/{field_extensions.rb → field_definition_extensions.rb} +4 -5
- data/lib/ogr/{geocoding_session.rb → geocoder.rb} +14 -13
- data/lib/ogr/geometries/geometry_collection.rb +13 -0
- data/lib/ogr/geometries/line_string.rb +35 -0
- data/lib/ogr/geometries/linear_ring.rb +11 -0
- data/lib/ogr/geometries/multi_line_string.rb +16 -0
- data/lib/ogr/geometries/multi_point.rb +14 -0
- data/lib/ogr/geometries/multi_polygon.rb +21 -0
- data/lib/ogr/geometries/none_geometry.rb +13 -0
- data/lib/ogr/geometries/point.rb +65 -0
- data/lib/ogr/geometries/point_extensions.rb +32 -0
- data/lib/ogr/geometries/polygon.rb +14 -0
- data/lib/ogr/geometries/unknown_geometry.rb +10 -0
- data/lib/ogr/geometry.rb +270 -242
- data/lib/ogr/geometry_extensions.rb +8 -9
- data/lib/ogr/geometry_field_definition.rb +99 -0
- data/lib/ogr/geometry_field_definition_extensions.rb +19 -0
- data/lib/ogr/geometry_types/container.rb +75 -0
- data/lib/ogr/geometry_types/curve.rb +25 -28
- data/lib/ogr/geometry_types/surface.rb +13 -4
- data/lib/ogr/internal_helpers.rb +57 -0
- data/lib/ogr/layer.rb +60 -181
- data/lib/ogr/layer_mixins/capability_methods.rb +102 -0
- data/lib/ogr/layer_mixins/extensions.rb +59 -0
- data/lib/ogr/layer_mixins/ogr_feature_methods.rb +127 -0
- data/lib/ogr/layer_mixins/ogr_field_methods.rb +143 -0
- data/lib/ogr/layer_mixins/ogr_layer_method_methods.rb +163 -0
- data/lib/ogr/layer_mixins/ogr_query_filter_methods.rb +89 -0
- data/lib/ogr/layer_mixins/ogr_sql_methods.rb +48 -0
- data/lib/ogr/spatial_reference.rb +108 -589
- data/lib/ogr/spatial_reference_extensions.rb +29 -3
- data/lib/ogr/spatial_reference_mixins/coordinate_system_getter_setters.rb +494 -0
- data/lib/ogr/spatial_reference_mixins/exporters.rb +134 -0
- data/lib/ogr/spatial_reference_mixins/importers.rb +243 -0
- data/lib/ogr/spatial_reference_mixins/morphers.rb +25 -0
- data/lib/ogr/spatial_reference_mixins/parameter_getter_setters.rb +122 -0
- data/lib/ogr/spatial_reference_mixins/type_checks.rb +62 -0
- data/lib/ogr/style_table.rb +53 -5
- data/lib/ogr/style_table_extensions.rb +21 -5
- data/lib/ogr/style_tool.rb +118 -0
- data/lib/ogr.rb +8 -0
- data/spec/ffi-gdal_spec.rb +1 -2
- data/spec/integration/{color_table_info_spec.rb → gdal/color_table_info_spec.rb} +12 -12
- data/spec/integration/{dataset_info_spec.rb → gdal/dataset_info_spec.rb} +2 -6
- data/spec/integration/{driver_info_spec.rb → gdal/driver_info_spec.rb} +5 -5
- data/spec/integration/{geo_transform_info_spec.rb → gdal/geo_transform_info_spec.rb} +1 -14
- data/spec/integration/{raster_attribute_table_info_spec.rb → gdal/raster_attribute_table_info_spec.rb} +1 -2
- data/spec/integration/{raster_band_info_spec.rb → gdal/raster_band_info_spec.rb} +30 -42
- data/spec/integration/ogr/layer_spec.rb +97 -0
- data/spec/spec_helper.rb +94 -5
- data/spec/support/integration_help.rb +1 -0
- data/spec/support/shared_contexts.rb +26 -0
- data/spec/support/shared_examples/{major_object_examples.rb → gdal/major_object_examples.rb} +5 -5
- data/spec/support/shared_examples/ogr/a_25D_geometry.rb +7 -0
- data/spec/support/shared_examples/ogr/a_container_geometry.rb +47 -0
- data/spec/support/shared_examples/ogr/a_geometry.rb +404 -0
- data/spec/support/shared_examples/ogr/a_line_string.rb +16 -0
- data/spec/support/test_style_table.txt +3 -0
- data/spec/unit/ext/error_symbols_spec.rb +41 -53
- data/spec/unit/ext/numeric_as_data_type_spec.rb +113 -0
- data/spec/unit/ffi/gdal_spec.rb +70 -0
- data/spec/unit/gdal/color_entry_spec.rb +5 -0
- data/spec/unit/gdal/color_interpretation_spec.rb +5 -0
- data/spec/unit/gdal/{color_table_extensions_spec.rb → color_table_mixins/extensions_spec.rb} +3 -3
- data/spec/unit/gdal/color_table_spec.rb +14 -16
- data/spec/unit/gdal/data_type_spec.rb +10 -17
- data/spec/unit/gdal/dataset_spec.rb +4 -7
- data/spec/unit/gdal/driver_mixins/extensions_spec.rb +22 -0
- data/spec/unit/gdal/driver_spec.rb +49 -0
- data/spec/unit/gdal/environment_methods_spec.rb +6 -0
- data/spec/unit/gdal/geo_transform_spec.rb +276 -0
- data/spec/unit/gdal/grid_spec.rb +5 -0
- data/spec/unit/gdal/internal_helpers_spec.rb +112 -0
- data/spec/unit/gdal/major_object_spec.rb +6 -0
- data/spec/unit/gdal/options_spec.rb +5 -0
- data/spec/unit/gdal/raster_attribute_table_spec.rb +5 -0
- data/spec/unit/gdal/raster_band_classifier_spec.rb +134 -0
- data/spec/unit/gdal/raster_band_spec.rb +5 -0
- data/spec/unit/gdal/rpc_info_spec.rb +5 -0
- data/spec/unit/gdal/version_info_spec.rb +6 -0
- data/spec/unit/gdal/virtual_dataset_spec.rb +32 -0
- data/spec/unit/gdal/warp_operation_spec.rb +5 -0
- data/spec/unit/ogr/data_source_mixins/capability_methods_spec.rb +30 -0
- data/spec/unit/ogr/data_source_spec.rb +209 -0
- data/spec/unit/ogr/driver_mixins/capability_methods_spec.rb +18 -0
- data/spec/unit/ogr/driver_spec.rb +150 -0
- data/spec/unit/ogr/envelope_spec.rb +322 -0
- data/spec/unit/ogr/feature_definition_spec.rb +313 -0
- data/spec/unit/ogr/feature_spec.rb +379 -0
- data/spec/unit/ogr/field_definition_spec.rb +135 -0
- data/spec/unit/ogr/field_spec.rb +193 -0
- data/spec/unit/ogr/geometries/geometry_collection_spec.rb +186 -0
- data/spec/unit/ogr/geometries/line_string_spec.rb +105 -0
- data/spec/unit/ogr/{linear_ring_spec.rb → geometries/linear_ring_spec.rb} +10 -31
- data/spec/unit/ogr/geometries/multi_line_string_spec.rb +14 -0
- data/spec/unit/ogr/geometries/multi_point_spec.rb +14 -0
- data/spec/unit/ogr/geometries/multi_polygon_spec.rb +41 -0
- data/spec/unit/ogr/geometries/none_geometry_spec.rb +12 -0
- data/spec/unit/ogr/{point_spec.rb → geometries/point_spec.rb} +19 -25
- data/spec/unit/ogr/geometries/polygon_spec.rb +17 -0
- data/spec/unit/ogr/geometries/unknown_geometry_spec.rb +10 -0
- data/spec/unit/ogr/geometry_field_definition_spec.rb +87 -0
- data/spec/unit/ogr/geometry_spec.rb +542 -0
- data/spec/unit/ogr/internal_helpers_spec.rb +57 -0
- data/spec/unit/ogr/layer_mixins/capability_methods_spec.rb +88 -0
- data/spec/unit/ogr/layer_mixins/ogr_feature_methods_spec.rb +145 -0
- data/spec/unit/ogr/layer_mixins/ogr_field_methods_spec.rb +432 -0
- data/spec/unit/ogr/layer_mixins/ogr_layer_method_methods_spec.rb +20 -0
- data/spec/unit/ogr/layer_mixins/ogr_query_filter_methods_spec.rb +42 -0
- data/spec/unit/ogr/layer_mixins/ogr_sql_methods_spec.rb +12 -0
- data/spec/unit/ogr/layer_spec.rb +66 -67
- data/spec/unit/ogr/spatial_reference_mixins/coordinate_system_getter_setters_spec.rb +46 -0
- data/spec/unit/ogr/spatial_reference_mixins/exporters_spec.rb +139 -0
- data/spec/unit/ogr/spatial_reference_mixins/importers_spec.rb +38 -0
- data/spec/unit/ogr/spatial_reference_mixins/morphers_spec.rb +36 -0
- data/spec/unit/ogr/spatial_reference_mixins/parameter_getter_setters_spec.rb +102 -0
- data/spec/unit/ogr/spatial_reference_mixins/type_checks_spec.rb +157 -0
- data/spec/unit/ogr/spatial_reference_spec.rb +42 -0
- data/spec/unit/ogr/style_table_spec.rb +132 -0
- data/spec/unit/ogr/style_tool_spec.rb +157 -0
- data/spec/unit/version_info_spec.rb +1 -1
- metadata +285 -75
- data/lib/ffi/cpl/conv_h.rb +0 -143
- data/lib/ffi/cpl/error_h.rb +0 -63
- data/lib/ffi/cpl/minixml_h.rb +0 -14
- data/lib/ffi/cpl/string_h.rb +0 -81
- data/lib/ffi/cpl/vsi_h.rb +0 -112
- data/lib/ffi/gdal/alg_h.rb +0 -127
- data/lib/ffi/gdal/grid_h.rb +0 -51
- data/lib/ffi/gdal/warper_h.rb +0 -48
- data/lib/ffi/ogr/api_h.rb +0 -553
- data/lib/ffi/ogr/core_h.rb +0 -148
- data/lib/ffi/ogr/featurestyle_h.rb +0 -22
- data/lib/ffi/ogr/geocoding_h.rb +0 -21
- data/lib/ffi/ogr/ogr_field.rb +0 -50
- data/lib/ffi/ogr/ogr_style_param.rb +0 -12
- data/lib/ffi/ogr/srs_api_h.rb +0 -325
- data/lib/gdal/color_entry_extensions.rb +0 -30
- data/lib/gdal/color_table_extensions.rb +0 -47
- data/lib/gdal/dataset_extensions.rb +0 -496
- data/lib/gdal/driver_extensions.rb +0 -56
- data/lib/gdal/geo_transform_extensions.rb +0 -90
- data/lib/gdal/raster_attribute_table_extensions.rb +0 -40
- data/lib/gdal/raster_band_extensions.rb +0 -198
- data/lib/ogr/geometry_types/collection.rb +0 -45
- data/lib/ogr/layer_extensions.rb +0 -55
- data/lib/ogr/line_string.rb +0 -7
- data/lib/ogr/linear_ring.rb +0 -6
- data/lib/ogr/multi_line_string.rb +0 -9
- data/lib/ogr/multi_point.rb +0 -7
- data/lib/ogr/multi_polygon.rb +0 -14
- data/lib/ogr/point.rb +0 -89
- data/lib/ogr/polygon.rb +0 -9
@@ -0,0 +1,542 @@
|
|
1
|
+
require 'json'
|
2
|
+
require 'narray'
|
3
|
+
require_relative '../raster_band'
|
4
|
+
require_relative '../warp_operation'
|
5
|
+
require_relative '../../ogr/driver'
|
6
|
+
require_relative '../../ogr/layer'
|
7
|
+
require_relative '../../ogr/spatial_reference'
|
8
|
+
require_relative '../../ogr/coordinate_transformation'
|
9
|
+
|
10
|
+
module GDAL
|
11
|
+
module DatasetMixins
|
12
|
+
# Methods not originally supplied with GDAL, but enhance it.
|
13
|
+
module Extensions
|
14
|
+
# Computes NDVI from the red and near-infrared bands in the dataset. Raises
|
15
|
+
# a GDAL::RequiredBandNotFound if one of those band types isn't found.
|
16
|
+
#
|
17
|
+
# @param destination [String] Path to output the new dataset to.
|
18
|
+
# @param driver_name [String] The type of dataset to create.
|
19
|
+
# @param band_order [Array<String>] The list of band types, i.e. ['red',
|
20
|
+
# 'green', 'blue'].
|
21
|
+
# @param output_data_type [FFI::GDAL::DataType] Resulting dataset will be
|
22
|
+
# in this data type.
|
23
|
+
# @param remove_negatives [Boolean] Remove negative values after
|
24
|
+
# calculating NDVI.
|
25
|
+
# @param no_data_value [Float]
|
26
|
+
# @param options [Hash] Options that get used for creating the new NDVI
|
27
|
+
# dataset. See docs for GDAL::Driver#create_dataset.
|
28
|
+
# @return [GDAL::Dataset] The new NDVI dataset. *Be sure to call #close on
|
29
|
+
# this object or the data may not persist!*
|
30
|
+
def extract_ndvi(destination, driver_name: 'GTiff', band_order: nil,
|
31
|
+
output_data_type: :GDT_Byte, remove_negatives: false,
|
32
|
+
no_data_value: -9999.0,
|
33
|
+
**options)
|
34
|
+
original_bands =
|
35
|
+
if band_order
|
36
|
+
bands_with_labels(band_order)
|
37
|
+
else
|
38
|
+
{
|
39
|
+
red: red_band,
|
40
|
+
green: green_band,
|
41
|
+
blue: blue_band,
|
42
|
+
nir: undefined_band
|
43
|
+
}
|
44
|
+
end
|
45
|
+
|
46
|
+
red = original_bands[:red]
|
47
|
+
nir = original_bands[:nir]
|
48
|
+
|
49
|
+
if red.nil?
|
50
|
+
fail RequiredBandNotFound, 'Red band not found.'
|
51
|
+
elsif nir.nil?
|
52
|
+
fail RequiredBandNotFound, 'Near-infrared'
|
53
|
+
end
|
54
|
+
|
55
|
+
the_array = calculate_ndvi(red.to_na,
|
56
|
+
nir.to_na,
|
57
|
+
no_data_value,
|
58
|
+
remove_negatives,
|
59
|
+
output_data_type)
|
60
|
+
driver = GDAL::Driver.by_name(driver_name)
|
61
|
+
|
62
|
+
driver.create_dataset(destination, raster_x_size, raster_y_size,
|
63
|
+
data_type: output_data_type, **options) do |ndvi_dataset|
|
64
|
+
ndvi_dataset.geo_transform = geo_transform
|
65
|
+
ndvi_dataset.projection = projection
|
66
|
+
|
67
|
+
ndvi_band = ndvi_dataset.raster_band(1)
|
68
|
+
ndvi_band.write_array(the_array, data_type: output_data_type)
|
69
|
+
ndvi_band.no_data_value = no_data_value
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
# Computes GNDVI from the green and near-infrared bands in the dataset.
|
74
|
+
# Raises a GDAL::RequiredBandNotFound if one of those band types isn't
|
75
|
+
# found.
|
76
|
+
#
|
77
|
+
# @param destination [String] Path to output the new dataset to.
|
78
|
+
# @param driver_name [String] The type of dataset to create.
|
79
|
+
# @param band_order [Array<String>] The list of band types, i.e. ['red',
|
80
|
+
# 'green', 'blue'].
|
81
|
+
# @param output_data_type [FFI::GDAL::DataType] Resulting dataset will be
|
82
|
+
# in this data type.
|
83
|
+
# @param remove_negatives [Boolean] Remove negative values after
|
84
|
+
# calculating NDVI.
|
85
|
+
# @param no_data_value [Float]
|
86
|
+
# @param options [Hash] Options that get used for creating the new NDVI
|
87
|
+
# dataset. See docs for GDAL::Driver#create_dataset.
|
88
|
+
# @return [GDAL::Dataset] The new NDVI dataset. *Be sure to call #close on
|
89
|
+
# this object or the data may not persist!*
|
90
|
+
def extract_gndvi(destination, driver_name: 'GTiff', band_order: nil,
|
91
|
+
output_data_type: :GDT_Byte, remove_negatives: false, no_data_value: -9999.0,
|
92
|
+
**options)
|
93
|
+
original_bands =
|
94
|
+
if band_order
|
95
|
+
bands_with_labels(band_order)
|
96
|
+
else
|
97
|
+
{
|
98
|
+
red: red_band,
|
99
|
+
green: green_band,
|
100
|
+
blue: blue_band,
|
101
|
+
nir: undefined_band
|
102
|
+
}
|
103
|
+
end
|
104
|
+
|
105
|
+
green = original_bands[:green]
|
106
|
+
nir = original_bands[:nir]
|
107
|
+
|
108
|
+
if green.nil?
|
109
|
+
fail RequiredBandNotFound, 'Green band not found.'
|
110
|
+
elsif nir.nil?
|
111
|
+
fail RequiredBandNotFound, 'Near-infrared'
|
112
|
+
end
|
113
|
+
|
114
|
+
the_array = calculate_ndvi(green.to_na, nir.to_na,
|
115
|
+
no_data_value, remove_negatives, output_data_type)
|
116
|
+
driver = GDAL::Driver.by_name(driver_name)
|
117
|
+
|
118
|
+
driver.create_dataset(destination, raster_x_size, raster_y_size,
|
119
|
+
data_type: output_data_type, **options) do |gndvi_dataset|
|
120
|
+
gndvi_dataset.geo_transform = geo_transform
|
121
|
+
gndvi_dataset.projection = projection
|
122
|
+
|
123
|
+
gndvi_band = gndvi_dataset.raster_band(1)
|
124
|
+
gndvi_band.write_array(the_array, data_type: output_data_type)
|
125
|
+
gndvi_band.no_data_value = no_data_value
|
126
|
+
end
|
127
|
+
end
|
128
|
+
|
129
|
+
# Extracts the NIR band and writes to a new file. NOTE: be sure to close
|
130
|
+
# the dataset object that gets returned or your data will not get written
|
131
|
+
# to the file.
|
132
|
+
#
|
133
|
+
# @param destination [String] The destination file path.
|
134
|
+
# @param band_number [Fixnum] The number of the band that is the NIR band.
|
135
|
+
# Remember that raster bands are 1-indexed, not 0-indexed.
|
136
|
+
# @param driver_name [String] the GDAL::Driver short name to use for the
|
137
|
+
# new dataset.
|
138
|
+
# @param output_data_type [FFI::GDAL::DataType] Resulting dataset will be
|
139
|
+
# in this data type.
|
140
|
+
# @param options [Hash] Options that get used for creating the new NDVI
|
141
|
+
# dataset. See docs for GDAL::Driver#create_dataset.
|
142
|
+
# @return [GDAL::Dataset] The new NIR dataset. *Be sure to call #close on
|
143
|
+
# this object or the data may not persist!*
|
144
|
+
def extract_nir(destination, band_number, driver_name: 'GTiff', output_data_type: :GDT_Byte, **options)
|
145
|
+
driver = GDAL::Driver.by_name(driver_name)
|
146
|
+
original_nir_band = raster_band(band_number)
|
147
|
+
|
148
|
+
if original_nir_band.nil?
|
149
|
+
fail InvalidBandNumber, "Band #{band_number} found but was nil."
|
150
|
+
end
|
151
|
+
|
152
|
+
driver.create_dataset(destination, raster_x_size, raster_y_size,
|
153
|
+
data_type: output_data_type, **options) do |nir_dataset|
|
154
|
+
nir_dataset.geo_transform = geo_transform
|
155
|
+
nir_dataset.projection = projection
|
156
|
+
|
157
|
+
nir_band = nir_dataset.raster_band(1)
|
158
|
+
original_nir_band.copy_whole_raster(nir_band)
|
159
|
+
end
|
160
|
+
end
|
161
|
+
|
162
|
+
# Extracts the RGB bands and writes to a new file. NOTE: be sure to close
|
163
|
+
# the dataset object that gets returned or your data will not get written
|
164
|
+
# to the file.
|
165
|
+
#
|
166
|
+
# @param destination [String] The destination file path.
|
167
|
+
# @param driver_name [String] the GDAL::Driver short name to use for the
|
168
|
+
# new dataset.
|
169
|
+
# @param band_order [Array<String>] The list of band types, i.e. ['red',
|
170
|
+
# 'green', 'blue'].
|
171
|
+
# @param options [Hash] Options that get used for creating the new NDVI
|
172
|
+
# dataset. See docs for GDAL::Driver#create_dataset.
|
173
|
+
# @return [GDAL::Dataset]
|
174
|
+
def extract_natural_color(destination, driver_name: 'GTiff',
|
175
|
+
band_order: nil, output_data_type: :GDT_Byte, **options)
|
176
|
+
rows = raster_y_size
|
177
|
+
columns = raster_x_size
|
178
|
+
driver = GDAL::Driver.by_name(driver_name)
|
179
|
+
|
180
|
+
original_bands = if band_order
|
181
|
+
bands_with_labels(band_order)
|
182
|
+
else
|
183
|
+
{
|
184
|
+
red: red_band,
|
185
|
+
green: green_band,
|
186
|
+
blue: blue_band
|
187
|
+
}
|
188
|
+
end
|
189
|
+
|
190
|
+
driver.create_dataset(destination, columns, rows,
|
191
|
+
band_count: 3, data_type: output_data_type, **options) do |new_dataset|
|
192
|
+
new_dataset.geo_transform = geo_transform
|
193
|
+
new_dataset.projection = projection
|
194
|
+
|
195
|
+
new_red_band = new_dataset.raster_band(1)
|
196
|
+
original_bands[:red].copy_whole_raster(new_red_band)
|
197
|
+
|
198
|
+
new_green_band = new_dataset.raster_band(2)
|
199
|
+
original_bands[:green].copy_whole_raster(new_green_band)
|
200
|
+
|
201
|
+
new_blue_band = new_dataset.raster_band(3)
|
202
|
+
original_bands[:blue].copy_whole_raster(new_blue_band)
|
203
|
+
end
|
204
|
+
end
|
205
|
+
|
206
|
+
# @param red_band_array [NArray]
|
207
|
+
# @param nir_band_array [NArray]
|
208
|
+
# @param remove_negatives [Fixnum] Value to replace negative values with.
|
209
|
+
# @return [NArray]
|
210
|
+
def calculate_ndvi(red_band_array, nir_band_array, no_data_value,
|
211
|
+
remove_negatives = false, output_data_type = nil)
|
212
|
+
|
213
|
+
# convert to float32 for calculating
|
214
|
+
nir_band_array = nir_band_array.to_type(NArray::DFLOAT)
|
215
|
+
red_band_array = red_band_array.to_type(NArray::DFLOAT)
|
216
|
+
|
217
|
+
numerator = nir_band_array - red_band_array
|
218
|
+
denominator = (nir_band_array + red_band_array)
|
219
|
+
ndvi = numerator / denominator
|
220
|
+
|
221
|
+
# Remove NaNs
|
222
|
+
0.upto(ndvi.size - 1) do |i|
|
223
|
+
ndvi[i] = no_data_value if ndvi[i].is_a?(Float) && ndvi[i].nan?
|
224
|
+
end
|
225
|
+
|
226
|
+
# Convert to output data type
|
227
|
+
final_array = case output_data_type
|
228
|
+
when :GDT_Byte
|
229
|
+
calculate_ndvi_byte(ndvi)
|
230
|
+
when :GDT_UInt16
|
231
|
+
calculate_ndvi_uint16(ndvi)
|
232
|
+
else
|
233
|
+
ndvi
|
234
|
+
end
|
235
|
+
|
236
|
+
remove_negatives ? remove_negatives_from(final_array) : final_array
|
237
|
+
end
|
238
|
+
|
239
|
+
# Map raster bands to a label, as a hash. Useful for when bands don't match
|
240
|
+
# the color_interpretation that's returned from GDAL. This simply maps the
|
241
|
+
# list of labels you pass in to the raster bands.
|
242
|
+
#
|
243
|
+
# Valid labels:
|
244
|
+
# * Near-infrared: 'N', :nir
|
245
|
+
# * Red: 'R', :red
|
246
|
+
# * Green: 'G', :green
|
247
|
+
# * Blue: 'B', :blue
|
248
|
+
# * Alpha: 'A', :alpha
|
249
|
+
#
|
250
|
+
# @param order [Array<Object>]
|
251
|
+
# @return [Hash{<Object> => GDAL::RasterBand}]
|
252
|
+
def bands_with_labels(order)
|
253
|
+
order.each_with_object({}).each_with_index do |(band_label, obj), i|
|
254
|
+
label = case band_label.to_s
|
255
|
+
when 'N', 'nir' then :nir
|
256
|
+
when 'R', 'red' then :red
|
257
|
+
when 'G', 'green' then :green
|
258
|
+
when 'B', 'blue' then :blue
|
259
|
+
else
|
260
|
+
band_label
|
261
|
+
end
|
262
|
+
|
263
|
+
obj[label] = raster_band(i + 1)
|
264
|
+
end
|
265
|
+
end
|
266
|
+
|
267
|
+
# @return [Array<GDAL::RasterBand>]
|
268
|
+
def raster_bands
|
269
|
+
1.upto(raster_count).map do |i|
|
270
|
+
raster_band(i)
|
271
|
+
end
|
272
|
+
end
|
273
|
+
|
274
|
+
# Iterates raster bands from 1 to #raster_count and yields them to the given
|
275
|
+
# block.
|
276
|
+
def each_band
|
277
|
+
1.upto(raster_count) do |i|
|
278
|
+
yield(raster_band(i))
|
279
|
+
end
|
280
|
+
end
|
281
|
+
|
282
|
+
# Returns the first raster band for which the block returns true. Ex.
|
283
|
+
#
|
284
|
+
# dataset.find_band do |band|
|
285
|
+
# band.color_interpretation == :GCI_RedBand
|
286
|
+
# end
|
287
|
+
#
|
288
|
+
# @return [GDAL::RasterBand]
|
289
|
+
def find_band
|
290
|
+
each_band do |band|
|
291
|
+
result = yield(band)
|
292
|
+
return band if result
|
293
|
+
end
|
294
|
+
end
|
295
|
+
|
296
|
+
# @return [GDAL::RasterBand]
|
297
|
+
def red_band
|
298
|
+
band = find_band do |b|
|
299
|
+
b.color_interpretation == :GCI_RedBand
|
300
|
+
end
|
301
|
+
|
302
|
+
band.is_a?(GDAL::RasterBand) ? band : nil
|
303
|
+
end
|
304
|
+
|
305
|
+
# @return [GDAL::RasterBand]
|
306
|
+
def green_band
|
307
|
+
band = find_band do |b|
|
308
|
+
b.color_interpretation == :GCI_GreenBand
|
309
|
+
end
|
310
|
+
|
311
|
+
band.is_a?(GDAL::RasterBand) ? band : nil
|
312
|
+
end
|
313
|
+
|
314
|
+
# @return [GDAL::RasterBand]
|
315
|
+
def blue_band
|
316
|
+
band = find_band do |b|
|
317
|
+
b.color_interpretation == :GCI_BlueBand
|
318
|
+
end
|
319
|
+
|
320
|
+
band.is_a?(GDAL::RasterBand) ? band : nil
|
321
|
+
end
|
322
|
+
|
323
|
+
# @return [GDAL::RasterBand]
|
324
|
+
def undefined_band
|
325
|
+
band = find_band do |b|
|
326
|
+
b.color_interpretation == :GCI_Undefined
|
327
|
+
end
|
328
|
+
|
329
|
+
band.is_a?(GDAL::RasterBand) ? band : nil
|
330
|
+
end
|
331
|
+
|
332
|
+
# Creates a OGR::SpatialReference object from the dataset's projection.
|
333
|
+
#
|
334
|
+
# @return [OGR::SpatialReference]
|
335
|
+
def spatial_reference
|
336
|
+
return @spatial_reference if @spatial_reference
|
337
|
+
|
338
|
+
return nil if projection.empty?
|
339
|
+
|
340
|
+
@spatial_reference = OGR::SpatialReference.new(projection)
|
341
|
+
end
|
342
|
+
|
343
|
+
# Converts raster band number +band_number+ to the vector format
|
344
|
+
# +vector_driver_name+. Similar to gdal_polygonize.py. If block format is
|
345
|
+
# used, the new DataSource will be closed/flushed when the block returns. If
|
346
|
+
# the non-block format is used, you need to call #close on the DataSource.
|
347
|
+
#
|
348
|
+
# @param file_name [String] Path to write the vector file to.
|
349
|
+
# @param vector_driver_name [String] One of OGR::Driver.names.
|
350
|
+
# @param geometry_type [FFI::GDAL::OGRwkbGeometryType] The type of geometry
|
351
|
+
# to use when turning the raster into a vector image.
|
352
|
+
# @param layer_name_prefix [String] Prefix of the name to give the new
|
353
|
+
# vector layer.
|
354
|
+
# @param band_numbers [Array<Fixnum>,Fixnum] Number of the raster band or
|
355
|
+
# bands from this dataset to vectorize. Can be a single Fixnum or array
|
356
|
+
# of Fixnums.
|
357
|
+
# @return [OGR::DataSource]
|
358
|
+
def to_vector(file_name, vector_driver_name, geometry_type: :wkbUnknown,
|
359
|
+
layer_name_prefix: 'band_number', band_numbers: [1],
|
360
|
+
field_name_prefix: 'field', use_band_masks: true)
|
361
|
+
band_numbers = band_numbers.is_a?(Array) ? band_numbers : [band_numbers]
|
362
|
+
ogr_driver = OGR::Driver.by_name(vector_driver_name)
|
363
|
+
|
364
|
+
if projection.empty?
|
365
|
+
spatial_ref = nil
|
366
|
+
else
|
367
|
+
spatial_ref = OGR::SpatialReference.new(projection)
|
368
|
+
spatial_ref.auto_identify_epsg! rescue OGR::UnsupportedSRS
|
369
|
+
end
|
370
|
+
|
371
|
+
data_source = ogr_driver.create_data_source(file_name)
|
372
|
+
|
373
|
+
band_numbers.each_with_index do |band_number, i|
|
374
|
+
log "Starting to polygonize raster band #{band_number}..."
|
375
|
+
layer_name = "#{layer_name_prefix}-#{band_number}"
|
376
|
+
layer = data_source.create_layer(layer_name, geometry_type: geometry_type,
|
377
|
+
spatial_reference: spatial_ref)
|
378
|
+
|
379
|
+
field_name = "#{field_name_prefix}#{i}"
|
380
|
+
layer.create_field(OGR::FieldDefinition.new(field_name, :OFTInteger))
|
381
|
+
band = raster_band(band_number)
|
382
|
+
|
383
|
+
unless band
|
384
|
+
fail GDAL::InvalidBandNumber, "Unknown band number: #{band_number}"
|
385
|
+
end
|
386
|
+
|
387
|
+
pixel_value_field = layer.feature_definition.field_index(field_name)
|
388
|
+
options = { pixel_value_field: pixel_value_field }
|
389
|
+
options.merge!(mask_band: band.mask_band) if use_band_masks
|
390
|
+
band.polygonize(layer, options)
|
391
|
+
end
|
392
|
+
|
393
|
+
if block_given?
|
394
|
+
yield data_source
|
395
|
+
data_source.close
|
396
|
+
end
|
397
|
+
|
398
|
+
data_source
|
399
|
+
end
|
400
|
+
|
401
|
+
# Gets the OGR::Geometry that represents the extent of the dataset.
|
402
|
+
#
|
403
|
+
# @return [OGR::Polygon]
|
404
|
+
def extent
|
405
|
+
raster_data_source = to_vector('memory data source', 'Memory', geometry_type: :wkbLinearRing)
|
406
|
+
|
407
|
+
raster_data_source.layer(0).geometry_from_extent
|
408
|
+
end
|
409
|
+
|
410
|
+
# @param wkt_geometry_string [String]
|
411
|
+
# @param wkt_srid [Fixnum]
|
412
|
+
# @return [Boolean]
|
413
|
+
def contains_geometry?(wkt_geometry_string, wkt_srid = 4326)
|
414
|
+
source_srs = OGR::SpatialReference.new_from_epsg(wkt_srid)
|
415
|
+
source_geometry = OGR::Geometry.create_from_wkt(wkt_geometry_string, source_srs)
|
416
|
+
@raster_geometry ||= extent
|
417
|
+
|
418
|
+
coordinate_transformation = OGR::CoordinateTransformation.new(source_srs,
|
419
|
+
@raster_geometry.spatial_reference)
|
420
|
+
source_geometry.transform!(coordinate_transformation)
|
421
|
+
|
422
|
+
@raster_geometry.contains? source_geometry
|
423
|
+
end
|
424
|
+
|
425
|
+
def image_warp(destination_file, driver, band_numbers, **warp_options)
|
426
|
+
fail NotImplementedError, '#image_warp not yet implemented.'
|
427
|
+
|
428
|
+
_options_ptr = GDAL::Options.pointer(warp_options)
|
429
|
+
driver = GDAL::Driver.by_name(driver)
|
430
|
+
destination_dataset = driver.create_dataset(destination_file, raster_x_size, raster_y_size)
|
431
|
+
|
432
|
+
band_numbers = band_numbers.is_a?(Array) ? band_numbers : [band_numbers]
|
433
|
+
log "band numbers: #{band_numbers}"
|
434
|
+
|
435
|
+
bands_ptr = FFI::MemoryPointer.new(:pointer, band_numbers.size)
|
436
|
+
bands_ptr.write_array_of_int(band_numbers)
|
437
|
+
log "band numbers ptr null? #{bands_ptr.null?}"
|
438
|
+
|
439
|
+
warp_options_struct = FFI::GDAL::WarpOptions.new
|
440
|
+
|
441
|
+
warp_options.each do |k, _|
|
442
|
+
warp_options_struct[k] = warp_options[k]
|
443
|
+
end
|
444
|
+
|
445
|
+
warp_options[:source_dataset] = c_pointer
|
446
|
+
warp_options[:destination_dataset] = destination_dataset.c_pointer
|
447
|
+
warp_options[:band_count] = band_numbers.size
|
448
|
+
warp_options[:source_bands] = bands_ptr
|
449
|
+
warp_options[:transformer] = transformer
|
450
|
+
warp_options[:transformer_arg] = transformer_arg
|
451
|
+
|
452
|
+
log "transformer: #{transformer}"
|
453
|
+
error_threshold = 0.0
|
454
|
+
order = 0
|
455
|
+
|
456
|
+
_transformer_ptr = FFI::GDAL::Alg.GDALCreateGenImgProjTransformer(@c_pointer,
|
457
|
+
projection,
|
458
|
+
destination_dataset.c_pointer,
|
459
|
+
destination.projection,
|
460
|
+
false,
|
461
|
+
error_threshold,
|
462
|
+
order)
|
463
|
+
|
464
|
+
warp_operation = GDAL::WarpOperation.new(warp_options)
|
465
|
+
warp_operation.chunk_and_warp_image(0, 0, raster_x_size, raster_y_size)
|
466
|
+
transformer.destroy!
|
467
|
+
warp_operation.destroy!
|
468
|
+
|
469
|
+
destination = GDAL::Dataset.new(destination_dataset_ptr)
|
470
|
+
destination.close
|
471
|
+
|
472
|
+
destination
|
473
|
+
end
|
474
|
+
|
475
|
+
# Retrieves pixels from each raster band and converts this to an array of
|
476
|
+
# points per pixel. For example:
|
477
|
+
#
|
478
|
+
# # If the arrays for each band look like:
|
479
|
+
# red_band_array = [0, 0, 0]
|
480
|
+
# green_band_array = [10, 10, 10]
|
481
|
+
# blue_band_array = [99, 99, 99]
|
482
|
+
# alpha_band_array = [250, 150, 2]
|
483
|
+
#
|
484
|
+
# # This array would look like:
|
485
|
+
# [[0, 10, 99, 2], [0, 10, 99, 150], [0, 10, 99, 250]]
|
486
|
+
# @return NArray
|
487
|
+
def to_na(to_data_type = nil)
|
488
|
+
na = NMatrix.to_na(raster_bands.map { |r| r.to_na(to_data_type) })
|
489
|
+
|
490
|
+
NArray[*na.transpose]
|
491
|
+
end
|
492
|
+
|
493
|
+
def as_json(options = nil)
|
494
|
+
{
|
495
|
+
dataset: {
|
496
|
+
driver: driver.long_name,
|
497
|
+
file_list: file_list,
|
498
|
+
gcp_count: gcp_count,
|
499
|
+
gcp_projection: gcp_projection,
|
500
|
+
geo_transform: geo_transform.as_json(options),
|
501
|
+
projection: projection,
|
502
|
+
raster_count: raster_count,
|
503
|
+
raster_bands: raster_bands.map(&:as_json),
|
504
|
+
spatial_reference: spatial_reference.as_json(options)
|
505
|
+
},
|
506
|
+
metadata: all_metadata
|
507
|
+
}
|
508
|
+
end
|
509
|
+
|
510
|
+
# @return [String]
|
511
|
+
def to_json(options = nil)
|
512
|
+
as_json(options).to_json
|
513
|
+
end
|
514
|
+
|
515
|
+
private
|
516
|
+
|
517
|
+
# @param ndvi [NArray]
|
518
|
+
# @return [NArray]
|
519
|
+
def calculate_ndvi_byte(ndvi)
|
520
|
+
((ndvi + 1) * (255.0 / 2)).to_type(NArray::BYTE)
|
521
|
+
end
|
522
|
+
|
523
|
+
# @param ndvi [NArray]
|
524
|
+
# @return [NArray]
|
525
|
+
def calculate_ndvi_uint16(ndvi)
|
526
|
+
((ndvi + 1) * (65_535.0 / 2)).to_type(NArray::INT)
|
527
|
+
end
|
528
|
+
|
529
|
+
# Sets any negative values in the NArray to 0.
|
530
|
+
#
|
531
|
+
# @param narray [NArray]
|
532
|
+
# @return [NArray]
|
533
|
+
def remove_negatives_from(narray, replace_with = 0)
|
534
|
+
0.upto(narray.size - 1) do |i|
|
535
|
+
narray[i] = replace_with if narray[i] < 0
|
536
|
+
end
|
537
|
+
|
538
|
+
narray
|
539
|
+
end
|
540
|
+
end
|
541
|
+
end
|
542
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
require_relative '../../ffi/gdal/matching'
|
2
|
+
|
3
|
+
module GDAL
|
4
|
+
module DatasetMixins
|
5
|
+
module Matching
|
6
|
+
# @param other_dataset [GDAL::Dataset]
|
7
|
+
# @param options [Hash]
|
8
|
+
# @return [Hash{count => Fixnum, gcp: => FFI::GDAL::GCP}] Not sure why,
|
9
|
+
# but the C function seems to return a single GCP instead of an Array of
|
10
|
+
# them.
|
11
|
+
def compute_matching_points(other_dataset, **options)
|
12
|
+
other_dataset_ptr = GDAL._pointer(GDAL::Dataset, other_dataset)
|
13
|
+
options_ptr = GDAL::Options.pointer(options)
|
14
|
+
gcp_count_ptr = FFI::MemoryPointer.new(:int)
|
15
|
+
|
16
|
+
gcp = FFI::GDAL::Matching.GDALComputeMatchingPoints(
|
17
|
+
@c_pointer,
|
18
|
+
other_dataset_ptr,
|
19
|
+
options_ptr,
|
20
|
+
gcp_count_ptr)
|
21
|
+
|
22
|
+
{ count: gcp_count_ptr.read_int, gcp: gcp }
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|