ffi-gdal 1.0.3 → 1.1.0

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.
Files changed (82) hide show
  1. checksums.yaml +4 -4
  2. data/.devcontainer/Dockerfile +9 -0
  3. data/.devcontainer/devcontainer.json +98 -0
  4. data/.github/CODEOWNERS +1 -0
  5. data/.github/workflows/codacy.yml +3 -3
  6. data/.github/workflows/codeql.yml +4 -4
  7. data/.github/workflows/continuous-integration.yml +30 -19
  8. data/.github/workflows/dependency-review.yml +2 -2
  9. data/.github/workflows/specs-in-docker.yml +12 -6
  10. data/.gitignore +4 -1
  11. data/Changelog.md +45 -4
  12. data/Gemfile +4 -2
  13. data/README.md +35 -0
  14. data/bin/rake +1 -1
  15. data/bin/rspec +1 -1
  16. data/bin/rubocop +1 -1
  17. data/lib/ext/numeric_as_data_type.rb +1 -1
  18. data/lib/ffi/cpl/vsi.rb +10 -0
  19. data/lib/ffi/gdal/gdal.rb +9 -2
  20. data/lib/ffi/gdal/grid_data_metrics_options.rb +27 -5
  21. data/lib/ffi/gdal/grid_inverse_distance_to_a_power_options.rb +30 -10
  22. data/lib/ffi/gdal/grid_moving_average_options.rb +30 -5
  23. data/lib/ffi/gdal/grid_nearest_neighbor_options.rb +24 -4
  24. data/lib/ffi/gdal/internal_helpers/gdal_version.rb +15 -0
  25. data/lib/ffi/gdal/internal_helpers/layout_version.rb +9 -0
  26. data/lib/ffi/gdal/internal_helpers/layout_version_resolver.rb +24 -0
  27. data/lib/ffi/gdal/internal_helpers.rb +11 -0
  28. data/lib/ffi/gdal/utils.rb +984 -0
  29. data/lib/ffi/gdal/version.rb +1 -1
  30. data/lib/ffi/gdal.rb +3 -1
  31. data/lib/ffi/ogr/core.rb +1 -1
  32. data/lib/ffi/ogr/srs_api.rb +17 -0
  33. data/lib/gdal/cpl_error_handler.rb +30 -15
  34. data/lib/gdal/exceptions.rb +35 -16
  35. data/lib/gdal/extensions/color_table/extensions.rb +1 -1
  36. data/lib/gdal/extensions/gridder.rb +4 -0
  37. data/lib/gdal/geo_transform.rb +13 -0
  38. data/lib/gdal/grid_algorithms/algorithm_base.rb +35 -0
  39. data/lib/gdal/grid_algorithms/inverse_distance_to_a_power.rb +3 -7
  40. data/lib/gdal/grid_algorithms/metric_average_distance.rb +5 -4
  41. data/lib/gdal/grid_algorithms/metric_average_distance_pts.rb +5 -4
  42. data/lib/gdal/grid_algorithms/metric_count.rb +5 -4
  43. data/lib/gdal/grid_algorithms/metric_maximum.rb +5 -4
  44. data/lib/gdal/grid_algorithms/metric_minimum.rb +5 -4
  45. data/lib/gdal/grid_algorithms/metric_range.rb +5 -4
  46. data/lib/gdal/grid_algorithms/moving_average.rb +3 -7
  47. data/lib/gdal/grid_algorithms/nearest_neighbor.rb +3 -7
  48. data/lib/gdal/grid_algorithms.rb +2 -0
  49. data/lib/gdal/internal_helpers.rb +8 -5
  50. data/lib/gdal/major_object.rb +6 -0
  51. data/lib/gdal/raster_band.rb +16 -12
  52. data/lib/gdal/utils/dem/options.rb +52 -0
  53. data/lib/gdal/utils/dem.rb +108 -0
  54. data/lib/gdal/utils/grid/options.rb +52 -0
  55. data/lib/gdal/utils/grid.rb +72 -0
  56. data/lib/gdal/utils/helpers/dataset_list.rb +43 -0
  57. data/lib/gdal/utils/helpers/string_list.rb +47 -0
  58. data/lib/gdal/utils/helpers.rb +11 -0
  59. data/lib/gdal/utils/info/options.rb +52 -0
  60. data/lib/gdal/utils/info.rb +40 -0
  61. data/lib/gdal/utils/nearblack/options.rb +52 -0
  62. data/lib/gdal/utils/nearblack.rb +119 -0
  63. data/lib/gdal/utils/rasterize/options.rb +52 -0
  64. data/lib/gdal/utils/rasterize.rb +108 -0
  65. data/lib/gdal/utils/translate/options.rb +52 -0
  66. data/lib/gdal/utils/translate.rb +72 -0
  67. data/lib/gdal/utils/vector_translate/options.rb +52 -0
  68. data/lib/gdal/utils/vector_translate.rb +132 -0
  69. data/lib/gdal/utils/warp/options.rb +52 -0
  70. data/lib/gdal/utils/warp.rb +118 -0
  71. data/lib/gdal/utils.rb +22 -0
  72. data/lib/gdal/warp_options.rb +11 -2
  73. data/lib/gdal.rb +1 -0
  74. data/lib/ogr/extensions/geometry/extensions.rb +0 -8
  75. data/lib/ogr/extensions/layer/extensions.rb +1 -1
  76. data/lib/ogr/extensions/spatial_reference/extensions.rb +4 -4
  77. data/lib/ogr/geometry.rb +9 -6
  78. data/lib/ogr/layer.rb +1 -1
  79. data/lib/ogr/spatial_reference.rb +27 -2
  80. metadata +32 -5
  81. data/.ruby-version +0 -1
  82. data/lib/gdal/grid_algorithms/data_metrics_base.rb +0 -14
