ffi-gdal 0.0.4 → 1.0.0.beta1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (138) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +7 -1
  3. data/Rakefile +12 -1
  4. data/TODO.md +11 -0
  5. data/ffi-gdal.gemspec +2 -2
  6. data/lib/ext/error_symbols.rb +59 -0
  7. data/lib/ext/float_ext.rb +15 -0
  8. data/lib/ext/narray_ext.rb +16 -0
  9. data/lib/ext/to_bool.rb +2 -0
  10. data/lib/ffi-gdal.rb +139 -4
  11. data/lib/ffi/{gdal/cpl_conv.rb → cpl/conv_h.rb} +2 -3
  12. data/lib/ffi/{gdal/cpl_error.rb → cpl/error_h.rb} +1 -25
  13. data/lib/ffi/cpl/minixml_h.rb +14 -0
  14. data/lib/ffi/{gdal/cpl_string.rb → cpl/string_h.rb} +0 -25
  15. data/lib/ffi/{gdal/cpl_vsi.rb → cpl/vsi_h.rb} +0 -0
  16. data/lib/ffi/cpl/xml_node.rb +13 -0
  17. data/lib/ffi/gdal.rb +57 -593
  18. data/lib/ffi/gdal/alg_h.rb +127 -0
  19. data/lib/ffi/gdal/gdal_grid_data_metrics_options.rb +14 -0
  20. data/lib/ffi/gdal/gdal_grid_inverse_distance_to_a_power_options.rb +19 -0
  21. data/lib/ffi/gdal/gdal_grid_moving_average_options.rb +14 -0
  22. data/lib/ffi/gdal/gdal_grid_nearest_neighbor_options.rb +13 -0
  23. data/lib/ffi/gdal/gdal_h.rb +683 -0
  24. data/lib/ffi/gdal/gdal_rpc_info.rb +27 -0
  25. data/lib/ffi/gdal/gdal_transformer_info.rb +14 -0
  26. data/lib/ffi/gdal/gdal_warp_options.rb +43 -0
  27. data/lib/ffi/gdal/grid_h.rb +51 -0
  28. data/lib/ffi/gdal/version.rb +1 -1
  29. data/lib/ffi/gdal/warper_h.rb +48 -0
  30. data/lib/ffi/ogr.rb +12 -0
  31. data/lib/ffi/ogr/api_h.rb +553 -0
  32. data/lib/ffi/ogr/core_h.rb +148 -0
  33. data/lib/ffi/ogr/featurestyle_h.rb +22 -0
  34. data/lib/ffi/ogr/geocoding_h.rb +21 -0
  35. data/lib/ffi/ogr/ogr_contour_writer_info.rb +14 -0
  36. data/lib/ffi/ogr/ogr_envelope.rb +12 -0
  37. data/lib/ffi/ogr/ogr_envelope_3d.rb +14 -0
  38. data/lib/ffi/ogr/ogr_field.rb +50 -0
  39. data/lib/ffi/ogr/ogr_style_param.rb +12 -0
  40. data/lib/ffi/ogr/ogr_style_value.rb +13 -0
  41. data/lib/ffi/ogr/srs_api_h.rb +325 -0
  42. data/lib/gdal/color_entry.rb +47 -0
  43. data/lib/gdal/color_entry_extensions.rb +30 -0
  44. data/lib/gdal/color_interpretation.rb +15 -0
  45. data/lib/gdal/color_table.rb +146 -0
  46. data/lib/gdal/color_table_extensions.rb +47 -0
  47. data/lib/gdal/color_table_types/cmyk.rb +25 -0
  48. data/lib/gdal/color_table_types/gray.rb +9 -0
  49. data/lib/gdal/color_table_types/hls.rb +21 -0
  50. data/lib/gdal/color_table_types/rgb.rb +25 -0
  51. data/lib/gdal/data_type.rb +38 -0
  52. data/lib/gdal/dataset.rb +437 -0
  53. data/lib/gdal/dataset_extensions.rb +496 -0
  54. data/lib/gdal/driver.rb +244 -0
  55. data/lib/gdal/driver_extensions.rb +56 -0
  56. data/lib/gdal/environment_methods.rb +43 -0
  57. data/lib/{ffi-gdal → gdal}/exceptions.rb +4 -1
  58. data/lib/gdal/geo_transform.rb +188 -0
  59. data/lib/gdal/geo_transform_extensions.rb +90 -0
  60. data/lib/gdal/logger.rb +7 -0
  61. data/lib/{ffi-gdal → gdal}/major_object.rb +15 -14
  62. data/lib/gdal/options.rb +49 -0
  63. data/lib/gdal/raster_attribute_table.rb +185 -0
  64. data/lib/gdal/raster_attribute_table_extensions.rb +40 -0
  65. data/lib/{ffi-gdal → gdal}/raster_band.rb +227 -99
  66. data/lib/gdal/raster_band_extensions.rb +198 -0
  67. data/lib/{ffi-gdal → gdal}/version_info.rb +8 -0
  68. data/lib/gdal/warp_operation.rb +96 -0
  69. data/lib/ogr/coordinate_transformation.rb +108 -0
  70. data/lib/ogr/data_source.rb +172 -0
  71. data/lib/ogr/data_source_extensions.rb +32 -0
  72. data/lib/ogr/driver.rb +119 -0
  73. data/lib/ogr/envelope.rb +80 -0
  74. data/lib/ogr/envelope_extensions.rb +92 -0
  75. data/lib/ogr/exceptions.rb +35 -0
  76. data/lib/ogr/feature.rb +212 -0
  77. data/lib/ogr/feature_definition.rb +120 -0
  78. data/lib/ogr/feature_definition_extensions.rb +36 -0
  79. data/lib/ogr/feature_extensions.rb +31 -0
  80. data/lib/ogr/field.rb +91 -0
  81. data/lib/ogr/field_extensions.rb +23 -0
  82. data/lib/ogr/geocoding_session.rb +84 -0
  83. data/lib/ogr/geometry.rb +617 -0
  84. data/lib/ogr/geometry_extensions.rb +60 -0
  85. data/lib/ogr/geometry_types/collection.rb +45 -0
  86. data/lib/ogr/geometry_types/curve.rb +120 -0
  87. data/lib/ogr/geometry_types/surface.rb +20 -0
  88. data/lib/ogr/layer.rb +226 -0
  89. data/lib/ogr/layer_extensions.rb +55 -0
  90. data/lib/ogr/line_string.rb +7 -0
  91. data/lib/ogr/linear_ring.rb +6 -0
  92. data/lib/ogr/multi_line_string.rb +9 -0
  93. data/lib/ogr/multi_point.rb +7 -0
  94. data/lib/ogr/multi_polygon.rb +14 -0
  95. data/lib/ogr/point.rb +89 -0
  96. data/lib/ogr/polygon.rb +9 -0
  97. data/lib/ogr/spatial_reference.rb +723 -0
  98. data/lib/ogr/spatial_reference_extensions.rb +32 -0
  99. data/lib/ogr/style_table.rb +17 -0
  100. data/lib/ogr/style_table_extensions.rb +16 -0
  101. data/spec/{ffi-gdal/integration → integration}/color_table_info_spec.rb +1 -1
  102. data/spec/{ffi-gdal/integration → integration}/dataset_info_spec.rb +0 -0
  103. data/spec/{ffi-gdal/integration → integration}/driver_info_spec.rb +1 -1
  104. data/spec/{ffi-gdal/integration → integration}/geo_transform_info_spec.rb +0 -0
  105. data/spec/{ffi-gdal/integration → integration}/raster_attribute_table_info_spec.rb +1 -1
  106. data/spec/{ffi-gdal/integration → integration}/raster_band_info_spec.rb +5 -5
  107. data/spec/spec_helper.rb +4 -1
  108. data/spec/support/shapefiles/states_21basic/states.prj +1 -0
  109. data/spec/support/shapefiles/states_21basic/states.sbn +0 -0
  110. data/spec/support/shapefiles/states_21basic/states.sbx +0 -0
  111. data/spec/support/shapefiles/states_21basic/states.shp +0 -0
  112. data/spec/support/worldfiles/SR_50M/SR_50M.VERSION.txt +1 -0
  113. data/spec/support/worldfiles/SR_50M/SR_50M.prj +1 -0
  114. data/spec/support/worldfiles/SR_50M/SR_50M.tfw +6 -0
  115. data/spec/{ext/cpl_error_symbols_spec.rb → unit/ext/error_symbols_spec.rb} +1 -1
  116. data/spec/unit/gdal/color_table_spec.rb +146 -0
  117. data/spec/unit/ogr/layer_spec.rb +97 -0
  118. data/spec/unit/ogr/linear_ring_spec.rb +111 -0
  119. data/spec/unit/ogr/point_spec.rb +321 -0
  120. data/spec/{ffi-gdal/unit → unit}/version_info_spec.rb +1 -1
  121. data/testing_gdal.rb +168 -0
  122. data/testing_gdalwarp.rb +91 -0
  123. data/testing_layer_to_layer.rb +35 -0
  124. data/testing_ndvi.rb +76 -0
  125. data/testing_nir.rb +77 -0
  126. data/testing_ogr.rb +63 -0
  127. metadata +167 -59
  128. data/lib/ext/cpl_error_symbols.rb +0 -37
  129. data/lib/ffi-gdal/color_table.rb +0 -59
  130. data/lib/ffi-gdal/dataset.rb +0 -359
  131. data/lib/ffi-gdal/driver.rb +0 -151
  132. data/lib/ffi-gdal/geo_transform.rb +0 -137
  133. data/lib/ffi-gdal/raster_attribute_table.rb +0 -78
  134. data/lib/ffi/gdal/ogr_api.rb +0 -21
  135. data/lib/ffi/gdal/ogr_core.rb +0 -195
  136. data/lib/ffi/gdal/ogr_srs_api.rb +0 -44
  137. data/meow.rb +0 -144
  138. data/rubby.rb +0 -224
