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,120 @@
|
|
1
|
+
require_relative '../ffi/ogr'
|
2
|
+
require_relative 'feature_definition_extensions'
|
3
|
+
require_relative 'field'
|
4
|
+
|
5
|
+
module OGR
|
6
|
+
class FeatureDefinition
|
7
|
+
include FeatureDefinitionExtensions
|
8
|
+
|
9
|
+
# @param name [String]
|
10
|
+
def self.create(name)
|
11
|
+
feature_defn_pointer = FFI::GDAL.OGR_FD_Create(name)
|
12
|
+
return nil if feature_defn_pointer.null?
|
13
|
+
|
14
|
+
new(feature_defn_pointer)
|
15
|
+
end
|
16
|
+
|
17
|
+
# @param feature_definition [String]
|
18
|
+
def initialize(feature_definition)
|
19
|
+
@feature_definition_pointer = GDAL._pointer(OGR::FeatureDefinition,
|
20
|
+
feature_definition)
|
21
|
+
|
22
|
+
close_me = -> { FFI::GDAL.OGR_FD_Destroy(@feature_definition_pointer) }
|
23
|
+
ObjectSpace.define_finalizer self, close_me
|
24
|
+
end
|
25
|
+
|
26
|
+
def c_pointer
|
27
|
+
@feature_definition_pointer
|
28
|
+
end
|
29
|
+
|
30
|
+
# @return [String]
|
31
|
+
def name
|
32
|
+
FFI::GDAL.OGR_FD_GetName(@feature_definition_pointer)
|
33
|
+
end
|
34
|
+
|
35
|
+
# @return [Fixnum]
|
36
|
+
def field_count
|
37
|
+
FFI::GDAL.OGR_FD_GetFieldCount(@feature_definition_pointer)
|
38
|
+
end
|
39
|
+
|
40
|
+
# @param index [Fixnum]
|
41
|
+
# @return [OGR::Field]
|
42
|
+
def field(index)
|
43
|
+
field_ptr = FFI::GDAL.OGR_FD_GetFieldDefn(@feature_definition_pointer, index)
|
44
|
+
return nil if field_ptr.null?
|
45
|
+
|
46
|
+
OGR::Field.new(field_ptr)
|
47
|
+
end
|
48
|
+
|
49
|
+
# @param name [String]
|
50
|
+
# @return [Fixnum] -1 if no match found
|
51
|
+
def field_index(name)
|
52
|
+
FFI::GDAL.OGR_FD_GetFieldIndex(@feature_definition_pointer, name)
|
53
|
+
end
|
54
|
+
|
55
|
+
# @return [FFI::GDAL::OGRwkbGeometryType]
|
56
|
+
def geometry_type
|
57
|
+
FFI::GDAL.OGR_FD_GetGeomType(@feature_definition_pointer)
|
58
|
+
end
|
59
|
+
|
60
|
+
# @param new_type [FFI::GDAL::OGRwkbGeometryType]
|
61
|
+
def geometry_type=(new_type)
|
62
|
+
FFI::GDAL.OGR_FD_SetGeomType(@feature_definition_pointer, new_type)
|
63
|
+
end
|
64
|
+
|
65
|
+
# @return [Boolean]
|
66
|
+
def geometry_ignored?
|
67
|
+
FFI::GDAL.OGR_FD_IsGeometryIgnored(@feature_definition_pointer)
|
68
|
+
end
|
69
|
+
|
70
|
+
# @param ignore [Boolean]
|
71
|
+
def ignore_geometry!(ignore)
|
72
|
+
FFI::GDAL.OGR_FD_SetGeometryIgnored(@feature_definition_pointer, ignore)
|
73
|
+
end
|
74
|
+
|
75
|
+
# @return [Boolean]
|
76
|
+
def style_ignored?
|
77
|
+
FFI::GDAL.OGR_FD_IsStyleIgnored(@feature_definition_pointer)
|
78
|
+
end
|
79
|
+
|
80
|
+
# @param ignore [Boolean]
|
81
|
+
def ignore_style!(ignore)
|
82
|
+
FFI::GDAL.OGR_FD_SetStyleIgnored(@feature_definition_pointer, ignore)
|
83
|
+
end
|
84
|
+
|
85
|
+
# @return [Fixnum]
|
86
|
+
def geometry_field_count
|
87
|
+
FFI::GDAL.OGR_FD_GetGeomFieldCount(@feature_definition_pointer)
|
88
|
+
end
|
89
|
+
|
90
|
+
# @param index [Fixnum]
|
91
|
+
# @return [OGR::Field]
|
92
|
+
def geometry_field_definition(index)
|
93
|
+
field_ptr = FFI::GDAL.OGR_FD_GetGeomFieldDefn(@feature_definition_pointer, index)
|
94
|
+
return nil if field_ptr.null?
|
95
|
+
|
96
|
+
OGR::Field.new(field_ptr)
|
97
|
+
end
|
98
|
+
|
99
|
+
# @param name [String]
|
100
|
+
# @return [Fixnum]
|
101
|
+
def geometry_field_index(name)
|
102
|
+
FFI::GDAL.OGR_FD_GetGeomFieldIndex(@feature_definition_pointer, name)
|
103
|
+
end
|
104
|
+
|
105
|
+
# @param name [String]
|
106
|
+
# @return [OGR::Field]
|
107
|
+
def geometry_field_by_name(name)
|
108
|
+
geometry_field_definition(geometry_field_index(name))
|
109
|
+
end
|
110
|
+
|
111
|
+
# @param other_feature_defintion [OGR::Feature, FFI::Pointer]
|
112
|
+
# @return [Boolean]
|
113
|
+
def same?(other_feature_defintion)
|
114
|
+
fd_ptr = GDAL._pointer(OGR::FeatureDefinition, other_feature_defintion)
|
115
|
+
|
116
|
+
FFI::GDAL.OGR_FD_IsSame(@feature_definition_pointer, fd_ptr)
|
117
|
+
end
|
118
|
+
alias_method :==, :same?
|
119
|
+
end
|
120
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
require 'json'
|
2
|
+
|
3
|
+
module OGR
|
4
|
+
module FeatureDefinitionExtensions
|
5
|
+
|
6
|
+
# @return [Array<OGR::Field>]
|
7
|
+
def fields
|
8
|
+
0.upto(field_count - 1).map do |i|
|
9
|
+
field(i)
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
# @param name [String]
|
14
|
+
# @return [OGR::Field]
|
15
|
+
def field_by_name(name)
|
16
|
+
field(field_index(name))
|
17
|
+
end
|
18
|
+
|
19
|
+
# @return [Hash]
|
20
|
+
def as_json
|
21
|
+
{
|
22
|
+
field_count: field_count,
|
23
|
+
fields: fields.map(&:as_json),
|
24
|
+
geometry_field_count: geometry_field_count,
|
25
|
+
geometry_type: geometry_type,
|
26
|
+
name: name,
|
27
|
+
is_style_ignored: style_ignored?
|
28
|
+
}
|
29
|
+
end
|
30
|
+
|
31
|
+
# @return [String]
|
32
|
+
def to_json
|
33
|
+
as_json.to_json
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
require 'json'
|
2
|
+
|
3
|
+
module OGR
|
4
|
+
module FeatureExtensions
|
5
|
+
|
6
|
+
# @return [Array<OGR::Field>]
|
7
|
+
def fields
|
8
|
+
0.upto(field_count - 1).map do |i|
|
9
|
+
field(i)
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
# @return [Hash]
|
14
|
+
def as_json
|
15
|
+
{
|
16
|
+
definition: definition,
|
17
|
+
fid: fid,
|
18
|
+
field_count: field_count,
|
19
|
+
fields: fields.map(&:as_json),
|
20
|
+
geometry: geometry.as_json,
|
21
|
+
geometry_field_count: geometry_field_count,
|
22
|
+
style_string: style_string
|
23
|
+
}
|
24
|
+
end
|
25
|
+
|
26
|
+
# @return [String]
|
27
|
+
def to_json
|
28
|
+
as_json.to_json
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
data/lib/ogr/field.rb
ADDED
@@ -0,0 +1,91 @@
|
|
1
|
+
require_relative '../ffi/ogr'
|
2
|
+
require_relative 'field_extensions'
|
3
|
+
|
4
|
+
module OGR
|
5
|
+
class Field
|
6
|
+
include FieldExtensions
|
7
|
+
|
8
|
+
# @param name [String]
|
9
|
+
# @param type [FFI::GDAL::OGRFieldType]
|
10
|
+
# @return [OGR::Field]
|
11
|
+
def self.create(name, type)
|
12
|
+
field_ptr = FFI::GDAL.OGR_Fld_Create(name, type)
|
13
|
+
return nil if field_ptr.null?
|
14
|
+
|
15
|
+
new(field_ptr)
|
16
|
+
end
|
17
|
+
|
18
|
+
# @param field [OGR::Field, FFI::Pointer]
|
19
|
+
def initialize(field)
|
20
|
+
@field_pointer = GDAL._pointer(OGR::Field, field)
|
21
|
+
end
|
22
|
+
|
23
|
+
def c_pointer
|
24
|
+
@field_pointer
|
25
|
+
end
|
26
|
+
|
27
|
+
def destroy!
|
28
|
+
FFI::GDAL.OGR_Fld_Destroy(@field_pointer)
|
29
|
+
end
|
30
|
+
|
31
|
+
# @return [String]
|
32
|
+
def name
|
33
|
+
FFI::GDAL.OGR_Fld_GetNameRef(@field_pointer)
|
34
|
+
end
|
35
|
+
|
36
|
+
# @param new_value [String]
|
37
|
+
def name=(new_value)
|
38
|
+
FFI::GDAL.OGR_Fld_SetName(@field_pointer, new_value)
|
39
|
+
end
|
40
|
+
|
41
|
+
# @return [FFI::GDAL::OGRJustification]
|
42
|
+
def justification
|
43
|
+
FFI::GDAL.OGR_Fld_GetJustify(@field_pointer)
|
44
|
+
end
|
45
|
+
|
46
|
+
# @param new_value [FFI::GDAL::OGRJustification]
|
47
|
+
def justification=(new_value)
|
48
|
+
FFI::GDAL.OGR_Fld_SetJustify(@field_pointer, new_value)
|
49
|
+
end
|
50
|
+
|
51
|
+
# @return [Fixnum]
|
52
|
+
def precision
|
53
|
+
FFI::GDAL.OGR_Fld_GetPrecision(@field_pointer)
|
54
|
+
end
|
55
|
+
|
56
|
+
# @param new_value [Fixnum]
|
57
|
+
def precision=(new_value)
|
58
|
+
FFI::GDAL.OGR_Fld_SetPrecision(@field_pointer, new_value)
|
59
|
+
end
|
60
|
+
|
61
|
+
# @return [FFI::GDAL::OGRFieldType]
|
62
|
+
def type
|
63
|
+
FFI::GDAL.OGR_Fld_GetType(@field_pointer)
|
64
|
+
end
|
65
|
+
|
66
|
+
# @param new_value [FFI::GDAL::OGRFieldType]
|
67
|
+
def type=(new_value)
|
68
|
+
FFI::GDAL.OGR_Fld_SetType(@field_pointer, new_value)
|
69
|
+
end
|
70
|
+
|
71
|
+
# @return [Fixnum]
|
72
|
+
def width
|
73
|
+
FFI::GDAL.OGR_Fld_GetWidth(@field_pointer)
|
74
|
+
end
|
75
|
+
|
76
|
+
# @param new_value [Fixnum]
|
77
|
+
def width=(new_value)
|
78
|
+
FFI::GDAL.OGR_Fld_SetWidth(@field_pointer, new_value)
|
79
|
+
end
|
80
|
+
|
81
|
+
# @return [Boolean]
|
82
|
+
def ignored?
|
83
|
+
FFI::GDAL.OGR_Fld_IsIgnored(@field_pointer)
|
84
|
+
end
|
85
|
+
|
86
|
+
# @param new_value [Boolean]
|
87
|
+
def ignore=(new_value)
|
88
|
+
FFI::GDAL.OGR_Fld_SetIgnored(@field_pointer, new_value)
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
require 'json'
|
2
|
+
|
3
|
+
module OGR
|
4
|
+
module FieldExtensions
|
5
|
+
|
6
|
+
# @return [Hash]
|
7
|
+
def as_json
|
8
|
+
{
|
9
|
+
is_ignored: ignored?,
|
10
|
+
justification: justification,
|
11
|
+
name: name,
|
12
|
+
precision: precision,
|
13
|
+
type: type,
|
14
|
+
width: width
|
15
|
+
}
|
16
|
+
end
|
17
|
+
|
18
|
+
# @return [String]
|
19
|
+
def to_json
|
20
|
+
as_json.to_json
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,84 @@
|
|
1
|
+
require_relative 'layer'
|
2
|
+
|
3
|
+
module OGR
|
4
|
+
|
5
|
+
# Geocode things! http://www.gdal.org/ogr__geocoding_8h.html
|
6
|
+
class GeocodingSession
|
7
|
+
# @param options [Hash]
|
8
|
+
# @option options cache_file [String] Name of the file to write the cache
|
9
|
+
# to.
|
10
|
+
# @option options read_cache [Boolean] Defaults to true.
|
11
|
+
# @option options write_cache [Boolean] Defaults to true.
|
12
|
+
# @option options service [String] "MAPQUEST_NOMINATIM", "YAHOO",
|
13
|
+
# "GEONAMES", "BING", or other value.
|
14
|
+
# @option options email [String] Required for the GEONAMES service.
|
15
|
+
# @option options key [String] Required for the BING service.
|
16
|
+
# @option options application [String] Sets the User-Agent request header.
|
17
|
+
# Defaults to the GDAL version string.
|
18
|
+
# @option options language [String] Sets the Accept-Language request
|
19
|
+
# header.
|
20
|
+
# @option options delay [Float] Minimum delay, in seconds, between
|
21
|
+
# consecutive requests. Defaults to 1.0.
|
22
|
+
# @option options query_template [String] URL template for GET requests.
|
23
|
+
# Must contain one and only one occurrence of %s. If not specified, the
|
24
|
+
# URL template is hard-coded.
|
25
|
+
# @option options reverse_query_template [String] Template to use for
|
26
|
+
# reverse geocoding.
|
27
|
+
def initialize(**options)
|
28
|
+
converted_options = options.each_with_object({}) do |(k, v), obj|
|
29
|
+
key = "OGR_GEOCODE_#{k.to_s.upcase}"
|
30
|
+
obj[key] = v
|
31
|
+
end
|
32
|
+
|
33
|
+
options_ptr = GDAL::Options.pointer(converted_options)
|
34
|
+
|
35
|
+
@geocoding_session_pointer = FFI::GDAL.OGRGeocodeCreateSession(options_ptr)
|
36
|
+
end
|
37
|
+
|
38
|
+
def c_pointer
|
39
|
+
@geocoding_session_pointer
|
40
|
+
end
|
41
|
+
|
42
|
+
def destroy!
|
43
|
+
FFI::GDAL.OGRGeocodeDestroySession(@geocoding_session_pointer)
|
44
|
+
end
|
45
|
+
|
46
|
+
# @param query [String]
|
47
|
+
# @param options [Hash]
|
48
|
+
# @option options addressdetails [Boolean] +true+ to include a breakdown of
|
49
|
+
# the adddress into elements. Only works with some geocoding services.
|
50
|
+
# @option options countrycodes [Array<String, Symbol>] Limit the search to a
|
51
|
+
# specific country or countries. Only works with some geocoding services.
|
52
|
+
# @option options limit [Fixnum] Limit the number of records returned. Only
|
53
|
+
# works with some geocoding services.
|
54
|
+
# @option options raw_feature ["YES"] Adds a raw feature to the returned
|
55
|
+
# feature that includes that raw XML response body.
|
56
|
+
# @option extra_query_parameters [String] Adds params to the GET request.
|
57
|
+
# @return [OGR::Layer, nil]
|
58
|
+
def geocode(query, **options)
|
59
|
+
options_ptr = GDAL::Options.pointer(options)
|
60
|
+
layer_ptr = FFI::GDAL.OGRGeocode(@geocoding_session_pointer, query, nil,
|
61
|
+
options_ptr)
|
62
|
+
return nil if layer_ptr.null?
|
63
|
+
|
64
|
+
OGR::Layer.new(layer_ptr)
|
65
|
+
end
|
66
|
+
|
67
|
+
# @param lon [Float]
|
68
|
+
# @param lat [Float]
|
69
|
+
# @param options [Hash]
|
70
|
+
# @option options zoom [Float] Only used by the Nominatim service.
|
71
|
+
# @option options raw_feature ["YES"] Adds a raw feature to the returned
|
72
|
+
# feature that includes that raw XML response body.
|
73
|
+
# @option extra_query_parameters [String] Adds params to the GET request.
|
74
|
+
# @return [OGR::Layer]
|
75
|
+
def reverse_geocode(lon, lat, **options)
|
76
|
+
options_ptr = GDAL::Options.pointer(options)
|
77
|
+
layer_ptr = FFI::GDAL.OGRGeocodeReverse(@geocoding_session_pointer, lon,
|
78
|
+
lat, options_ptr)
|
79
|
+
return nil if layer_ptr.null?
|
80
|
+
|
81
|
+
OGR::Layer.new(layer_ptr)
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
data/lib/ogr/geometry.rb
ADDED
@@ -0,0 +1,617 @@
|
|
1
|
+
require_relative 'envelope'
|
2
|
+
require_relative 'geometry_extensions'
|
3
|
+
|
4
|
+
module OGR
|
5
|
+
class Geometry
|
6
|
+
include GDAL::Logger
|
7
|
+
include GeometryExtensions
|
8
|
+
|
9
|
+
# @param type [FFI::GDAL::OGRwkbGeometryType]
|
10
|
+
# @return [OGR::Geometry]
|
11
|
+
def self.create(type)
|
12
|
+
geometry_pointer = FFI::GDAL.OGR_G_CreateGeometry(type)
|
13
|
+
return nil if geometry_pointer.null?
|
14
|
+
geometry_pointer.autorelease = false
|
15
|
+
|
16
|
+
_to_geometry_type(geometry_pointer)
|
17
|
+
end
|
18
|
+
|
19
|
+
def self._to_geometry_type(geometry)
|
20
|
+
geometry = if geometry.kind_of?(OGR::Geometry)
|
21
|
+
geometry
|
22
|
+
else
|
23
|
+
new(geometry)
|
24
|
+
end
|
25
|
+
case geometry.name
|
26
|
+
when 'POINT' then OGR::Point.new(geometry.c_pointer)
|
27
|
+
when 'LINESTRING' then OGR::LineString.new(geometry.c_pointer)
|
28
|
+
when 'LINEARRING' then OGR::LinearRing.new(geometry.c_pointer)
|
29
|
+
when 'POLYGON' then OGR::Polygon.new(geometry.c_pointer)
|
30
|
+
when 'MULTIPOINT' then OGR::MultiPoint.new(geometry.c_pointer)
|
31
|
+
when 'MULTILINESTRING' then OGR::MultiLineString.new(geometry.c_pointer)
|
32
|
+
when 'MULTIPOLYGON' then OGR::MultiPolygon.new(geometry.c_pointer)
|
33
|
+
else
|
34
|
+
geometry
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
# @param wkt_data [String]
|
39
|
+
# @param spatial_reference [FFI::Pointer] Optional spatial reference
|
40
|
+
# to assign to the new geometry.
|
41
|
+
# @return [OGR::Geometry]
|
42
|
+
def self.create_from_wkt(wkt_data, spatial_reference=nil)
|
43
|
+
wkt_data_pointer = FFI::MemoryPointer.from_string(wkt_data)
|
44
|
+
wkt_pointer_pointer = FFI::MemoryPointer.new(:pointer)
|
45
|
+
wkt_pointer_pointer.write_pointer(wkt_data_pointer)
|
46
|
+
|
47
|
+
spatial_ref_pointer = if spatial_reference
|
48
|
+
GDAL._pointer(OGR::SpatialReference, spatial_reference)
|
49
|
+
else
|
50
|
+
FFI::MemoryPointer.new(:pointer)
|
51
|
+
end
|
52
|
+
|
53
|
+
geometry_ptr = FFI::MemoryPointer.new(:pointer)
|
54
|
+
geometry_ptr_ptr = FFI::MemoryPointer.new(:pointer)
|
55
|
+
geometry_ptr_ptr.write_pointer(geometry_ptr)
|
56
|
+
|
57
|
+
FFI::GDAL.OGR_G_CreateFromWkt(wkt_pointer_pointer,
|
58
|
+
spatial_ref_pointer, geometry_ptr_ptr)
|
59
|
+
|
60
|
+
return nil if geometry_ptr_ptr.null? ||
|
61
|
+
geometry_ptr_ptr.read_pointer.null?
|
62
|
+
geometry_ptr_ptr.read_pointer.nil?
|
63
|
+
|
64
|
+
# Not assigning here makes tests crash when using a #let.
|
65
|
+
geometry = _to_geometry_type(geometry_ptr_ptr.read_pointer)
|
66
|
+
end
|
67
|
+
|
68
|
+
# @param gml_data [String]
|
69
|
+
# @return [OGR::Geometry]
|
70
|
+
def self.create_from_gml(gml_data)
|
71
|
+
geometry_pointer = FFI::GDAL.OGR_G_CreateFromGML(gml_data)
|
72
|
+
|
73
|
+
new(geometry_pointer)
|
74
|
+
end
|
75
|
+
|
76
|
+
# @param json_data [String]
|
77
|
+
# @return [OGR::Geometry]
|
78
|
+
def self.create_from_json(json_data)
|
79
|
+
geometry_pointer = FFI::GDAL.OGR_G_CreateGeometryFromJson(json_data)
|
80
|
+
|
81
|
+
new(geometry_pointer)
|
82
|
+
end
|
83
|
+
|
84
|
+
# @return [String]
|
85
|
+
def self.type_to_name(type)
|
86
|
+
FFI::GDAL.OGRGeometryTypeToName(type)
|
87
|
+
end
|
88
|
+
|
89
|
+
# @param geometry [OGR::Geometry, FFI::Pointer]
|
90
|
+
def initialize(geometry)
|
91
|
+
@geometry_pointer = GDAL._pointer(OGR::Geometry, geometry)
|
92
|
+
@geometry_pointer.autorelease = false
|
93
|
+
|
94
|
+
close_me = -> {
|
95
|
+
if @geometry_pointer && !@geometry_pointer.null?
|
96
|
+
FFI::GDAL.OGR_G_DestroyGeometry(@geometry_pointer)
|
97
|
+
end
|
98
|
+
}
|
99
|
+
ObjectSpace.define_finalizer self, close_me
|
100
|
+
end
|
101
|
+
|
102
|
+
def c_pointer
|
103
|
+
@geometry_pointer
|
104
|
+
end
|
105
|
+
|
106
|
+
# If this geometry is a container, this adds +geometry+ to the container.
|
107
|
+
# If this is a Polygon, +geometry+ must be a LinearRing. If the Polygon is
|
108
|
+
# empty, the first added +geometry+ will be the exterior ring. Subsequent
|
109
|
+
# geometries added will be interior rings.
|
110
|
+
#
|
111
|
+
# @param sub_geometry [OGR::Geometry, FFI::Pointer]
|
112
|
+
# @return +true+ if successful, otherwise raises an OGR exception.
|
113
|
+
def add_geometry(sub_geometry)
|
114
|
+
ogr_err = FFI::GDAL.OGR_G_AddGeometry(@geometry_pointer, pointer_from(sub_geometry))
|
115
|
+
|
116
|
+
ogr_err.to_ruby
|
117
|
+
end
|
118
|
+
|
119
|
+
# @param sub_geometry [OGR::Geometry, FFI::Pointer]
|
120
|
+
# @return +true+ if successful, otherwise raises an OGR exception.
|
121
|
+
def add_directly(sub_geometry)
|
122
|
+
ogr_err = FFI::GDAL.OGR_G_AddGeometryDirectly(@geometry_pointer, pointer_from(sub_geometry))
|
123
|
+
|
124
|
+
ogr_err.to_ruby
|
125
|
+
end
|
126
|
+
|
127
|
+
# @param geometry_index [Fixnum]
|
128
|
+
# @param delete [Boolean]
|
129
|
+
# @return +true+ if successful, otherwise raises an OGR exception.
|
130
|
+
def remove!(geometry_index, delete=true)
|
131
|
+
ogr_err = FFI::GDAL.OGR_G_RemoveGeometry(@geometry_pointer, geometry_index, delete)
|
132
|
+
|
133
|
+
ogr_err.to_ruby
|
134
|
+
end
|
135
|
+
|
136
|
+
# Clears all information from the geometry.
|
137
|
+
def empty!
|
138
|
+
FFI::GDAL.OGR_G_Empty(@geometry_pointer)
|
139
|
+
end
|
140
|
+
|
141
|
+
# @return [Fixnum] 0 for points, 1 for lines, 2 for surfaces.
|
142
|
+
def dimension
|
143
|
+
FFI::GDAL.OGR_G_GetDimension(@geometry_pointer)
|
144
|
+
end
|
145
|
+
|
146
|
+
# The dimension of coordinates in this geometry (i.e. 2d vs 3d).
|
147
|
+
#
|
148
|
+
# @return [Fixnum] 2 or 3, but 0 in the case of an empty point.
|
149
|
+
def coordinate_dimension
|
150
|
+
FFI::GDAL.OGR_G_GetCoordinateDimension(@geometry_pointer)
|
151
|
+
end
|
152
|
+
|
153
|
+
# @param new_coordinate_dimension [Fixnum]
|
154
|
+
def coordinate_dimension=(new_coordinate_dimension)
|
155
|
+
unless [2, 3].include?(new_coordinate_dimension)
|
156
|
+
raise "Can't set coordinate to #{new_coordinate_dimension}. Must be 2 or 3."
|
157
|
+
end
|
158
|
+
|
159
|
+
FFI::GDAL.OGR_G_SetCoordinateDimension(@geometry_pointer, new_coordinate_dimension)
|
160
|
+
end
|
161
|
+
|
162
|
+
# @return [OGR::Envelope]
|
163
|
+
def envelope
|
164
|
+
return @envelope if @envelope
|
165
|
+
|
166
|
+
case coordinate_dimension
|
167
|
+
when 2
|
168
|
+
envelope = FFI::GDAL::OGREnvelope.new
|
169
|
+
FFI::GDAL.OGR_G_GetEnvelope(@geometry_pointer, envelope)
|
170
|
+
when 3
|
171
|
+
envelope = FFI::GDAL::OGREnvelope3D.new
|
172
|
+
FFI::GDAL.OGR_G_GetEnvelope3D(@geometry_pointer, envelope)
|
173
|
+
when 0
|
174
|
+
return nil
|
175
|
+
else
|
176
|
+
raise 'Unknown envelope dimension.'
|
177
|
+
end
|
178
|
+
|
179
|
+
return nil if envelope.null?
|
180
|
+
|
181
|
+
@envelope = OGR::Envelope.new(envelope)
|
182
|
+
end
|
183
|
+
|
184
|
+
# @return [FFI::GDAL::OGRwkbGeometryType]
|
185
|
+
def type
|
186
|
+
FFI::GDAL.OGR_G_GetGeometryType(@geometry_pointer)
|
187
|
+
end
|
188
|
+
|
189
|
+
# @return [String]
|
190
|
+
def type_to_name
|
191
|
+
FFI::GDAL.OGRGeometryTypeToName(type)
|
192
|
+
end
|
193
|
+
|
194
|
+
# @return [String]
|
195
|
+
def name
|
196
|
+
FFI::GDAL.OGR_G_GetGeometryName(@geometry_pointer)
|
197
|
+
end
|
198
|
+
|
199
|
+
# @return [Fixnum]
|
200
|
+
def count
|
201
|
+
FFI::GDAL.OGR_G_GetGeometryCount(@geometry_pointer)
|
202
|
+
end
|
203
|
+
|
204
|
+
# @return [Fixnum]
|
205
|
+
def point_count
|
206
|
+
return 0 if empty?
|
207
|
+
|
208
|
+
FFI::GDAL.OGR_G_GetPointCount(@geometry_pointer)
|
209
|
+
end
|
210
|
+
|
211
|
+
# @return [Fixnum]
|
212
|
+
# @todo This regularly crashes, so disabling it.
|
213
|
+
def centroid
|
214
|
+
raise NotImplementedError, '#centroid not yet implemented.'
|
215
|
+
|
216
|
+
point = OGR::Geometry.create(:wkbPoint)
|
217
|
+
FFI::GDAL.OGR_G_Centroid(@geometry_pointer, point.c_pointer)
|
218
|
+
return nil if point.c_pointer.null?
|
219
|
+
|
220
|
+
point
|
221
|
+
end
|
222
|
+
|
223
|
+
# # Dump as WKT to the give +file+.
|
224
|
+
#
|
225
|
+
# @param file [String] The text file to write to.
|
226
|
+
# @param prefix [String] The prefix to put on each line of output.
|
227
|
+
# @return [String]
|
228
|
+
def dump_readable(file, prefix=nil)
|
229
|
+
FFI::GDAL.OGR_G_DumpReadable(@geometry_pointer, file, prefix)
|
230
|
+
end
|
231
|
+
|
232
|
+
# Converts this geometry to a 2D geometry.
|
233
|
+
def flatten_to_2d!
|
234
|
+
FFI::GDAL.OGR_G_FlattenTo2D(@geometry_pointer)
|
235
|
+
end
|
236
|
+
|
237
|
+
# @param geometry [OGR::Geometry, FFI::Pointer]
|
238
|
+
# @return [Boolean]
|
239
|
+
def intersects?(geometry)
|
240
|
+
FFI::GDAL.OGR_G_Intersects(@geometry_pointer, pointer_from(geometry))
|
241
|
+
end
|
242
|
+
|
243
|
+
# @param geometry [OGR::Geometry, FFI::Pointer]
|
244
|
+
# @return [Boolean]
|
245
|
+
def equals?(geometry)
|
246
|
+
FFI::GDAL.OGR_G_Equals(@geometry_pointer, pointer_from(geometry))
|
247
|
+
end
|
248
|
+
alias_method :==, :equals?
|
249
|
+
|
250
|
+
# @param geometry [OGR::Geometry, FFI::Pointer]
|
251
|
+
# @return [Boolean]
|
252
|
+
def disjoint?(geometry)
|
253
|
+
FFI::GDAL.OGR_G_Disjoint(@geometry_pointer, pointer_from(geometry))
|
254
|
+
end
|
255
|
+
|
256
|
+
# @param geometry [OGR::Geometry, FFI::Pointer]
|
257
|
+
# @return [Boolean]
|
258
|
+
def touches?(geometry)
|
259
|
+
FFI::GDAL.OGR_G_Touches(@geometry_pointer, geometry.c_pointer)
|
260
|
+
end
|
261
|
+
|
262
|
+
# @param geometry [OGR::Geometry, FFI::Pointer]
|
263
|
+
# @return [Boolean]
|
264
|
+
def crosses?(geometry)
|
265
|
+
FFI::GDAL.OGR_G_Crosses(@geometry_pointer, pointer_from(geometry))
|
266
|
+
end
|
267
|
+
|
268
|
+
# @param geometry [OGR::Geometry, FFI::Pointer]
|
269
|
+
# @return [Boolean]
|
270
|
+
def within?(geometry)
|
271
|
+
FFI::GDAL.OGR_G_Within(@geometry_pointer, pointer_from(geometry))
|
272
|
+
end
|
273
|
+
|
274
|
+
# @param geometry [OGR::Geometry, FFI::Pointer]
|
275
|
+
# @return [Boolean]
|
276
|
+
def contains?(geometry)
|
277
|
+
FFI::GDAL.OGR_G_Contains(@geometry_pointer, pointer_from(geometry))
|
278
|
+
end
|
279
|
+
|
280
|
+
# @param geometry [OGR::Geometry, FFI::Pointer]
|
281
|
+
# @return [Boolean]
|
282
|
+
def overlaps?(geometry)
|
283
|
+
FFI::GDAL.OGR_G_Overlaps(@geometry_pointer, pointer_from(geometry))
|
284
|
+
end
|
285
|
+
|
286
|
+
# @return [Boolean]
|
287
|
+
def empty?
|
288
|
+
FFI::GDAL.OGR_G_IsEmpty(@geometry_pointer)
|
289
|
+
end
|
290
|
+
|
291
|
+
# @return [Boolean]
|
292
|
+
def valid?
|
293
|
+
FFI::GDAL.OGR_G_IsValid(@geometry_pointer)
|
294
|
+
end
|
295
|
+
|
296
|
+
# Returns TRUE if the geometry has no anomalous geometric points, such as
|
297
|
+
# self intersection or self tangency. The description of each instantiable
|
298
|
+
# geometric class will include the specific conditions that cause an
|
299
|
+
# instance of that class to be classified as not simple.
|
300
|
+
#
|
301
|
+
# @return [Boolean]
|
302
|
+
def simple?
|
303
|
+
FFI::GDAL.OGR_G_IsSimple(@geometry_pointer)
|
304
|
+
end
|
305
|
+
|
306
|
+
# TRUE if the geometry has no points, otherwise FALSE.
|
307
|
+
#
|
308
|
+
# @return [Boolean]
|
309
|
+
def ring?
|
310
|
+
FFI::GDAL.OGR_G_IsRing(@geometry_pointer)
|
311
|
+
end
|
312
|
+
|
313
|
+
# @param other_geometry [OGR::Geometry]
|
314
|
+
# @return [OGR::Geometry]
|
315
|
+
# @todo This regularly crashes, so disabling it.
|
316
|
+
def intersection(other_geometry)
|
317
|
+
raise NotImplementedError, '#intersection not yet implemented.'
|
318
|
+
|
319
|
+
return nil unless intersects?(other_geometry)
|
320
|
+
|
321
|
+
build_geometry do |ptr|
|
322
|
+
FFI::GDAL.OGR_G_Intersection(ptr, other_geometry.c_pointer)
|
323
|
+
end
|
324
|
+
end
|
325
|
+
|
326
|
+
# @param other_geometry [OGR::Geometry]
|
327
|
+
# @return [OGR::Geometry]
|
328
|
+
def union(other_geometry)
|
329
|
+
build_geometry do |ptr|
|
330
|
+
FFI::GDAL.OGR_G_Union(ptr, other_geometry.c_pointer)
|
331
|
+
end
|
332
|
+
end
|
333
|
+
|
334
|
+
# If this or any contained geometries has polygon rings that aren't closed,
|
335
|
+
# this closes them by adding the starting point at the end.
|
336
|
+
def close_rings!
|
337
|
+
FFI::GDAL.OGR_G_CloseRings(@geometry_pointer)
|
338
|
+
end
|
339
|
+
|
340
|
+
# Creates a polygon from a set of sparse edges. The newly created geometry
|
341
|
+
# will contain a collection of reassembled Polygons.
|
342
|
+
#
|
343
|
+
# @return [OGR::Geometry] nil if the current geometry isn't a
|
344
|
+
# MultiLineString or if it's impossible to reassemble due to topological
|
345
|
+
# inconsistencies.
|
346
|
+
def polygonize
|
347
|
+
build_geometry { |ptr| FFI::GDAL.OGR_G_Polygonize(ptr) }
|
348
|
+
end
|
349
|
+
|
350
|
+
# @param geometry [OGR::Geometry]
|
351
|
+
# @return [OGR::Geometry]
|
352
|
+
def difference(geometry)
|
353
|
+
new_geometry_ptr = FFI::GDAL.OGR_G_Difference(@geometry_pointer, geometry.c_pointer)
|
354
|
+
return nil if new_geometry_ptr.null?
|
355
|
+
|
356
|
+
self.class._to_geometry_type(new_geometry_ptr)
|
357
|
+
end
|
358
|
+
alias_method :-, :difference
|
359
|
+
|
360
|
+
# @param geometry [OGR::Geometry]
|
361
|
+
# @return [OGR::Geometry]
|
362
|
+
def symmetric_difference(geometry)
|
363
|
+
new_geometry_ptr = FFI::GDAL.OGR_G_SymDifference(@geometry_pointer, geometry.c_pointer)
|
364
|
+
return nil if new_geometry_ptr.null?
|
365
|
+
|
366
|
+
self.class._to_geometry_type(new_geometry_ptr)
|
367
|
+
end
|
368
|
+
|
369
|
+
# The shortest distance between the two geometries.
|
370
|
+
#
|
371
|
+
# @param geometry [OGR::Geometry]
|
372
|
+
# @return [Float] -1 if an error occurs.
|
373
|
+
def distance_to(geometry)
|
374
|
+
FFI::GDAL.OGR_G_Distance(@geometry_pointer, geometry.c_pointer)
|
375
|
+
end
|
376
|
+
|
377
|
+
# @return [OGR::SpatialReference]
|
378
|
+
def spatial_reference
|
379
|
+
return @spatial_reference if @spatial_reference
|
380
|
+
|
381
|
+
spatial_ref_ptr = FFI::GDAL.OGR_G_GetSpatialReference(@geometry_pointer)
|
382
|
+
return nil if spatial_ref_ptr.null?
|
383
|
+
|
384
|
+
@spatial_reference = OGR::SpatialReference.new(spatial_ref_ptr)
|
385
|
+
end
|
386
|
+
|
387
|
+
# Assigns a spatial reference to this geometry. Any existing spatial
|
388
|
+
# reference is replace, but this does not reproject the geometry.
|
389
|
+
#
|
390
|
+
# @param new_spatial_ref [OGR::SpatialReference, FFI::Pointer]
|
391
|
+
def spatial_reference=(new_spatial_ref)
|
392
|
+
new_spatial_ref_ptr = GDAL._pointer(OGR::SpatialReference, new_spatial_ref)
|
393
|
+
|
394
|
+
FFI::GDAL.OGR_G_AssignSpatialReference(@geometry_pointer, new_spatial_ref_ptr)
|
395
|
+
end
|
396
|
+
|
397
|
+
# Transforms the coordinates of this geometry in its current spatial
|
398
|
+
# reference system to a new spatial reference system. Normally this means
|
399
|
+
# reprojecting the vectors, but it could also include datum shifts, and
|
400
|
+
# changes of units.
|
401
|
+
#
|
402
|
+
# Note that this doesn't require the geometry to have an existing spatial
|
403
|
+
# reference system.
|
404
|
+
#
|
405
|
+
# @param coordinate_transformation [OGR::CoordinateTransformation,
|
406
|
+
# FFI::Pointer]
|
407
|
+
# @return [Boolean]
|
408
|
+
def transform!(coordinate_transformation)
|
409
|
+
coord_trans_ptr = GDAL._pointer(OGR::CoordinateTransformation,
|
410
|
+
coordinate_transformation)
|
411
|
+
|
412
|
+
return if coord_trans_ptr.nil? or coord_trans_ptr.null?
|
413
|
+
|
414
|
+
ogr_err = FFI::GDAL.OGR_G_Transform(@geometry_pointer, coord_trans_ptr)
|
415
|
+
|
416
|
+
ogr_err.to_ruby
|
417
|
+
end
|
418
|
+
|
419
|
+
# Similar to +#transform+, but this only works if the geometry already has an
|
420
|
+
# assigned spatial reference system _and_ is transformable to the target
|
421
|
+
# coordinate system.
|
422
|
+
#
|
423
|
+
# @param new_spatial_ref [OGR::SpatialReference, FFI::Pointer]
|
424
|
+
# @return [Boolean]
|
425
|
+
def transform_to!(new_spatial_ref)
|
426
|
+
new_spatial_ref_ptr = GDAL._pointer(OGR::SpatialReference, new_spatial_ref)
|
427
|
+
return nil if new_spatial_ref_ptr.null?
|
428
|
+
|
429
|
+
ogr_err = FFI::GDAL.OGR_G_TransformTo(@geometry_pointer, new_spatial_ref_ptr)
|
430
|
+
|
431
|
+
ogr_err.to_ruby
|
432
|
+
end
|
433
|
+
|
434
|
+
# Computes and returns a new, simplified geometry.
|
435
|
+
#
|
436
|
+
# NOTE: this relies on GDAL having been built against GEOS. If it wasn't,
|
437
|
+
# this will fail.
|
438
|
+
#
|
439
|
+
# @param distance_tolerance [Float]
|
440
|
+
# @return [OGR::Geometry]
|
441
|
+
def simplify(distance_tolerance)
|
442
|
+
build_geometry do |ptr|
|
443
|
+
FFI::GDAL.OGR_G_Simplify(ptr, distance_tolerance)
|
444
|
+
end
|
445
|
+
end
|
446
|
+
|
447
|
+
# Like +#simplify+, but preserves the geometry's topology.
|
448
|
+
#
|
449
|
+
# @param distance_tolerance [Float]
|
450
|
+
# @return [OGR::Geometry]
|
451
|
+
def simplify_preserve_topology(distance_tolerance)
|
452
|
+
build_geometry do |ptr|
|
453
|
+
FFI::GDAL.OGR_G_SimplifyPreserveTopology(ptr, distance_tolerance)
|
454
|
+
end
|
455
|
+
end
|
456
|
+
|
457
|
+
# Modify the geometry so that it has no segments longer than +max_length+.
|
458
|
+
#
|
459
|
+
# @param max_length [Float]
|
460
|
+
def segmentize!(max_length)
|
461
|
+
FFI::GDAL.OGR_G_Segmentize(@geometry_pointer, max_length)
|
462
|
+
end
|
463
|
+
|
464
|
+
# @return [OGR::Geometry]
|
465
|
+
def boundary
|
466
|
+
build_geometry { |ptr| FFI::GDAL.OGR_G_Boundary(ptr) }
|
467
|
+
end
|
468
|
+
|
469
|
+
# @param distance [Float] The buffer distance to be applied.
|
470
|
+
# @param quad_segments [Fixnum] The number of segments to use to approximate
|
471
|
+
# a 90 degree (quadrant) of curvature.
|
472
|
+
# @return [OGR::Geometry]
|
473
|
+
def buffer(distance, quad_segments)
|
474
|
+
build_geometry do |ptr|
|
475
|
+
FFI::GDAL.OGR_G_Buffer(ptr, distance, quad_segments)
|
476
|
+
end
|
477
|
+
end
|
478
|
+
|
479
|
+
# @return [OGR::Geometry]
|
480
|
+
def convex_hull
|
481
|
+
build_geometry { |ptr| FFI::GDAL.OGR_G_ConvexHull(ptr) }
|
482
|
+
end
|
483
|
+
|
484
|
+
# TODO: should this be a class method?
|
485
|
+
# @param wkb_data [String] Binary WKB data.
|
486
|
+
# @return +true+ if successful, otherwise raises an OGR exception.
|
487
|
+
def from_wkb(wkb_data)
|
488
|
+
ogr_err = FFI::GDAL.OGR_G_ImportFromWkb(@geometry_pointer, wkb_data, wkb_data.length)
|
489
|
+
|
490
|
+
ogr_err.to_ruby
|
491
|
+
end
|
492
|
+
|
493
|
+
# The exact number of bytes required to hold the WKB of this object.
|
494
|
+
#
|
495
|
+
# @return [Fixnum]
|
496
|
+
def wkb_size
|
497
|
+
FFI::GDAL.OGR_G_WkbSize(@geometry_pointer)
|
498
|
+
end
|
499
|
+
|
500
|
+
# @return [String]
|
501
|
+
def to_wkb(byte_order=:wkbXDR)
|
502
|
+
output = FFI::MemoryPointer.new(:uchar, wkb_size)
|
503
|
+
ogr_err = FFI::GDAL.OGR_G_ExportToWkb(@geometry_pointer, byte_order, output)
|
504
|
+
ogr_err.to_ruby
|
505
|
+
|
506
|
+
output.read_bytes(wkb_size)
|
507
|
+
end
|
508
|
+
|
509
|
+
# TODO: should this be a class method?
|
510
|
+
# @param wkt_data [String]
|
511
|
+
def from_wkt(wkt_data)
|
512
|
+
wkt_data_pointer = FFI::MemoryPointer.from_string(wkt_data)
|
513
|
+
wkt_pointer_pointer = FFI::MemoryPointer.new(:pointer)
|
514
|
+
wkt_pointer_pointer.write_pointer(wkt_data_pointer)
|
515
|
+
ogr_err = FFI::GDAL.OGR_G_ImportFromWkt(@geometry_pointer, wkt_pointer_pointer)
|
516
|
+
|
517
|
+
ogr_err.to_ruby
|
518
|
+
end
|
519
|
+
|
520
|
+
# @return [String]
|
521
|
+
def to_wkt
|
522
|
+
output = FFI::MemoryPointer.new(:string)
|
523
|
+
ogr_err = FFI::GDAL.OGR_G_ExportToWkt(@geometry_pointer, output)
|
524
|
+
ogr_err.to_ruby
|
525
|
+
|
526
|
+
output.read_pointer.read_string
|
527
|
+
end
|
528
|
+
|
529
|
+
# This geometry expressed as GML in GML basic data types.
|
530
|
+
#
|
531
|
+
# @return [String]
|
532
|
+
def to_gml
|
533
|
+
FFI::GDAL.OGR_G_ExportToGML(@geometry_pointer)
|
534
|
+
end
|
535
|
+
|
536
|
+
# @param altitude_mode [String] Value to write in the +altitudeMode+
|
537
|
+
# element.
|
538
|
+
# @return [String]
|
539
|
+
def to_kml(altitude_mode=nil)
|
540
|
+
FFI::GDAL.OGR_G_ExportToKML(@geometry_pointer, altitude_mode)
|
541
|
+
end
|
542
|
+
|
543
|
+
# @return [String]
|
544
|
+
def to_geo_json
|
545
|
+
FFI::GDAL.OGR_G_ExportToJson(@geometry_pointer)
|
546
|
+
end
|
547
|
+
|
548
|
+
# Converts the current geometry to a Polygon geometry. The returned object
|
549
|
+
# is a new OGR::Geometry instance.
|
550
|
+
#
|
551
|
+
# @return [OGR::Geometry]
|
552
|
+
def to_polygon
|
553
|
+
build_geometry { |ptr| FFI::GDAL.OGR_G_ForceToPolygon(ptr) }
|
554
|
+
end
|
555
|
+
|
556
|
+
# Converts the current geometry to a LineString geometry. The returned
|
557
|
+
# object is a new OGR::Geometry instance.
|
558
|
+
#
|
559
|
+
# @return [OGR::Geometry]
|
560
|
+
def to_line_string
|
561
|
+
build_geometry { |ptr| FFI::GDAL.OGR_G_ForceToLineString(ptr) }
|
562
|
+
end
|
563
|
+
|
564
|
+
# Converts the current geometry to a MultiPolygon geometry. The returned
|
565
|
+
# object is a new OGR::Geometry instance.
|
566
|
+
#
|
567
|
+
# @return [OGR::Geometry]
|
568
|
+
def to_multi_polygon
|
569
|
+
build_geometry { |ptr| FFI::GDAL.OGR_G_ForceToMultiPolygon(ptr) }
|
570
|
+
end
|
571
|
+
|
572
|
+
# Converts the current geometry to a MultiPoint geometry. The returned
|
573
|
+
# object is a new OGR::Geometry instance.
|
574
|
+
#
|
575
|
+
# @return [OGR::Geometry]
|
576
|
+
def to_multi_point
|
577
|
+
build_geometry { |ptr| FFI::GDAL.OGR_G_ForceToMultiPoint(ptr) }
|
578
|
+
end
|
579
|
+
|
580
|
+
# Converts the current geometry to a MultiLineString geometry. The returned
|
581
|
+
# object is a new OGR::Geometry instance.
|
582
|
+
#
|
583
|
+
# @return [OGR::Geometry]
|
584
|
+
def to_multi_line_string
|
585
|
+
build_geometry { |ptr| FFI::GDAL.OGR_G_ForceToMultiLineString(ptr) }
|
586
|
+
end
|
587
|
+
|
588
|
+
private
|
589
|
+
|
590
|
+
def build_geometry
|
591
|
+
geometry_ptr = yield(@geometry_pointer)
|
592
|
+
return nil if geometry_ptr.null?
|
593
|
+
|
594
|
+
if geometry_ptr == @geometry_pointer
|
595
|
+
log 'Newly created geometry and current geometry are the same.'
|
596
|
+
end
|
597
|
+
|
598
|
+
self.class._to_geometry_type(geometry_ptr)
|
599
|
+
end
|
600
|
+
|
601
|
+
def pointer_from(geometry)
|
602
|
+
if geometry.is_a? OGR::Geometry
|
603
|
+
geometry.c_pointer
|
604
|
+
elsif geometry.kind_of? FFI::Pointer
|
605
|
+
geometry
|
606
|
+
end
|
607
|
+
end
|
608
|
+
|
609
|
+
def object_from(geometry)
|
610
|
+
if geometry.is_a? OGR::Geometry
|
611
|
+
geometry
|
612
|
+
elsif geometry.kind_of? FFI::Pointer
|
613
|
+
geometry.c_pointer
|
614
|
+
end
|
615
|
+
end
|
616
|
+
end
|
617
|
+
end
|