@@ -0,0 +1,108 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "rasterize/options"
4
+
5
+ module GDAL
6
+ module Utils
7
+ # Wrapper for gdal_rasterize using GDALRasterize C API.
8
+ #
9
+ # @see https://gdal.org/programs/gdal_rasterize.html gdal_rasterize utility documentation.
10
+ # @see https://gdal.org/api/gdal_utils.html#_CPPv413GDALRasterizePKc12GDALDatasetH12GDALDatasetHPK20GDALRasterizeOptionsPi
11
+ # GDALRasterize C API.
12
+ class Rasterize
13
+ # Perform the gdal_rasterize (GDALRasterize) operation.
14
+ #
15
+ # @example Rasterize a dataset with options (for dst_dataset_path).
16
+ # src_dataset = OGR::DataSource.open("source.shp", "r")
17
+ # options = GDAL::Utils::Rasterize::Options.new(options: ["-ts", "10", "10"])
18
+ #
19
+ # dataset = GDAL::Utils::Rasterize.perform(
20
+ # dst_dataset_path: "destination.tif",
21
+ # src_dataset: src_dataset,
22
+ # options: options
23
+ # )
24
+ #
25
+ # # Do something with the dataset.
26
+ # puts dataset.raster_x_size
27
+ #
28
+ # # You must close the dataset when you are done with it.
29
+ # dataset.close
30
+ # src_dataset.close
31
+ #
32
+ # @example Rasterize a dataset (for dst_dataset_path) using block syntax.
33
+ # src_dataset = OGR::DataSource.open("source.shp", "r")
34
+ # options = GDAL::Utils::Rasterize::Options.new(options: ["-ts", "10", "10"])
35
+ #
36
+ # GDAL::Utils::Rasterize.perform(
37
+ # dst_dataset_path: "destination.tif",
38
+ # src_dataset: src_dataset,
39
+ # options: options
40
+ # ) do |dataset|
41
+ # # Do something with the dataset.
42
+ # puts dataset.raster_x_size
43
+ #
44
+ # # Dataset will be closed automatically.
45
+ # end
46
+ # src_dataset.close
47
+ #
48
+ # @example Rasterize a dataset (for dst_dataset).
49
+ # src_dataset = OGR::DataSource.open("source.shp", "r")
50
+ # dst_dataset = GDAL::Dataset.open("destination.tif", "w")
51
+ # options = GDAL::Utils::Rasterize::Options.new(options: ["-ts", "10", "10"])
52
+ #
53
+ # GDAL::Utils::Rasterize.perform(dst_dataset: dst_dataset, src_dataset: src_dataset, options: options)
54
+ #
55
+ # # You must close the dataset when you are done with it.
56
+ # dst_dataset.close
57
+ # src_dataset.close
58
+ #
59
+ # @param dst_dataset_path [String] The path to the destination dataset.
60
+ # @param dst_dataset [GDAL::Dataset] The destination dataset.
61
+ # @param src_dataset [OGR::DataSource] The source dataset.
62
+ # @param options [GDAL::Utils::Rasterize::Options] Options.
63
+ # @yield [GDAL::Dataset] The destination dataset.
64
+ # @return [GDAL::Dataset] The destination dataset (only if block is not specified; dataset must be closed).
65
+ def self.perform(src_dataset:, dst_dataset: nil, dst_dataset_path: nil, options: Options.new, &block)
66
+ if dst_dataset
67
+ for_dataset(dst_dataset: dst_dataset, src_dataset: src_dataset, options: options)
68
+ else
69
+ for_dataset_path(dst_dataset_path: dst_dataset_path, src_dataset: src_dataset, options: options, &block)
70
+ end
71
+ end
72
+
73
+ def self.for_dataset(dst_dataset:, src_dataset:, options: Options.new)
74
+ result_dataset_ptr(dst_dataset: dst_dataset, src_dataset: src_dataset, options: options)
75
+
76
+ # Return the input dataset as the output dataset (dataset is modified in place).
77
+ dst_dataset
78
+ end
79
+ private_class_method :for_dataset
80
+
81
+ def self.for_dataset_path(dst_dataset_path:, src_dataset:, options: Options.new, &block)
82
+ dst_dataset_ptr = result_dataset_ptr(
83
+ dst_dataset_path: dst_dataset_path, src_dataset: src_dataset, options: options
84
+ )
85
+
86
+ ::GDAL::Dataset.open(dst_dataset_ptr, "w", &block)
87
+ end
88
+ private_class_method :for_dataset_path
89
+
90
+ def self.result_dataset_ptr(src_dataset:, dst_dataset_path: nil, dst_dataset: nil, options: Options.new)
91
+ result_code_ptr = ::FFI::MemoryPointer.new(:int)
92
+ dst_dataset_ptr = ::FFI::GDAL::Utils.GDALRasterize(
93
+ dst_dataset_path,
94
+ dst_dataset&.c_pointer,
95
+ src_dataset.c_pointer,
96
+ options.c_pointer,
97
+ result_code_ptr
98
+ )
99
+ success = result_code_ptr.read_int.zero?
100
+
101
+ raise ::GDAL::Error, "GDALRasterize failed." if dst_dataset_ptr.null? || !success
102
+
103
+ dst_dataset_ptr
104
+ end
105
+ private_class_method :result_dataset_ptr
106
+ end
107
+ end
108
+ end
@@ -0,0 +1,52 @@
1
+ # frozen_string_literal: true
2
+
3
+ module GDAL
4
+ module Utils
5
+ class Translate
6
+ # Ruby wrapper for GDALTranslateOptions C API (options for gdal_translate utility).
7
+ #
8
+ # @see GDAL::Utils::Translate
9
+ # @see https://gdal.org/programs/gdal_translate.html gdal_translate utility documentation.
10
+ class Options
11
+ # @private
12
+ class AutoPointer < ::FFI::AutoPointer
13
+ # @param pointer [FFI::Pointer]
14
+ def self.release(pointer)
15
+ return unless pointer && !pointer.null?
16
+
17
+ ::FFI::GDAL::Utils.GDALTranslateOptionsFree(pointer)
18
+ end
19
+ end
20
+
21
+ # @return [AutoPointer] C pointer to the GDALTranslateOptions.
22
+ attr_reader :c_pointer
23
+
24
+ # @return [Array<String>] The options.
25
+ attr_reader :options
26
+
27
+ # Create a new instance.
28
+ #
29
+ # @see https://gdal.org/programs/gdal_translate.html
30
+ # List of available options could be found in gdal_translate utility documentation.
31
+ #
32
+ # @example Create a new instance.
33
+ # options = GDAL::Utils::Translate::Options.new(options: ["-of", "GTiff", "-co", "COMPRESS=DEFLATE"])
34
+ #
35
+ # @param options [Array<String>] The options list.
36
+ def initialize(options: [])
37
+ @options = options
38
+ @string_list = ::GDAL::Utils::Helpers::StringList.new(strings: options)
39
+ @c_pointer = AutoPointer.new(options_pointer)
40
+ end
41
+
42
+ private
43
+
44
+ attr_reader :string_list
45
+
46
+ def options_pointer
47
+ ::FFI::GDAL::Utils.GDALTranslateOptionsNew(string_list.c_pointer, nil)
48
+ end
49
+ end
50
+ end
51
+ end
52
+ end
@@ -0,0 +1,72 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "translate/options"
4
+
5
+ module GDAL
6
+ module Utils
7
+ # Wrapper for gdal_translate using GDALTranslate C API.
8
+ #
9
+ # @see https://gdal.org/programs/gdal_translate.html gdal_translate utility documentation.
10
+ # @see https://gdal.org/api/gdal_utils.html#gdal__utils_8h_1a1cf5b30de14ccaf847ae7a77bb546b28 GDALTranslate C API.
11
+ class Translate
12
+ # Perform the gdal_translate (GDALTranslate) operation.
13
+ #
14
+ # @example Translate a dataset.
15
+ # src_dataset = GDAL::Dataset.open("source.tif", "r")
16
+ # dataset = GDAL::Utils::Translate.perform(dst_dataset_path: "destination.tif", src_dataset: src_dataset)
17
+ #
18
+ # # Do something with the dataset.
19
+ # puts dataset.raster_x_size
20
+ #
21
+ # # You must close the dataset when you are done with it.
22
+ # dataset.close
23
+ # src_dataset.close
24
+ #
25
+ # @example Translate a dataset with options.
26
+ # src_dataset = GDAL::Dataset.open("source.tif", "r")
27
+ # dataset = GDAL::Utils::Translate.perform(
28
+ # dst_dataset_path: "destination.tif",
29
+ # src_dataset: src_dataset,
30
+ # options: GDAL::Utils::Translate::Options.new(options: ["-of", "GTiff", "-co", "COMPRESS=DEFLATE"])
31
+ # )
32
+ #
33
+ # # Do something with the dataset.
34
+ # puts dataset.raster_x_size
35
+ #
36
+ # # You must close the dataset when you are done with it.
37
+ # dataset.close
38
+ # src_dataset.close
39
+ #
40
+ # @example Translate a dataset using block syntax.
41
+ # src_dataset = GDAL::Dataset.open("source.tif", "r")
42
+ # GDAL::Utils::Translate.perform(dst_dataset_path: "destination.tif", src_dataset: src_dataset) do |dataset|
43
+ # # Do something with the dataset.
44
+ # puts dataset.raster_x_size
45
+ #
46
+ # # Dataset will be closed automatically.
47
+ # end
48
+ # src_dataset.close
49
+ #
50
+ # @param dst_dataset_path [String] The path to the destination dataset.
51
+ # @param src_dataset [GDAL::Dataset] The source dataset.
52
+ # @param options [GDAL::Utils::Translate::Options] Options.
53
+ # @yield [GDAL::Dataset] The destination dataset.
54
+ # @return [GDAL::Dataset] The destination dataset (only if block is not specified; dataset must be closed).
55
+ # @raise [GDAL::Error] If the operation fails.
56
+ def self.perform(dst_dataset_path:, src_dataset:, options: Options.new, &block)
57
+ result_code_ptr = ::FFI::MemoryPointer.new(:int)
58
+ dst_dataset_ptr = ::FFI::GDAL::Utils.GDALTranslate(
59
+ dst_dataset_path,
60
+ src_dataset.c_pointer,
61
+ options.c_pointer,
62
+ result_code_ptr
63
+ )
64
+ success = result_code_ptr.read_int.zero?
65
+
66
+ raise ::GDAL::Error, "GDALTranslate failed." if dst_dataset_ptr.null? || !success
67
+
68
+ ::GDAL::Dataset.open(dst_dataset_ptr, "w", &block)
69
+ end
70
+ end
71
+ end
72
+ end
@@ -0,0 +1,52 @@
1
+ # frozen_string_literal: true
2
+
3
+ module GDAL
4
+ module Utils
5
+ class VectorTranslate
6
+ # Ruby wrapper for GDALVectorTranslateOptions C API (options for ogr2ogr utility).
7
+ #
8
+ # @see GDAL::Utils::VectorTranslate
9
+ # @see https://gdal.org/programs/ogr2ogr.html ogr2ogr utility documentation.
10
+ class Options
11
+ # @private
12
+ class AutoPointer < ::FFI::AutoPointer
13
+ # @param pointer [FFI::Pointer]
14
+ def self.release(pointer)
15
+ return unless pointer && !pointer.null?
16
+
17
+ ::FFI::GDAL::Utils.GDALVectorTranslateOptionsFree(pointer)
18
+ end
19
+ end
20
+
21
+ # @return [AutoPointer] C pointer to the GDALVectorTranslateOptions.
22
+ attr_reader :c_pointer
23
+
24
+ # @return [Array<String>] The options.
25
+ attr_reader :options
26
+
27
+ # Create a new instance.
28
+ #
29
+ # @see https://gdal.org/programs/ogr2ogr.html
30
+ # List of available options could be found in ogr2ogr utility documentation.
31
+ #
32
+ # @example Create a new instance.
33
+ # options = GDAL::Utils::VectorTranslate::Options.new(options: ["-overwrite", "-nlt", "MULTIPOLYGON"])
34
+ #
35
+ # @param options [Array<String>] The options list.
36
+ def initialize(options: [])
37
+ @options = options
38
+ @string_list = ::GDAL::Utils::Helpers::StringList.new(strings: options)
39
+ @c_pointer = AutoPointer.new(options_pointer)
40
+ end
41
+
42
+ private
43
+
44
+ attr_reader :string_list
45
+
46
+ def options_pointer
47
+ ::FFI::GDAL::Utils.GDALVectorTranslateOptionsNew(string_list.c_pointer, nil)
48
+ end
49
+ end
50
+ end
51
+ end
52
+ end
@@ -0,0 +1,132 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "vector_translate/options"
4
+
5
+ module GDAL
6
+ module Utils
7
+ # Wrapper for ogr2ogr using GDALVectorTranslate C API.
8
+ #
9
+ # @see https://gdal.org/programs/ogr2ogr.html ogr2ogr utility documentation.
10
+ # @see https://gdal.org/api/gdal_utils.html#_CPPv419GDALVectorTranslatePKc12GDALDatasetHiP12GDALDatasetHPK26GDALVectorTranslateOptionsPi
11
+ # GDALVectorTranslate C API.
12
+ class VectorTranslate
13
+ # Perform the ogr2ogr (GDALVectorTranslate) operation.
14
+ #
15
+ # @example Translate a vector dataset (for dst_dataset_path).
16
+ # src_dataset = OGR::DataSource.open("source.shp", "r")
17
+ # dataset = GDAL::Utils::VectorTranslate.perform(
18
+ # dst_dataset_path: "destination.geojson",
19
+ # src_datasets: [src_dataset]
20
+ # )
21
+ #
22
+ # # Do something with the dataset.
23
+ # puts dataset.layer(0).name
24
+ #
25
+ # # You must close the dataset when you are done with it.
26
+ # dataset.close
27
+ # src_dataset.close
28
+ #
29
+ # @example Translate a vector dataset with options (for dst_dataset_path).
30
+ # src_dataset = OGR::DataSource.open("source.shp", "r")
31
+ # dataset = GDAL::Utils::VectorTranslate.perform(
32
+ # dst_dataset_path: "destination.geojson",
33
+ # src_datasets: [src_dataset],
34
+ # options: GDAL::Utils::VectorTranslate::Options.new(options: ["-nlt", "MULTIPOLYGON"])
35
+ # )
36
+ #
37
+ # # Do something with the dataset.
38
+ # puts dataset.layer(0).name
39
+ #
40
+ # # You must close the dataset when you are done with it.
41
+ # dataset.close
42
+ # src_dataset.close
43
+ #
44
+ # @example Translate a vector dataset using block syntax (for dst_dataset_path).
45
+ # src_dataset = OGR::DataSource.open("source.shp", "r")
46
+ # GDAL::Utils::VectorTranslate.perform(
47
+ # dst_dataset_path: "destination.geojson",
48
+ # src_datasets: [src_dataset]
49
+ # ) do |dataset|
50
+ # # Do something with the dataset.
51
+ # puts dataset.layer(0).name
52
+ #
53
+ # # Dataset will be closed automatically.
54
+ # end
55
+ # src_dataset.close
56
+ #
57
+ # @example Translate a vector dataset (for dst_dataset).
58
+ # src_dataset = OGR::DataSource.open("source.shp", "r")
59
+ # dst_dataset = OGR::DataSource.open("destination.geojson", "w")
60
+ #
61
+ # GDAL::Utils::VectorTranslate.perform(dst_dataset: dst_dataset, src_datasets: [src_dataset])
62
+ #
63
+ # # You must close the dataset when you are done with it.
64
+ # dst_dataset.close
65
+ # src_dataset.close
66
+ #
67
+ # @example Translate a vector dataset with options (for dst_dataset).
68
+ # src_dataset = OGR::DataSource.open("source.shp", "r")
69
+ # dst_dataset = OGR::DataSource.open("destination.geojson", "w")
70
+ #
71
+ # GDAL::Utils::VectorTranslate.perform(
72
+ # dst_dataset: dst_dataset,
73
+ # src_datasets: [src_dataset],
74
+ # options: GDAL::Utils::VectorTranslate::Options.new(options: ["-nlt", "MULTIPOLYGON"])
75
+ # )
76
+ #
77
+ # # You must close the dataset when you are done with it.
78
+ # dst_dataset.close
79
+ # src_dataset.close
80
+ #
81
+ # @param dst_dataset_path [String] The path to the destination dataset.
82
+ # @param dst_dataset [OGR::DataSource] The destination dataset.
83
+ # @param src_datasets [Array<OGR::DataSource>] The source datasets.
84
+ # @param options [GDAL::Utils::VectorTranslate::Options] Options.
85
+ # @yield [OGR::DataSource] The destination dataset.
86
+ # @return [OGR::DataSource] The destination dataset (only if block is not specified; dataset must be closed).
87
+ def self.perform(dst_dataset: nil, dst_dataset_path: nil, src_datasets: [], options: Options.new, &block)
88
+ if dst_dataset
89
+ for_dataset(dst_dataset: dst_dataset, src_datasets: src_datasets, options: options)
90
+ else
91
+ for_dataset_path(dst_dataset_path: dst_dataset_path, src_datasets: src_datasets, options: options, &block)
92
+ end
93
+ end
94
+
95
+ def self.for_dataset(dst_dataset:, src_datasets: [], options: Options.new)
96
+ result_dataset_ptr(dst_dataset: dst_dataset, src_datasets: src_datasets, options: options)
97
+
98
+ # Return the input dataset as the output dataset (dataset is modified in place).
99
+ dst_dataset
100
+ end
101
+ private_class_method :for_dataset
102
+
103
+ def self.for_dataset_path(dst_dataset_path:, src_datasets: [], options: Options.new, &block)
104
+ dst_dataset_ptr = result_dataset_ptr(
105
+ dst_dataset_path: dst_dataset_path, src_datasets: src_datasets, options: options
106
+ )
107
+
108
+ ::OGR::DataSource.open(dst_dataset_ptr, "w", &block)
109
+ end
110
+ private_class_method :for_dataset_path
111
+
112
+ def self.result_dataset_ptr(dst_dataset_path: nil, dst_dataset: nil, src_datasets: [], options: Options.new)
113
+ src_dataset_list = ::GDAL::Utils::Helpers::DatasetList.new(datasets: src_datasets)
114
+ result_code_ptr = ::FFI::MemoryPointer.new(:int)
115
+ dst_dataset_ptr = ::FFI::GDAL::Utils.GDALVectorTranslate(
116
+ dst_dataset_path,
117
+ dst_dataset&.c_pointer,
118
+ src_dataset_list.count,
119
+ src_dataset_list.c_pointer,
120
+ options.c_pointer,
121
+ result_code_ptr
122
+ )
123
+ success = result_code_ptr.read_int.zero?
124
+
125
+ raise ::GDAL::Error, "GDALVectorTranslate failed." if dst_dataset_ptr.null? || !success
126
+
127
+ dst_dataset_ptr
128
+ end
129
+ private_class_method :result_dataset_ptr
130
+ end
131
+ end
132
+ end
@@ -0,0 +1,52 @@
1
+ # frozen_string_literal: true
2
+
3
+ module GDAL
4
+ module Utils
5
+ class Warp
6
+ # Ruby wrapper for GDALWarpAppOptions C API (options for ogr2ogr utility).
7
+ #
8
+ # @see GDAL::Utils::Warp
9
+ # @see https://gdal.org/programs/gdalwarp.html gdalwarp utility documentation.
10
+ class Options
11
+ # @private
12
+ class AutoPointer < ::FFI::AutoPointer
13
+ # @param pointer [FFI::Pointer]
14
+ def self.release(pointer)
15
+ return unless pointer && !pointer.null?
16
+
17
+ ::FFI::GDAL::Utils.GDALWarpAppOptionsFree(pointer)
18
+ end
19
+ end
20
+
21
+ # @return [AutoPointer] C pointer to the GDALWarpAppOptions.
22
+ attr_reader :c_pointer
23
+
24
+ # @return [Array<String>] The options.
25
+ attr_reader :options
26
+
27
+ # Create a new instance.
28
+ #
29
+ # @see https://gdal.org/programs/gdalwarp.html
30
+ # List of available options could be found in gdalwarp utility documentation.
31
+ #
32
+ # @example Create a new instance.
33
+ # options = GDAL::Utils::Warp::Options.new(options: ["-multi", "-wo", "CUTLINE_ALL_TOUCHED=TRUE"])
34
+ #
35
+ # @param options [Array<String>] The options list.
36
+ def initialize(options: [])
37
+ @options = options
38
+ @string_list = ::GDAL::Utils::Helpers::StringList.new(strings: options)
39
+ @c_pointer = AutoPointer.new(options_pointer)
40
+ end
41
+
42
+ private
43
+
44
+ attr_reader :string_list
45
+
46
+ def options_pointer
47
+ ::FFI::GDAL::Utils.GDALWarpAppOptionsNew(string_list.c_pointer, nil)
48
+ end
49
+ end
50
+ end
51
+ end
52
+ end
@@ -0,0 +1,118 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "warp/options"
4
+
5
+ module GDAL
6
+ module Utils
7
+ # Wrapper for gdalwarp using GDALWarp C API.
8
+ #
9
+ # @see https://gdal.org/programs/gdalwarp.html gdalwarp utility documentation.
10
+ # @see https://gdal.org/api/gdal_utils.html#_CPPv48GDALWarpPKc12GDALDatasetHiP12GDALDatasetHPK18GDALWarpAppOptionsPi
11
+ # GDALWarp C API.
12
+ class Warp
13
+ # Perform the gdalwarp (GDALWarp) operation.
14
+ #
15
+ # @example Warp a dataset (for dst_dataset_path).
16
+ # src_dataset = GDAL::Dataset.open("source.tif", "r")
17
+ # options = GDAL::Utils::Warp::Options.new(options: ["-t_srs", "EPSG:3857"])
18
+ #
19
+ # dataset = GDAL::Utils::Warp.perform(
20
+ # dst_dataset_path: "destination.tif",
21
+ # src_datasets: [src_dataset],
22
+ # options: options
23
+ # )
24
+ #
25
+ # # Do something with the dataset.
26
+ # puts dataset.raster_x_size
27
+ #
28
+ # # You must close the dataset when you are done with it.
29
+ # dataset.close
30
+ # src_dataset.close
31
+ #
32
+ # @example Warp a dataset (for dst_dataset_path) using block syntax.
33
+ # src_dataset = GDAL::Dataset.open("source.tif", "r")
34
+ # options = GDAL::Utils::Warp::Options.new(options: ["-t_srs", "EPSG:3857"])
35
+ #
36
+ # GDAL::Utils::Warp.perform(
37
+ # dst_dataset_path: "destination.tif",
38
+ # src_datasets: src_dataset,
39
+ # options: options
40
+ # ) do |dataset|
41
+ # # Do something with the dataset.
42
+ # puts dataset.raster_x_size
43
+ #
44
+ # # Dataset will be closed automatically.
45
+ # end
46
+ # src_dataset.close
47
+ #
48
+ # @example Warp a dataset (for dst_dataset).
49
+ # src_dataset = GDAL::Dataset.open("source.tif", "r")
50
+ # dst_dataset = GDAL::Dataset.open("destination.tif", "w") # Dataset with other projection.
51
+ #
52
+ # GDAL::Utils::Warp.perform(dst_dataset: dst_dataset, src_datasets: [src_dataset])
53
+ #
54
+ # # You must close the dataset when you are done with it.
55
+ # dst_dataset.close
56
+ # src_dataset.close
57
+ #
58
+ # @param dst_dataset_path [String] The path to the destination dataset.
59
+ # @param dst_dataset [GDAL::Dataset] The destination dataset.
60
+ # @param src_datasets [Array<GDAL::Dataset>] The source datasets.
61
+ # @param options [GDAL::Utils::Warp::Options] Options.
62
+ # @yield [GDAL::Dataset] The destination dataset.
63
+ # @return [GDAL::Dataset] The destination dataset (only if block is not specified; dataset must be closed).
64
+ def self.perform(dst_dataset: nil, dst_dataset_path: nil, src_datasets: [], options: Options.new, &block)
65
+ if dst_dataset
66
+ for_dataset(dst_dataset: dst_dataset, src_datasets: src_datasets, options: options)
67
+ else
68
+ for_dataset_path(dst_dataset_path: dst_dataset_path, src_datasets: src_datasets, options: options, &block)
69
+ end
70
+ end
71
+
72
+ # @param dst_dataset [GDAL::Dataset] The destination dataset.
73
+ # @param src_datasets [Array<GDAL::Dataset>] The source datasets.
74
+ # @param options [GDAL::Utils::Warp::Options] Options.
75
+ # @return [GDAL::Dataset] The destination dataset (it's the same object as dst_dataset).
76
+ def self.for_dataset(dst_dataset:, src_datasets: [], options: Options.new)
77
+ result_dataset_ptr(dst_dataset: dst_dataset, src_datasets: src_datasets, options: options)
78
+
79
+ # Return the input dataset as the output dataset (dataset is modified in place).
80
+ dst_dataset
81
+ end
82
+ private_class_method :for_dataset
83
+
84
+ # @param dst_dataset_path [String] The path to the destination dataset.
85
+ # @param src_datasets [Array<GDAL::Dataset>] The source datasets.
86
+ # @param options [GDAL::Utils::Warp::Options] Options.
87
+ # @yield [GDAL::Dataset] The destination dataset.
88
+ # @return [GDAL::Dataset] The destination dataset (only if block is not specified; dataset must be closed).
89
+ def self.for_dataset_path(dst_dataset_path:, src_datasets: [], options: Options.new, &block)
90
+ dst_dataset_ptr = result_dataset_ptr(
91
+ dst_dataset_path: dst_dataset_path, src_datasets: src_datasets, options: options
92
+ )
93
+
94
+ ::GDAL::Dataset.open(dst_dataset_ptr, "w", &block)
95
+ end
96
+ private_class_method :for_dataset_path
97
+
98
+ def self.result_dataset_ptr(dst_dataset_path: nil, dst_dataset: nil, src_datasets: [], options: Options.new)
99
+ src_dataset_list = ::GDAL::Utils::Helpers::DatasetList.new(datasets: src_datasets)
100
+ result_code_ptr = ::FFI::MemoryPointer.new(:int)
101
+ dst_dataset_ptr = ::FFI::GDAL::Utils.GDALWarp(
102
+ dst_dataset_path,
103
+ dst_dataset&.c_pointer,
104
+ src_dataset_list.count,
105
+ src_dataset_list.c_pointer,
106
+ options.c_pointer,
107
+ result_code_ptr
108
+ )
109
+ success = result_code_ptr.read_int.zero?
110
+
111
+ raise ::GDAL::Error, "GDALWarp failed." if dst_dataset_ptr.null? || !success
112
+
113
+ dst_dataset_ptr
114
+ end
115
+ private_class_method :result_dataset_ptr
116
+ end
117
+ end
118
+ end
data/lib/gdal/utils.rb ADDED
@@ -0,0 +1,22 @@
1
+ # frozen_string_literal: true
2
+
3
+ module GDAL
4
+ # Wrappers for the GDAL utilities.
5
+ #
6
+ # @see https://gdal.org/programs/index.html GDAL Utils documentation (gdalwarp, gdal_translate, ...).
7
+ # @see https://gdal.org/api/gdal_utils.html GDAL Utils C API.
8
+ module Utils
9
+ # Internal helpers
10
+ autoload :Helpers, File.expand_path("utils/helpers", __dir__)
11
+
12
+ # GDAL Utils
13
+ autoload :DEM, File.expand_path("utils/dem", __dir__)
14
+ autoload :Grid, File.expand_path("utils/grid", __dir__)
15
+ autoload :Nearblack, File.expand_path("utils/nearblack", __dir__)
16
+ autoload :Rasterize, File.expand_path("utils/rasterize", __dir__)
17
+ autoload :Info, File.expand_path("utils/info", __dir__)
18
+ autoload :Translate, File.expand_path("utils/translate", __dir__)
19
+ autoload :VectorTranslate, File.expand_path("utils/vector_translate", __dir__)
20
+ autoload :Warp, File.expand_path("utils/warp", __dir__)
21
+ end
22
+ end
@@ -12,7 +12,7 @@ module GDAL
12
12
  @destination_dataset = nil