@@ -0,0 +1,32 @@
1
+ module OGR
2
+ module DataSourceExtensions
3
+
4
+ # @return [Array<OGR::Layer>]
5
+ def layers
6
+ l = 0.upto(layer_count - 1).map do |i|
7
+ layer(i)
8
+ end
9
+
10
+ @layers = l
11
+ end
12
+
13
+ # @return [Hash]
14
+ def as_json
15
+ {
16
+ data_source: {
17
+ driver: driver.name,
18
+ layer_count: layer_count,
19
+ layers: layers.map(&:as_json),
20
+ name: name,
21
+ style_table: style_table ? style_table.as_json : nil
22
+ },
23
+ metadata: all_metadata
24
+ }
25
+ end
26
+
27
+ # @return [String]
28
+ def to_json
29
+ as_json.to_json
30
+ end
31
+ end
32
+ end
data/lib/ogr/driver.rb ADDED
@@ -0,0 +1,119 @@
1
+ module OGR
2
+ class Driver
3
+ include GDAL::MajorObject
4
+ include GDAL::Logger
5
+
6
+ # @return [Fixnum]
7
+ def self.count
8
+ FFI::GDAL.OGRGetDriverCount
9
+ end
10
+
11
+ # @param name [String] Short name of the registered OGRDriver.
12
+ # @return [OGR::Driver]
13
+ def self.by_name(name)
14
+ driver_ptr = FFI::GDAL.OGRGetDriverByName(name)
15
+ return nil if driver_ptr.null?
16
+
17
+ new(driver_ptr)
18
+ end
19
+
20
+ # @param index [Fixnum] Index of the registered driver. Must be less than
21
+ # OGR::Driver.count.
22
+ # @return [OGR::Driver]
23
+ def self.at_index(index)
24
+ if index > count
25
+ raise "index must be between 0 and #{count - 1}."
26
+ end
27
+
28
+ driver_ptr = FFI::GDAL.OGRGetDriver(index)
29
+ return nil if driver_ptr.null?
30
+
31
+ new(driver_ptr)
32
+ end
33
+
34
+ # @return [Array<String>]
35
+ def self.names
36
+ return @names if @names
37
+
38
+ names = 0.upto(count - 1).map do |i|
39
+ at_index(i).name
40
+ end
41
+
42
+ @names = names.compact.sort
43
+ end
44
+
45
+ # @param driver [OGR::Driver, FFI::Pointer]
46
+ def initialize(driver)
47
+ @driver_pointer = GDAL._pointer(OGR::Driver, driver)
48
+ end
49
+
50
+ def c_pointer
51
+ @driver_pointer
52
+ end
53
+
54
+ # @return [String]
55
+ def name
56
+ FFI::GDAL.OGR_Dr_GetName(@driver_pointer)
57
+ end
58
+
59
+ # @param file_name [String]
60
+ # @param access_flag [String] 'r' or 'w'.
61
+ # @return [OGR::DataSource, nil]
62
+ def open(file_name, access_flag = 'r')
63
+ update = OGR._boolean_access_flag(access_flag)
64
+
65
+ data_source_ptr = FFI::GDAL.OGR_Dr_Open(@driver_pointer, file_name, update)
66
+ return nil if data_source_ptr.null?
67
+
68
+ OGR::DataSource.new(data_source_ptr)
69
+ end
70
+
71
+ # Creates a new data source at path +file_name+. Yields the newly created
72
+ # data source to a block, if given. NOTE: in order to write out all
73
+ # in-memory data, you need to call #close on the created DataSource.
74
+ #
75
+ # @param file_name [String]
76
+ # @param options [Hash]
77
+ # @return [OGR::DataSource, nil]
78
+ def create_data_source(file_name, **options)
79
+ options_ptr = GDAL::Options.pointer(options)
80
+
81
+ data_source_ptr = FFI::GDAL.OGR_Dr_CreateDataSource(@driver_pointer,
82
+ file_name, options_ptr)
83
+ return nil if data_source_ptr.null?
84
+
85
+ ds = OGR::DataSource.new(data_source_ptr)
86
+
87
+ yield ds if block_given?
88
+
89
+ ds
90
+ rescue GDAL::InvalidBandNumber
91
+ ds.close if ds
92
+ delete_data_source(file_name)
93
+ raise
94
+ end
95
+
96
+ # @param file_name [String]
97
+ # @return +true+ if successful, otherwise raises an OGR exception.
98
+ def delete_data_source(file_name)
99
+ ogr_err = FFI::GDAL.OGR_Dr_DeleteDataSource(@driver_pointer, file_name)
100
+
101
+ ogr_err.to_ruby
102
+ end
103
+
104
+ # @param source_data_source [OGR::DataSource, FFI::Pointer]
105
+ # @param new_file_name [String]
106
+ # @param options [Hash]
107
+ # @return [OGR::DataSource, nil]
108
+ def copy_data_source(source_data_source, new_file_name, **options)
109
+ source_ptr = GDAL._pointer(OGR::DataSource, source_data_source)
110
+ options_ptr = GDAL::Options.pointer(options)
111
+
112
+ data_source_ptr = FFI::GDAL.OGR_Dr_CopyDataSource(@driver_pointer,
113
+ source_ptr, new_file_name, options_ptr)
114
+ return nil if data_source_ptr.null?
115
+
116
+ OGR::DataSource.new(data_source_ptr)
117
+ end
118
+ end
119
+ end
@@ -0,0 +1,80 @@
1
+ require_relative '../ffi/ogr'
2
+ require_relative 'envelope_extensions'
3
+
4
+ module OGR
5
+ class Envelope
6
+ include EnvelopeExtensions
7
+
8
+ def initialize(ogr_envelope_struct)
9
+ @ogr_envelope_struct = ogr_envelope_struct
10
+ end
11
+
12
+ # @return [Float]
13
+ def x_min
14
+ @ogr_envelope_struct[:min_x]
15
+ end
16
+
17
+ # @param new_x_min [Float]
18
+ def x_min=(new_x_min)
19
+ @ogr_envelope_struct[:min_x] = new_x_min
20
+ end
21
+
22
+ # @return [Float]
23
+ def x_max
24
+ @ogr_envelope_struct[:max_x]
25
+ end
26
+
27
+ # @param new_x_max [Float]
28
+ def x_max=(new_x_max)
29
+ @ogr_envelope_struct[:max_x] = new_x_max
30
+ end
31
+
32
+ # @return [Float]
33
+ def y_min
34
+ @ogr_envelope_struct[:min_y]
35
+ end
36
+
37
+ # @param new_y_min [Float]
38
+ def y_min=(new_y_min)
39
+ @ogr_envelope_struct[:min_y] = new_y_min
40
+ end
41
+
42
+ # @return [Float]
43
+ def y_max
44
+ @ogr_envelope_struct[:max_y]
45
+ end
46
+
47
+ # @param new_y_max [Float]
48
+ def y_max=(new_y_max)
49
+ @ogr_envelope_struct[:max_y] = new_y_max
50
+ end
51
+
52
+ # @return [Float, nil]
53
+ def z_min
54
+ return nil unless @ogr_envelope_struct.is_a? FFI::GDAL::OGREnvelope3D
55
+
56
+ @ogr_envelope_struct[:min_z]
57
+ end
58
+
59
+ # @param new_z_min [Float]
60
+ def z_min=(new_z_min)
61
+ return nil unless @ogr_envelope_struct.is_a? FFI::GDAL::OGREnvelope3D
62
+
63
+ @ogr_envelope_struct[:min_z] = new_z_min
64
+ end
65
+
66
+ # @return [Float, nil]
67
+ def z_max
68
+ return nil unless @ogr_envelope_struct.is_a? FFI::GDAL::OGREnvelope3D
69
+
70
+ @ogr_envelope_struct[:max_z]
71
+ end
72
+
73
+ # @param new_z_max [Float]
74
+ def z_max=(new_z_max)
75
+ return nil unless @ogr_envelope_struct.is_a? FFI::GDAL::OGREnvelope3D
76
+
77
+ @ogr_envelope_struct[:max_z] = new_z_max
78
+ end
79
+ end
80
+ end
@@ -0,0 +1,92 @@
1
+ require 'json'
2
+
3
+ module OGR
4
+ module EnvelopeExtensions
5
+
6
+ # Adapted from "Advanced Geospatial Python Modeling". Calculates the
7
+ # pixel locations of these geospatial coordinates.
8
+ #
9
+ # @param geo_transform [GDAL::GeoTransform]
10
+ # @param value_type [Symbol] Data type to return: :float or :integer.
11
+ # @return [Hash<x_origin, y_origin, x_max, y_max>]
12
+ def world_to_pixel(geo_transform, value_type=:integer)
13
+ min_values = geo_transform.world_to_pixel(x_min, y_max)
14
+ max_values = geo_transform.world_to_pixel(x_max, y_min)
15
+ pixel_count = max_values[:x] - min_values[:x]
16
+ line_count = max_values[:y] - min_values[:y]
17
+ pixel_width = (x_max - x_min) / pixel_count
18
+ pixel_height = (y_max - y_min) / pixel_count
19
+
20
+ case value_type
21
+ when :float
22
+ {
23
+ x_origin: min_values[:x].to_f.abs,
24
+ y_origin: min_values[:y].to_f.abs,
25
+ x_max: max_values[:x].to_f.abs,
26
+ y_max: max_values[:y].to_f.abs,
27
+ pixel_count: pixel_count.to_i.abs,
28
+ line_count: line_count.to_i.abs,
29
+ pixel_width: pixel_width.to_f,
30
+ pixel_height: pixel_height.to_f
31
+ }
32
+ when :integer
33
+ {
34
+ x_origin: min_values[:x].to_i.abs,
35
+ y_origin: min_values[:y].to_i.abs,
36
+ x_max: max_values[:x].to_i.abs,
37
+ y_max: max_values[:y].to_i.abs,
38
+ pixel_count: pixel_count.to_i.abs,
39
+ line_count: line_count.to_i.abs,
40
+ pixel_width: pixel_width.to_f,
41
+ pixel_height: pixel_height.to_f
42
+ }
43
+ else
44
+ {
45
+ x_origin: min_values[:x].abs,
46
+ y_origin: min_values[:y].abs,
47
+ x_max: max_values[:x].abs,
48
+ y_max: max_values[:y].abs,
49
+ pixel_count: pixel_count.to_i.abs,
50
+ line_count: line_count.to_i.abs,
51
+ pixel_width: pixel_width.to_f,
52
+ pixel_height: pixel_height.to_f
53
+ }
54
+ end
55
+ end
56
+
57
+ # Compares min/max X and min/max Y to the other envelope. The envelopes are
58
+ # considered equal if those values are the same.
59
+ #
60
+ # @param other_envelope [OGR::Envelope]
61
+ # @return [Boolean]
62
+ def ==(other_envelope)
63
+ x_min == other_envelope.x_min && y_min == other_envelope.y_min &&
64
+ x_max == other_envelope.x_max && y_max == other_envelope.y_max
65
+ end
66
+
67
+ # @return [Hash]
68
+ def as_json
69
+ json = {
70
+ x_min: x_min,
71
+ x_max: x_max,
72
+ y_min: y_min,
73
+ y_max: y_max
74
+ }
75
+
76
+ if @ogr_envelope_struct.is_a? FFI::GDAL::OGREnvelope3D
77
+ json.merge!({ min_z: min_z, max_z: max_z })
78
+ end
79
+
80
+ json
81
+ end
82
+
83
+ # @return [String]
84
+ def to_json
85
+ as_json.to_json
86
+ end
87
+
88
+ def to_a
89
+ [x_min, y_min, x_max, y_max]
90
+ end
91
+ end
92
+ end
@@ -0,0 +1,35 @@
1
+ module OGR
2
+ class OpenFailure < RuntimeError
3
+ def initialize(file, msg=nil)
4
+ message = msg || "Unable to open file '#{file}'. Perhaps an unsupported file format?"
5
+ super(message)
6
+ end
7
+ end
8
+
9
+ class InvalidLayer < RuntimeError
10
+ end
11
+
12
+ class NotEnoughData < RuntimeError
13
+ end
14
+
15
+ class NotEnoughMemory < RuntimeError
16
+ end
17
+
18
+ class UnsupportedGeometryType < RuntimeError
19
+ end
20
+
21
+ class UnsupportedOperation < RuntimeError
22
+ end
23
+
24
+ class CorruptData < RuntimeError
25
+ end
26
+
27
+ class Failure < RuntimeError
28
+ end
29
+
30
+ class UnsupportedSRS < RuntimeError
31
+ end
32
+
33
+ class InvalidHandle < RuntimeError
34
+ end
35
+ end
@@ -0,0 +1,212 @@
1
+ require_relative '../ffi/ogr'
2
+ require_relative 'feature_extensions'
3
+ require_relative 'feature_definition'
4
+ require_relative 'field'
5
+
6
+ module OGR
7
+ class Feature
8
+ include FeatureExtensions
9
+
10
+ # @param feature_definition [OGR::FeatureDefinition,FFI::Pointer]
11
+ # @return [OGR::Feature]
12
+ def self.create(feature_definition)
13
+ feature_def_ptr = GDAL._pointer(OGR::FeatureDefinition, feature_definition)
14
+ feature_ptr = FFI::GDAL::OGR_F_Create(feature_def_ptr)
15
+ return nil if feature_ptr.null?
16
+
17
+ new(feature_ptr)
18
+ end
19
+
20
+ # @param feature [OGR::Feature, FFI::Pointer]
21
+ def initialize(feature)
22
+ @feature_pointer = GDAL._pointer(OGR::Feature, feature)
23
+
24
+ close_me = -> { FFI::GDAL.OGR_F_Destroy(@feature_pointer) }
25
+ ObjectSpace.define_finalizer self, close_me
26
+ end
27
+
28
+ def c_pointer
29
+ @feature_pointer
30
+ end
31
+
32
+ # @return [Fixnum]
33
+ def field_count
34
+ FFI::GDAL.OGR_F_GetFieldCount(@feature_pointer)
35
+ end
36
+
37
+ def add_field(index, value)
38
+ case value.class.name
39
+ when 'String'
40
+ FFI::GDAL.OGR_F_SetFieldString(@feature_pointer, index, value)
41
+ when 'Fixnum'
42
+ FFI::GDAL.OGR_F_SetFieldInteger(@feature_pointer, index, value)
43
+ when 'Float'
44
+ FFI::GDAL.OGR_F_SetFieldDouble(@feature_pointer, index, value)
45
+ when ('Date' or 'Time' or 'DateTime')
46
+ time = value.to_time
47
+ zone = if time.zone =~ /GMT/
48
+ 100
49
+ elsif time.zone
50
+ 1
51
+ else
52
+ 0
53
+ end
54
+
55
+ FFI::GDAL.OGR_F_SetFieldDateTime(@feature_pointer, index,
56
+ time.year,
57
+ time.month,
58
+ time.day,
59
+ time.hour,
60
+ time.min,
61
+ time.sec,
62
+ zone)
63
+ else
64
+ raise "Unknown field type: #{value.class.name}"
65
+ end
66
+ end
67
+
68
+ # @param index [Fixnum]
69
+ # @return [OGR::Field]
70
+ def field(index)
71
+ field_pointer = FFI::GDAL.OGR_F_GetFieldDefnRef(@feature_pointer, index)
72
+ return nil if field_pointer.null?
73
+
74
+ OGR::Field.new(field_pointer)
75
+ end
76
+
77
+ # @param name [String]
78
+ # @return [Fixnum]
79
+ def field_index(name)
80
+ FFI::GDAL.OGR_F_GetFieldIndex(@feature_pointer, name)
81
+ end
82
+
83
+ # @param index [Fixnum]
84
+ # @return [Boolean]
85
+ def field_set?(index)
86
+ FFI::GDAL.OGR_F_IsFieldSet(@feature_pointer, index)
87
+ end
88
+
89
+ # @param index [Fixnum]
90
+ def unset_field(index)
91
+ FFI::GDAL.OGR_F_UnsetField(@feature_pointer, index)
92
+ end
93
+
94
+ # @return [OGR::FeatureDefinition,nil]
95
+ def definition
96
+ return @definition if @definition
97
+
98
+ feature_defn_ptr = FFI::GDAL.OGR_F_GetDefnRef(@feature_pointer)
99
+ return nil if feature_defn_ptr.null?
100
+
101
+ @definition = OGR::FeatureDefinition.new(feature_defn_ptr)
102
+ end
103
+
104
+ # @return [OGR::Geometry]
105
+ def geometry
106
+ return @geometry if @geometry
107
+
108
+ geometry_ptr = FFI::GDAL.OGR_F_GetGeometryRef(@feature_pointer)
109
+ return nil if geometry_ptr.null?
110
+
111
+ @geometry = OGR::Geometry._to_geometry_type(geometry_ptr)
112
+ end
113
+
114
+ # @param new_geometry [OGR::Geometry]
115
+ # @return +true+ if successful, otherwise raises an OGR exception.
116
+ def geometry=(new_geometry)
117
+ ogr_err = FFI::GDAL.OGR_F_SetGeometryDirectly(@feature_pointer, new_geometry.c_pointer)
118
+ @geometry = new_geometry
119
+
120
+ ogr_err.to_ruby
121
+ end
122
+
123
+ # @return [Fixnum]
124
+ def fid
125
+ FFI::GDAL.OGR_F_GetFID(@feature_pointer)
126
+ end
127
+
128
+ # @param new_fid [Fixnum]
129
+ # @return +true+ if successful, otherwise raises an OGR exception.
130
+ def fid=(new_fid)
131
+ ogr_err = FFI::GDAL.OGR_F_SetFID(@feature_pointer, new_fid)
132
+
133
+ ogr_err.to_ruby
134
+ end
135
+
136
+ # @return [Fixnum]
137
+ def geometry_field_count
138
+ FFI::GDAL.OGR_F_GetGeomFieldCount(@feature_pointer)
139
+ end
140
+
141
+ # @return [Boolean]
142
+ def equal?(other_feature)
143
+ FFI::GDAL.OGR_F_Equal(@feature_pointer, feature_pointer_from(other_feature))
144
+ end
145
+ alias_method :equals?, :equal?
146
+
147
+ # @param index [Fixnum]
148
+ # @return [Fixnum]
149
+ def field_as_integer(index)
150
+ FFI::GDAL.OGR_F_GetFieldAsInteger(@feature_pointer, index)
151
+ end
152
+
153
+ # @param index [Fixnum]
154
+ # @return [Array<Fixnum>]
155
+ def field_as_integer_list(index)
156
+ count_ptr = FFI::MemoryPointer.new(:int)
157
+ list_ints = FFI::GDAL.OGR_F_GetFieldAsIntegerList(@feature_pointer, index, count_ptr)
158
+
159
+ list_ints.read_array_of_int
160
+ end
161
+
162
+ # @param index [Fixnum]
163
+ # @return [Float]
164
+ def field_as_double(index)
165
+ FFI::GDAL.OGR_F_GetFieldAsDouble(@feature_pointer, index)
166
+ end
167
+
168
+ # @param index [Fixnum]
169
+ # @return [Array<Float>]
170
+ def field_as_double_list(index)
171
+ count_ptr = FFI::MemoryPointer.new(:int)
172
+ list_ints = FFI::GDAL.OGR_F_GetFieldAsDoubleList(@feature_pointer, index, count_ptr)
173
+
174
+ list_ints.read_array_of_double
175
+ end
176
+
177
+ # @param index [Fixnum]
178
+ # @return [String]
179
+ def field_as_string(index)
180
+ FFI::GDAL.OGR_F_GetFieldAsString(@feature_pointer, index)
181
+ end
182
+
183
+ # @param index [Fixnum]
184
+ # @return [Array<String>]
185
+ def field_as_string_list(index)
186
+ count_ptr = FFI::MemoryPointer.new(:int)
187
+ list_ints = FFI::GDAL.OGR_F_GetFieldAsStringList(@feature_pointer, index, count_ptr)
188
+
189
+ list_ints.read_array_of_string
190
+ end
191
+
192
+ # @return [String]
193
+ def style_string
194
+ FFI::GDAL.OGR_F_GetStyleString(@feature_pointer)
195
+ end
196
+
197
+ # @param new_style [String]
198
+ def style_string=(new_style)
199
+ FFI::GDAL.OGR_F_SetStyleString(@feature_pointer, new_style)
200
+ end
201
+
202
+ private
203
+
204
+ def feature_pointer_from(feature)
205
+ if feature.is_a? OGR::Feature
206
+ feature.c_pointer
207
+ elsif feature.kind_of? FFI::Pointer
208
+ feature
209
+ end
210
+ end
211
+ end
212
+ end