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.
- checksums.yaml +4 -4
- data/.gitignore +7 -1
- data/Rakefile +12 -1
- data/TODO.md +11 -0
- data/ffi-gdal.gemspec +2 -2
- data/lib/ext/error_symbols.rb +59 -0
- data/lib/ext/float_ext.rb +15 -0
- data/lib/ext/narray_ext.rb +16 -0
- data/lib/ext/to_bool.rb +2 -0
- data/lib/ffi-gdal.rb +139 -4
- data/lib/ffi/{gdal/cpl_conv.rb → cpl/conv_h.rb} +2 -3
- data/lib/ffi/{gdal/cpl_error.rb → cpl/error_h.rb} +1 -25
- data/lib/ffi/cpl/minixml_h.rb +14 -0
- data/lib/ffi/{gdal/cpl_string.rb → cpl/string_h.rb} +0 -25
- data/lib/ffi/{gdal/cpl_vsi.rb → cpl/vsi_h.rb} +0 -0
- data/lib/ffi/cpl/xml_node.rb +13 -0
- data/lib/ffi/gdal.rb +57 -593
- data/lib/ffi/gdal/alg_h.rb +127 -0
- data/lib/ffi/gdal/gdal_grid_data_metrics_options.rb +14 -0
- data/lib/ffi/gdal/gdal_grid_inverse_distance_to_a_power_options.rb +19 -0
- data/lib/ffi/gdal/gdal_grid_moving_average_options.rb +14 -0
- data/lib/ffi/gdal/gdal_grid_nearest_neighbor_options.rb +13 -0
- data/lib/ffi/gdal/gdal_h.rb +683 -0
- data/lib/ffi/gdal/gdal_rpc_info.rb +27 -0
- data/lib/ffi/gdal/gdal_transformer_info.rb +14 -0
- data/lib/ffi/gdal/gdal_warp_options.rb +43 -0
- data/lib/ffi/gdal/grid_h.rb +51 -0
- data/lib/ffi/gdal/version.rb +1 -1
- data/lib/ffi/gdal/warper_h.rb +48 -0
- data/lib/ffi/ogr.rb +12 -0
- data/lib/ffi/ogr/api_h.rb +553 -0
- data/lib/ffi/ogr/core_h.rb +148 -0
- data/lib/ffi/ogr/featurestyle_h.rb +22 -0
- data/lib/ffi/ogr/geocoding_h.rb +21 -0
- data/lib/ffi/ogr/ogr_contour_writer_info.rb +14 -0
- data/lib/ffi/ogr/ogr_envelope.rb +12 -0
- data/lib/ffi/ogr/ogr_envelope_3d.rb +14 -0
- data/lib/ffi/ogr/ogr_field.rb +50 -0
- data/lib/ffi/ogr/ogr_style_param.rb +12 -0
- data/lib/ffi/ogr/ogr_style_value.rb +13 -0
- data/lib/ffi/ogr/srs_api_h.rb +325 -0
- data/lib/gdal/color_entry.rb +47 -0
- data/lib/gdal/color_entry_extensions.rb +30 -0
- data/lib/gdal/color_interpretation.rb +15 -0
- data/lib/gdal/color_table.rb +146 -0
- data/lib/gdal/color_table_extensions.rb +47 -0
- data/lib/gdal/color_table_types/cmyk.rb +25 -0
- data/lib/gdal/color_table_types/gray.rb +9 -0
- data/lib/gdal/color_table_types/hls.rb +21 -0
- data/lib/gdal/color_table_types/rgb.rb +25 -0
- data/lib/gdal/data_type.rb +38 -0
- data/lib/gdal/dataset.rb +437 -0
- data/lib/gdal/dataset_extensions.rb +496 -0
- data/lib/gdal/driver.rb +244 -0
- data/lib/gdal/driver_extensions.rb +56 -0
- data/lib/gdal/environment_methods.rb +43 -0
- data/lib/{ffi-gdal → gdal}/exceptions.rb +4 -1
- data/lib/gdal/geo_transform.rb +188 -0
- data/lib/gdal/geo_transform_extensions.rb +90 -0
- data/lib/gdal/logger.rb +7 -0
- data/lib/{ffi-gdal → gdal}/major_object.rb +15 -14
- data/lib/gdal/options.rb +49 -0
- data/lib/gdal/raster_attribute_table.rb +185 -0
- data/lib/gdal/raster_attribute_table_extensions.rb +40 -0
- data/lib/{ffi-gdal → gdal}/raster_band.rb +227 -99
- data/lib/gdal/raster_band_extensions.rb +198 -0
- data/lib/{ffi-gdal → gdal}/version_info.rb +8 -0
- data/lib/gdal/warp_operation.rb +96 -0
- data/lib/ogr/coordinate_transformation.rb +108 -0
- data/lib/ogr/data_source.rb +172 -0
- data/lib/ogr/data_source_extensions.rb +32 -0
- data/lib/ogr/driver.rb +119 -0
- data/lib/ogr/envelope.rb +80 -0
- data/lib/ogr/envelope_extensions.rb +92 -0
- data/lib/ogr/exceptions.rb +35 -0
- data/lib/ogr/feature.rb +212 -0
- data/lib/ogr/feature_definition.rb +120 -0
- data/lib/ogr/feature_definition_extensions.rb +36 -0
- data/lib/ogr/feature_extensions.rb +31 -0
- data/lib/ogr/field.rb +91 -0
- data/lib/ogr/field_extensions.rb +23 -0
- data/lib/ogr/geocoding_session.rb +84 -0
- data/lib/ogr/geometry.rb +617 -0
- data/lib/ogr/geometry_extensions.rb +60 -0
- data/lib/ogr/geometry_types/collection.rb +45 -0
- data/lib/ogr/geometry_types/curve.rb +120 -0
- data/lib/ogr/geometry_types/surface.rb +20 -0
- data/lib/ogr/layer.rb +226 -0
- data/lib/ogr/layer_extensions.rb +55 -0
- data/lib/ogr/line_string.rb +7 -0
- data/lib/ogr/linear_ring.rb +6 -0
- data/lib/ogr/multi_line_string.rb +9 -0
- data/lib/ogr/multi_point.rb +7 -0
- data/lib/ogr/multi_polygon.rb +14 -0
- data/lib/ogr/point.rb +89 -0
- data/lib/ogr/polygon.rb +9 -0
- data/lib/ogr/spatial_reference.rb +723 -0
- data/lib/ogr/spatial_reference_extensions.rb +32 -0
- data/lib/ogr/style_table.rb +17 -0
- data/lib/ogr/style_table_extensions.rb +16 -0
- data/spec/{ffi-gdal/integration → integration}/color_table_info_spec.rb +1 -1
- data/spec/{ffi-gdal/integration → integration}/dataset_info_spec.rb +0 -0
- data/spec/{ffi-gdal/integration → integration}/driver_info_spec.rb +1 -1
- data/spec/{ffi-gdal/integration → integration}/geo_transform_info_spec.rb +0 -0
- data/spec/{ffi-gdal/integration → integration}/raster_attribute_table_info_spec.rb +1 -1
- data/spec/{ffi-gdal/integration → integration}/raster_band_info_spec.rb +5 -5
- data/spec/spec_helper.rb +4 -1
- data/spec/support/shapefiles/states_21basic/states.prj +1 -0
- data/spec/support/shapefiles/states_21basic/states.sbn +0 -0
- data/spec/support/shapefiles/states_21basic/states.sbx +0 -0
- data/spec/support/shapefiles/states_21basic/states.shp +0 -0
- data/spec/support/worldfiles/SR_50M/SR_50M.VERSION.txt +1 -0
- data/spec/support/worldfiles/SR_50M/SR_50M.prj +1 -0
- data/spec/support/worldfiles/SR_50M/SR_50M.tfw +6 -0
- data/spec/{ext/cpl_error_symbols_spec.rb → unit/ext/error_symbols_spec.rb} +1 -1
- data/spec/unit/gdal/color_table_spec.rb +146 -0
- data/spec/unit/ogr/layer_spec.rb +97 -0
- data/spec/unit/ogr/linear_ring_spec.rb +111 -0
- data/spec/unit/ogr/point_spec.rb +321 -0
- data/spec/{ffi-gdal/unit → unit}/version_info_spec.rb +1 -1
- data/testing_gdal.rb +168 -0
- data/testing_gdalwarp.rb +91 -0
- data/testing_layer_to_layer.rb +35 -0
- data/testing_ndvi.rb +76 -0
- data/testing_nir.rb +77 -0
- data/testing_ogr.rb +63 -0
- metadata +167 -59
- data/lib/ext/cpl_error_symbols.rb +0 -37
- data/lib/ffi-gdal/color_table.rb +0 -59
- data/lib/ffi-gdal/dataset.rb +0 -359
- data/lib/ffi-gdal/driver.rb +0 -151
- data/lib/ffi-gdal/geo_transform.rb +0 -137
- data/lib/ffi-gdal/raster_attribute_table.rb +0 -78
- data/lib/ffi/gdal/ogr_api.rb +0 -21
- data/lib/ffi/gdal/ogr_core.rb +0 -195
- data/lib/ffi/gdal/ogr_srs_api.rb +0 -44
- data/meow.rb +0 -144
- 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
|
data/lib/ogr/envelope.rb
ADDED
@@ -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
|
data/lib/ogr/feature.rb
ADDED
@@ -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
|