13
13
 
14
14
  options.each_key do |k|
15
- assign_meth = "#{k}=".to_sym
15
+ assign_meth = :"#{k}="
16
16
 
17
17
  begin
18
18
  if respond_to?(assign_meth)
@@ -175,8 +175,17 @@ module GDAL
175
175
  def source_per_band_validity_mask_function=(band_procs)
176
176
  mask_func = FFI::GDAL::Warper::MaskFunc
177
177
 
178
+ mask_func_return_type =
179
+ if mask_func.respond_to?(:return_type)
180
+ # `.return_type` is for FFI 1.16.0+;
181
+ mask_func.return_type
182
+ else
183
+ # `.result_type` is for older FFI versions.
184
+ mask_func.result_type
185
+ end
186
+
178
187
  funcs = band_procs.map do |band_proc|
179
- FFI::Function.new(mask_func.result_type, mask_func.param_types, band_proc, blocking: true)
188
+ FFI::Function.new(mask_func_return_type, mask_func.param_types, band_proc, blocking: true)
180
189
  end
181
190
 
182
191
  pointer = FFI::MemoryPointer.new(:pointer, band_procs.length)
data/lib/gdal.rb CHANGED
@@ -37,6 +37,7 @@ module GDAL
37
37
  autoload :Options, gdal_require("gdal/options")
38
38
  autoload :RasterAttributeTable, gdal_require("gdal/raster_attribute_table")
39
39
  autoload :RasterBand, gdal_require("gdal/raster_band")
40
+ autoload :Utils, gdal_require("gdal/utils")
40
41
  end
41
42
 
42
43
  require_relative "gdal/exceptions"
@@ -44,14 +44,6 @@ module OGR
44
44
  !equals?(other)
45
45
  end
46
46
 
47
- def is_2d?
48
- coordinate_dimension == 2
49
- end
50
-
51
- def is_3d?
52
- coordinate_dimension == 3
53
- end
54
-
55
47
  # @return [Boolean]
56
48
  def invalid?
57
49
  !valid?
@@ -130,7 +130,7 @@ module OGR
130
130
  # least at this point), it needs to be as fast as possible.
131
131
  each_feature_pointer do |feature_ptr| # rubocop:todo Metrics/BlockLength
132
132
  field_values = field_indices.map.with_index do |j, attribute_index|
133
- FFI::OGR::API.send("OGR_F_GetFieldAs#{with_attributes.values[attribute_index].capitalize}", feature_ptr, j)
133
+ FFI::OGR::API.send(:"OGR_F_GetFieldAs#{with_attributes.values[attribute_index].capitalize}", feature_ptr, j)
134
134
  end
135
135
 
136
136
  geom_ptr = FFI::OGR::API.OGR_F_GetGeometryRef(feature_ptr)