ffi-ogr 0.0.1.pre → 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/README.md +22 -12
- data/lib/ffi-ogr/coordinate_transformation.rb +30 -0
- data/lib/ffi-ogr/data_source.rb +158 -19
- data/lib/ffi-ogr/envelope.rb +33 -0
- data/lib/ffi-ogr/feature.rb +20 -7
- data/lib/ffi-ogr/geometry.rb +49 -4
- data/lib/ffi-ogr/layer.rb +41 -6
- data/lib/ffi-ogr/options_struct.rb +10 -0
- data/lib/ffi-ogr/spatial_reference.rb +81 -0
- data/lib/ffi-ogr/tools.rb +19 -12
- data/lib/ffi-ogr/version.rb +1 -1
- data/lib/ffi-ogr/writer.rb +4 -4
- data/lib/ffi-ogr.rb +41 -3
- metadata +13 -9
data/README.md
CHANGED
@@ -6,33 +6,46 @@ To run: `bin/ogr_console`
|
|
6
6
|
To read a shapefile:
|
7
7
|
|
8
8
|
```ruby
|
9
|
+
shp = OGR::ShpReader.new.read './spec/data/ne_110m_coastline/ne_110m_coastline.shp'
|
10
|
+
# => #<OGR::DataSource:0x007fba4d19c328 @ptr=#<FFI::AutoPointer address=0x007fba4c4cdc50>>
|
11
|
+
|
12
|
+
shp.to_geojson '~/Desktop/output.geojson'
|
13
|
+
# => Output GeoJSON to specified file
|
14
|
+
```
|
15
|
+
|
16
|
+
To reproject a shapefile:
|
9
17
|
|
18
|
+
```ruby
|
10
19
|
shp = OGR::ShpReader.new.read './spec/data/ne_110m_coastline/ne_110m_coastline.shp'
|
11
|
-
# => #<OGR::DataSource:0x007fba4d19c328 @
|
20
|
+
# => #<OGR::DataSource:0x007fba4d19c328 @ptr=#<FFI::AutoPointer address=0x007fba4c4cdc50>>
|
21
|
+
|
22
|
+
shp.to_json
|
23
|
+
# => Output GeoJSON string
|
24
|
+
|
25
|
+
shp.to_json true
|
26
|
+
# => Output GeoJSON string (pretty print)
|
12
27
|
|
13
|
-
|
14
|
-
|
28
|
+
# from_epsg(integer), from_proj4(string), from_wkt(string)
|
29
|
+
new_sr = OGR::SpatialReference.from_epsg 3857
|
30
|
+
# => #<OGR::SpatialReference:0x007fd859a0e6f8 @ptr=#<FFI::AutoPointer address=0x007fd85a11c100>>
|
15
31
|
|
16
|
-
shp.
|
17
|
-
# =>
|
32
|
+
shp.to_shp '~/Desktop/reprojected_shp.shp', {spatial_ref: new_sr}
|
33
|
+
# => Output reprojected SHP to specified file
|
18
34
|
```
|
19
35
|
|
20
36
|
A reader may also be inferred by file extension (currently works for shp and json/geojson):
|
21
37
|
|
22
38
|
```ruby
|
23
|
-
|
24
39
|
shp = OGR::Reader.from_file_type './spec/data/ne_110m_coastline/ne_110m_coastline.shp'
|
25
|
-
|
26
40
|
```
|
27
41
|
|
28
42
|
To create a shapefile:
|
29
43
|
|
30
44
|
```ruby
|
31
|
-
|
32
45
|
writer = OGR::ShpWriter.new
|
33
46
|
writer.set_output '~/Documents/shapefiles/my_new.shp'
|
34
47
|
|
35
|
-
shp = writer.
|
48
|
+
shp = writer.ptr
|
36
49
|
|
37
50
|
# add layer to shp : add_layer(name, geometry_type, spatial_reference)
|
38
51
|
# currently does not handle spatial reference, will automatically be nil
|
@@ -58,15 +71,12 @@ layer.add_feature feature
|
|
58
71
|
|
59
72
|
# sync to disk
|
60
73
|
layer.sync
|
61
|
-
|
62
74
|
```
|
63
75
|
|
64
76
|
A writer may also be inferred by file extension (currently works for shp and json/geojson):
|
65
77
|
|
66
78
|
```ruby
|
67
|
-
|
68
79
|
writer = OGR::Writer.from_file_type '~/Documents/shapefiles/my_new.shp'
|
69
|
-
|
70
80
|
```
|
71
81
|
|
72
82
|
Tested on: MRI 1.9.3-p392 and JRuby 1.7.3
|
@@ -0,0 +1,30 @@
|
|
1
|
+
module OGR
|
2
|
+
class CoordinateTransformation
|
3
|
+
attr_accessor :ptr
|
4
|
+
|
5
|
+
def initialize(ptr)
|
6
|
+
@ptr = FFI::AutoPointer.new(ptr, self.class.method(:release))
|
7
|
+
@ptr.autorelease = false
|
8
|
+
end
|
9
|
+
|
10
|
+
def self.release(ptr);end
|
11
|
+
|
12
|
+
def free
|
13
|
+
FFIOGR.OCTDestroyCoordinateTransformation(@ptr)
|
14
|
+
end
|
15
|
+
|
16
|
+
def self.find_transformation(in_sr, out_sr)
|
17
|
+
bad_sr = []
|
18
|
+
|
19
|
+
if !in_sr.instance_of?(OGR::SpatialReference)
|
20
|
+
bad_sr << 'Input SR'
|
21
|
+
elsif !out_sr.instance_of?(OGR::SpatialReference)
|
22
|
+
bad_sr << 'Output SR'
|
23
|
+
end
|
24
|
+
|
25
|
+
raise RuntimeError.new("Invalid Spatial Reference(s): #{bad_sr.join(', ')}") if bad_sr.size > 0
|
26
|
+
|
27
|
+
FFIOGR.OCTNewCoordinateTransformation(in_sr.ptr, out_sr.ptr)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
data/lib/ffi-ogr/data_source.rb
CHANGED
@@ -2,31 +2,108 @@ module OGR
|
|
2
2
|
class DataSource
|
3
3
|
include FFIOGR
|
4
4
|
|
5
|
-
attr_accessor :
|
5
|
+
attr_accessor :ptr
|
6
6
|
|
7
|
-
def initialize(ptr
|
8
|
-
@
|
9
|
-
@
|
7
|
+
def initialize(ptr)
|
8
|
+
@ptr = FFI::AutoPointer.new(ptr, self.class.method(:release))
|
9
|
+
@ptr.autorelease = false
|
10
10
|
end
|
11
11
|
|
12
|
-
def self.release(ptr)
|
13
|
-
|
12
|
+
def self.release(ptr);end
|
13
|
+
|
14
|
+
def free
|
15
|
+
FFIOGR.OGR_DS_Destroy(@ptr)
|
16
|
+
end
|
17
|
+
|
18
|
+
def copy(output_type, output_path, driver_options=nil)
|
19
|
+
driver = OGRGetDriverByName(OGR::DRIVER_TYPES[output_type.downcase])
|
20
|
+
new_ds = FFIOGR.OGR_Dr_CopyDataSource(driver, @ptr, File.expand_path(output_path), driver_options)
|
21
|
+
FFIOGR.OGR_DS_Destroy(new_ds)
|
22
|
+
end
|
23
|
+
|
24
|
+
def copy_with_transform(output_type, output_path, spatial_ref=nil, driver_options=nil)
|
25
|
+
writer = OGR::GenericWriter.new(OGR::DRIVER_TYPES[output_type.downcase])
|
26
|
+
writer.set_output(output_path)
|
27
|
+
out = writer.ptr
|
28
|
+
|
29
|
+
layers.each do |layer|
|
30
|
+
name = layer.name
|
31
|
+
geometry_type = layer.geometry_type
|
32
|
+
old_sr = layer.spatial_ref
|
33
|
+
|
34
|
+
ct = OGR::CoordinateTransformation.find_transformation(old_sr, spatial_ref) unless spatial_ref.nil? || (spatial_ref == old_sr)
|
35
|
+
|
36
|
+
sr = spatial_ref.nil? ? nil : spatial_ref.ptr
|
37
|
+
|
38
|
+
new_layer = out.add_layer name, geometry_type, sr, driver_options
|
39
|
+
|
40
|
+
ptr = layer.ptr
|
41
|
+
|
42
|
+
layer_definition = FFIOGR.OGR_L_GetLayerDefn(ptr)
|
43
|
+
field_count = FFIOGR.OGR_FD_GetFieldCount(layer_definition)
|
44
|
+
|
45
|
+
for i in (0...field_count)
|
46
|
+
fd = FFIOGR.OGR_FD_GetFieldDefn(layer_definition, i)
|
47
|
+
name = FFIOGR.OGR_Fld_GetNameRef(fd)
|
48
|
+
type = FFIOGR.OGR_Fld_GetType(fd)
|
49
|
+
|
50
|
+
opts = {}
|
51
|
+
|
52
|
+
opts[:precision] = FFIOGR.OGR_Fld_GetPrecision(fd) if type == :real
|
53
|
+
opts[:width] = FFIOGR.OGR_Fld_GetWidth(fd) if type == :string
|
54
|
+
|
55
|
+
new_layer.add_field name, type
|
56
|
+
end
|
57
|
+
|
58
|
+
layer.features.each do |feature|
|
59
|
+
geometry = OGR::Tools.cast_geometry(feature.geometry)
|
60
|
+
geometry.transform ct if ct
|
61
|
+
|
62
|
+
new_feature = new_layer.create_feature
|
63
|
+
new_feature.add_geometry geometry
|
64
|
+
|
65
|
+
ptr = feature.ptr
|
66
|
+
field_count = FFIOGR.OGR_F_GetFieldCount(ptr)
|
67
|
+
|
68
|
+
for i in (0...field_count)
|
69
|
+
fd = FFIOGR.OGR_F_GetFieldDefnRef(ptr, i)
|
70
|
+
field_name = FFIOGR.OGR_Fld_GetNameRef(fd)
|
71
|
+
field_type = FFIOGR.OGR_Fld_GetType(fd)
|
72
|
+
|
73
|
+
case field_type
|
74
|
+
when :integer
|
75
|
+
field_value = FFIOGR.OGR_F_GetFieldAsInteger(ptr, i)
|
76
|
+
when :real
|
77
|
+
field_value = FFIOGR.OGR_F_GetFieldAsDouble(ptr, i)
|
78
|
+
else
|
79
|
+
field_value = FFIOGR.OGR_F_GetFieldAsString(ptr, i)
|
80
|
+
end
|
81
|
+
|
82
|
+
new_feature.set_field_value field_name, field_value, field_type
|
83
|
+
end
|
84
|
+
|
85
|
+
new_layer.add_feature new_feature
|
86
|
+
end
|
87
|
+
|
88
|
+
new_layer.sync
|
89
|
+
end
|
90
|
+
out.free
|
14
91
|
end
|
15
92
|
|
16
|
-
def add_layer(name, geometry_type, spatial_ref=nil, options=
|
17
|
-
|
18
|
-
# need to add options as StringList ...
|
19
|
-
layer = FFIOGR.OGR_DS_CreateLayer(@ds, name, spatial_ref, geometry_type.to_sym, nil)
|
93
|
+
def add_layer(name, geometry_type, spatial_ref=nil, options=nil)
|
94
|
+
layer = FFIOGR.OGR_DS_CreateLayer(@ptr, name, spatial_ref, geometry_type.to_sym, options)
|
20
95
|
OGR::Tools.cast_layer(layer)
|
21
96
|
end
|
22
97
|
|
98
|
+
def num_layers
|
99
|
+
FFIOGR.OGR_DS_GetLayerCount(@ptr)
|
100
|
+
end
|
101
|
+
|
23
102
|
def get_layers
|
24
103
|
layers = []
|
25
104
|
|
26
|
-
num_layers = OGR_DS_GetLayerCount(@ds)
|
27
|
-
|
28
105
|
for i in (0...num_layers) do
|
29
|
-
layers << OGR::Tools.cast_layer(OGR_DS_GetLayer(@
|
106
|
+
layers << OGR::Tools.cast_layer(OGR_DS_GetLayer(@ptr, i))
|
30
107
|
end
|
31
108
|
|
32
109
|
layers
|
@@ -34,22 +111,84 @@ module OGR
|
|
34
111
|
alias_method :layers, :get_layers
|
35
112
|
|
36
113
|
def get_features
|
37
|
-
layers.map {|l| l.features}
|
114
|
+
layers.map {|l| l.features}
|
38
115
|
end
|
39
116
|
alias_method :features, :get_features
|
40
117
|
|
41
|
-
def get_geometries
|
42
|
-
|
118
|
+
def get_geometries(as_geojson=false)
|
119
|
+
unless as_geojson
|
120
|
+
features.map {|feature| feature.map {|f| OGR::Tools.cast_geometry(f.geometry)}}
|
121
|
+
else
|
122
|
+
features.map {|feature| feature.map {|f| OGR::Tools.cast_geometry(f.geometry).to_geojson}}
|
123
|
+
end
|
43
124
|
end
|
44
125
|
alias_method :geometries, :get_geometries
|
45
126
|
|
46
127
|
def get_fields
|
47
|
-
features.map {|f| f.fields}
|
128
|
+
features.map {|feature| feature.map {|f| f.fields}}
|
48
129
|
end
|
49
130
|
alias_method :fields, :get_fields
|
50
131
|
|
51
|
-
def
|
52
|
-
|
132
|
+
def to_shp(output_path, spatial_ref=nil)
|
133
|
+
raise RuntimeError.new("Output path not specified.") if output_path.nil?
|
134
|
+
|
135
|
+
# TODO: handle parsing of spatial_ref -> copy options
|
136
|
+
|
137
|
+
if spatial_ref.instance_of? OGR::SpatialReference
|
138
|
+
copy_with_transform('shapefile', output_path, spatial_ref)
|
139
|
+
elsif spatial_ref.nil?
|
140
|
+
copy('shapefile', output_path, spatial_ref)
|
141
|
+
end
|
142
|
+
end
|
143
|
+
|
144
|
+
def to_geojson(output_path, options=nil)
|
145
|
+
raise RuntimeError.new("Output path not specified.") if output_path.nil?
|
146
|
+
|
147
|
+
unless options.nil?
|
148
|
+
spatial_ref = options[:spatial_ref] ? options[:spatial_ref] : nil
|
149
|
+
|
150
|
+
if options[:bbox]
|
151
|
+
# this segfaults -- working on solution
|
152
|
+
bbox = FFI::MemoryPointer.from_string "WRITE_BBOX=YES"
|
153
|
+
driver_options = FFI::MemoryPointer.new :pointer, 1
|
154
|
+
driver_options[0].put_pointer 0, bbox
|
155
|
+
else
|
156
|
+
driver_options = nil
|
157
|
+
end
|
158
|
+
|
159
|
+
if spatial_ref
|
160
|
+
copy_with_transform('geojson', output_path, spatial_ref, driver_options)
|
161
|
+
else
|
162
|
+
copy('geojson', output_path, driver_options)
|
163
|
+
end
|
164
|
+
else
|
165
|
+
copy('geojson', output_path, nil)
|
166
|
+
end
|
167
|
+
end
|
168
|
+
|
169
|
+
def to_json(pretty=false)
|
170
|
+
h = {
|
171
|
+
type: 'FeatureCollection',
|
172
|
+
bbox: nil,
|
173
|
+
features: []
|
174
|
+
}
|
175
|
+
|
176
|
+
layers.each do |layer|
|
177
|
+
h[:bbox] = layer.envelope.to_a true
|
178
|
+
geometry_type = layer.geometry_type.to_s.capitalize
|
179
|
+
|
180
|
+
layer.features.each do |feature|
|
181
|
+
properties = feature.fields
|
182
|
+
geometry = OGR::Tools.cast_geometry(feature.geometry).to_geojson
|
183
|
+
h[:features] << {type: geometry_type, geometry: geometry, properties: properties}
|
184
|
+
end
|
185
|
+
end
|
186
|
+
|
187
|
+
unless pretty
|
188
|
+
MultiJson.dump(h)
|
189
|
+
else
|
190
|
+
MultiJson.dump(h, pretty: true)
|
191
|
+
end
|
53
192
|
end
|
54
193
|
end
|
55
194
|
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
module OGR
|
2
|
+
class Envelope
|
3
|
+
attr_accessor :min_x, :max_x, :min_y, :max_y
|
4
|
+
|
5
|
+
def initialize(env)
|
6
|
+
raise RuntimeError.new("Invalid envelope specified") unless env.size == 4
|
7
|
+
|
8
|
+
@min_x, @max_x = env[0], env[1]
|
9
|
+
@min_y, @max_y = env[2], env[3]
|
10
|
+
end
|
11
|
+
|
12
|
+
def to_a(se_nw=false)
|
13
|
+
unless se_nw
|
14
|
+
[@min_x, @max_x, @min_y, @max_y]
|
15
|
+
else
|
16
|
+
[@min_x, @min_y, @max_x, @max_y]
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
def to_hash
|
21
|
+
{min_x: @min_x, max_x: @max_x, min_y: @min_y, max_y: @max_y}
|
22
|
+
end
|
23
|
+
|
24
|
+
def to_json
|
25
|
+
MultiJson.dump(to_hash)
|
26
|
+
end
|
27
|
+
|
28
|
+
def to_polygon
|
29
|
+
coords = [[[@min_x, @min_y], [@min_x, @max_y], [@max_x, @max_y], [@max_x, @min_y], [@min_x, @min_y]]]
|
30
|
+
OGR::Polygon.create coords
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
data/lib/ffi-ogr/feature.rb
CHANGED
@@ -2,13 +2,16 @@ module OGR
|
|
2
2
|
class Feature
|
3
3
|
attr_accessor :ptr
|
4
4
|
|
5
|
-
def initialize(ptr
|
5
|
+
def initialize(ptr)
|
6
6
|
@ptr = FFI::AutoPointer.new(ptr, self.class.method(:release))
|
7
|
-
|
7
|
+
#@ptr = FFI::AutoPointer.new(ptr)
|
8
|
+
@ptr.autorelease = false
|
8
9
|
end
|
9
10
|
|
10
|
-
def self.release(ptr)
|
11
|
-
|
11
|
+
def self.release(ptr);end
|
12
|
+
|
13
|
+
def free
|
14
|
+
FFIOGR.OGR_F_Destroy(@ptr)
|
12
15
|
end
|
13
16
|
|
14
17
|
def set_field_value(name, value, field_type=nil)
|
@@ -25,7 +28,10 @@ module OGR
|
|
25
28
|
when :integer
|
26
29
|
FFIOGR.OGR_F_SetFieldInteger(@ptr, field_index, Integer(value))
|
27
30
|
when :real
|
28
|
-
|
31
|
+
#dbl_ptr = FFI::MemoryPointer.new(:double, 1)
|
32
|
+
#dbl_ptr.write_double(Float(value))
|
33
|
+
|
34
|
+
FFIOGR.OGR_F_SetFieldDouble(@ptr, field_index, value)
|
29
35
|
when :string
|
30
36
|
FFIOGR.OGR_F_SetFieldString(@ptr, field_index, String(value))
|
31
37
|
when :binary
|
@@ -34,8 +40,8 @@ module OGR
|
|
34
40
|
end
|
35
41
|
|
36
42
|
def add_geometry(geometry)
|
37
|
-
FFIOGR.OGR_F_SetGeometry(@ptr, geometry.ptr)
|
38
|
-
|
43
|
+
#FFIOGR.OGR_F_SetGeometry(@ptr, geometry.ptr)
|
44
|
+
FFIOGR.OGR_F_SetGeometryDirectly(@ptr, geometry.ptr)
|
39
45
|
end
|
40
46
|
|
41
47
|
def get_geometry
|
@@ -72,6 +78,13 @@ module OGR
|
|
72
78
|
end
|
73
79
|
alias_method :fields, :get_fields
|
74
80
|
|
81
|
+
def transform_to(out_sr)
|
82
|
+
geom = OGR::Tools.cast_geometry(geometry)
|
83
|
+
geom.transform(out_sr)
|
84
|
+
p geom.ptr
|
85
|
+
add_geometry(geom)
|
86
|
+
end
|
87
|
+
|
75
88
|
def to_geojson
|
76
89
|
{type: 'Feature', geometry: OGR::Tools.cast_geometry(geometry).to_geojson, properties: fields}
|
77
90
|
end
|
data/lib/ffi-ogr/geometry.rb
CHANGED
@@ -1,21 +1,46 @@
|
|
1
1
|
module OGR
|
2
2
|
class Geometry
|
3
|
-
|
3
|
+
attr_accessor :ptr
|
4
4
|
|
5
|
-
def initialize(ptr
|
5
|
+
def initialize(ptr)
|
6
6
|
@ptr = FFI::AutoPointer.new(ptr, self.class.method(:release))
|
7
|
-
#@ptr
|
7
|
+
#@ptr = FFI::AutoPointer.new(ptr)
|
8
|
+
@ptr.autorelease = false
|
8
9
|
end
|
9
10
|
|
10
11
|
def self.release(ptr);end
|
11
12
|
|
13
|
+
def free
|
14
|
+
FFIOGR.OGR_G_DestroyGeometry(@ptr)
|
15
|
+
end
|
16
|
+
|
17
|
+
def self.from_geojson(geojson)
|
18
|
+
if geojson.instance_of? String
|
19
|
+
geojson = MultiJson.load(geojson)
|
20
|
+
end
|
21
|
+
|
22
|
+
coords = geojson['coordinates']
|
23
|
+
|
24
|
+
case geojson['type']
|
25
|
+
when 'Point'
|
26
|
+
OGR::Point.create coords
|
27
|
+
when 'LineString'
|
28
|
+
OGR::LineString.create coords
|
29
|
+
when 'Polygon'
|
30
|
+
OGR::Polygon.create coords
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
12
34
|
def self.create_empty(geometry_type)
|
13
35
|
OGR::Tools.cast_geometry(FFIOGR.OGR_G_CreateGeometry(geometry_type))
|
14
36
|
end
|
15
37
|
|
16
38
|
def add_geometry(geometry)
|
17
39
|
FFIOGR.OGR_G_AddGeometry(@ptr, geometry.ptr)
|
18
|
-
|
40
|
+
end
|
41
|
+
|
42
|
+
def add_geometry_directly(geometry)
|
43
|
+
FFIOGR.OGR_G_AddGeometryDirectly(@ptr, geometry.ptr)
|
19
44
|
end
|
20
45
|
|
21
46
|
def add_point(coords)
|
@@ -44,6 +69,10 @@ module OGR
|
|
44
69
|
end
|
45
70
|
end
|
46
71
|
|
72
|
+
def is_3d?
|
73
|
+
!!(geometry_type.to_s =~ /_25d/)
|
74
|
+
end
|
75
|
+
|
47
76
|
def flatten
|
48
77
|
FFIOGR.OGR_G_FlattenTo2D(@ptr)
|
49
78
|
end
|
@@ -53,6 +82,15 @@ module OGR
|
|
53
82
|
end
|
54
83
|
alias_method :geometry_type, :get_geometry_type
|
55
84
|
|
85
|
+
def get_spatial_ref
|
86
|
+
OGR::Tools.cast_spatial_reference(FFIOGR.OGR_G_GetSpatialReference(@ptr))
|
87
|
+
end
|
88
|
+
alias_method :spatial_ref, :get_spatial_ref
|
89
|
+
|
90
|
+
def transform(ct)
|
91
|
+
FFIOGR.OGR_G_Transform(@ptr, ct)
|
92
|
+
end
|
93
|
+
|
56
94
|
def get_length
|
57
95
|
FFIOGR.OGR_G_Length(@ptr)
|
58
96
|
end
|
@@ -68,6 +106,13 @@ module OGR
|
|
68
106
|
end
|
69
107
|
alias_method :boundary, :get_boundary
|
70
108
|
|
109
|
+
def get_envelope
|
110
|
+
envelope = FFI::MemoryPointer.new :pointer, 4
|
111
|
+
FFIOGR.OGR_G_GetEnvelope(@ptr, envelope)
|
112
|
+
OGR::Envelope.new(envelope.read_array_of_double(4))
|
113
|
+
end
|
114
|
+
alias_method :envelope, :get_envelope
|
115
|
+
|
71
116
|
def to_geojson
|
72
117
|
MultiJson.load(FFIOGR.OGR_G_ExportToJson(@ptr))
|
73
118
|
end
|
data/lib/ffi-ogr/layer.rb
CHANGED
@@ -2,22 +2,57 @@ module OGR
|
|
2
2
|
class Layer
|
3
3
|
attr_accessor :ptr, :name, :geometry_type
|
4
4
|
|
5
|
-
def initialize(ptr
|
5
|
+
def initialize(ptr)
|
6
6
|
@ptr = FFI::AutoPointer.new(ptr, self.class.method(:release))
|
7
|
-
|
8
|
-
@
|
9
|
-
#@ptr.autorelease = auto_free
|
7
|
+
#@ptr = FFI::AutoPointer.new(ptr)
|
8
|
+
@ptr.autorelease = false
|
10
9
|
end
|
11
10
|
|
12
11
|
def self.release(ptr);end
|
13
12
|
|
13
|
+
def free
|
14
|
+
@ptr.free
|
15
|
+
end
|
16
|
+
|
14
17
|
def sync
|
15
18
|
FFIOGR.OGR_L_SyncToDisk(@ptr)
|
16
19
|
end
|
17
20
|
|
18
|
-
def
|
21
|
+
def get_envelope
|
22
|
+
envelope = FFI::MemoryPointer.new :pointer, 4
|
23
|
+
FFIOGR.OGR_L_GetExtent(@ptr, envelope, 0)
|
24
|
+
OGR::Envelope.new(envelope.read_array_of_double(4))
|
25
|
+
end
|
26
|
+
alias_method :envelope, :get_envelope
|
27
|
+
|
28
|
+
def get_name
|
29
|
+
FFIOGR.OGR_L_GetName(@ptr)
|
30
|
+
end
|
31
|
+
alias_method :name, :get_name
|
32
|
+
|
33
|
+
def get_geometry_type
|
34
|
+
FFIOGR.OGR_L_GetGeomType(@ptr)
|
35
|
+
end
|
36
|
+
alias_method :geometry_type, :get_geometry_type
|
37
|
+
|
38
|
+
def get_spatial_ref
|
39
|
+
OGR::Tools.cast_spatial_reference(FFIOGR.OGR_L_GetSpatialRef(@ptr))
|
40
|
+
end
|
41
|
+
alias_method :spatial_ref, :get_spatial_ref
|
42
|
+
|
43
|
+
def add_field(name, field_type, options={})
|
44
|
+
type = field_type.to_sym
|
45
|
+
precision = options[:precision] || 1
|
46
|
+
width = options[:width] || 32
|
47
|
+
|
19
48
|
field = FFIOGR.OGR_Fld_Create(name, field_type.to_sym)
|
20
|
-
|
49
|
+
|
50
|
+
if type == :real
|
51
|
+
FFIOGR.OGR_Fld_SetPrecision(field, precision)
|
52
|
+
else
|
53
|
+
FFIOGR.OGR_Fld_SetWidth(field, width)
|
54
|
+
end
|
55
|
+
|
21
56
|
FFIOGR.OGR_L_CreateField(@ptr, field, 1)
|
22
57
|
FFIOGR.OGR_Fld_Destroy(field)
|
23
58
|
end
|
@@ -0,0 +1,81 @@
|
|
1
|
+
module OGR
|
2
|
+
class SpatialReference
|
3
|
+
attr_accessor :ptr
|
4
|
+
|
5
|
+
def initialize(ptr)
|
6
|
+
@ptr = FFI::AutoPointer.new(ptr, self.class.method(:release))
|
7
|
+
@ptr.autorelease = false
|
8
|
+
end
|
9
|
+
|
10
|
+
def self.release(ptr);end
|
11
|
+
|
12
|
+
def free
|
13
|
+
FFIOGR.OSRDestroySpatialReference(@ptr)
|
14
|
+
end
|
15
|
+
|
16
|
+
def self.create
|
17
|
+
OGR::Tools.cast_spatial_reference(FFIOGR.OSRNewSpatialReference(nil))
|
18
|
+
end
|
19
|
+
|
20
|
+
def self.from_wkt(wkt)
|
21
|
+
sr = OGR::Tools.cast_spatial_reference(FFIOGR.OSRNewSpatialReference(nil))
|
22
|
+
sr.import_wkt(wkt)
|
23
|
+
sr
|
24
|
+
end
|
25
|
+
|
26
|
+
def self.from_proj4(proj4)
|
27
|
+
sr = OGR::Tools.cast_spatial_reference(FFIOGR.OSRNewSpatialReference(nil))
|
28
|
+
sr.import_proj4(proj4)
|
29
|
+
sr
|
30
|
+
end
|
31
|
+
|
32
|
+
def self.from_epsg(epsg_code)
|
33
|
+
sr = OGR::Tools.cast_spatial_reference(FFIOGR.OSRNewSpatialReference(nil))
|
34
|
+
sr.import_epsg(epsg_code)
|
35
|
+
sr
|
36
|
+
end
|
37
|
+
|
38
|
+
def import_wkt(wkt)
|
39
|
+
wkt_ptr = FFI::MemoryPointer.from_string wkt
|
40
|
+
wkt_ptr_ptr = FFI::MemoryPointer.new :pointer
|
41
|
+
wkt_ptr_ptr.put_pointer 0, wkt_ptr
|
42
|
+
FFIOGR.OSRImportFromWkt(@ptr, wkt_ptr_ptr)
|
43
|
+
end
|
44
|
+
|
45
|
+
def import_proj4(proj4)
|
46
|
+
FFIOGR.OSRImportFromProj4(@ptr, proj4)
|
47
|
+
end
|
48
|
+
|
49
|
+
def import_epsg(epsg_code)
|
50
|
+
FFIOGR.OSRImportFromEPSG(@ptr, epsg_code)
|
51
|
+
end
|
52
|
+
|
53
|
+
def to_wkt(pretty=false)
|
54
|
+
ptr = FFI::MemoryPointer.new :pointer
|
55
|
+
|
56
|
+
unless pretty
|
57
|
+
FFIOGR.OSRExportToWkt(@ptr, ptr)
|
58
|
+
else
|
59
|
+
FFIOGR.OSRExportToPrettyWkt(@ptr, ptr, 4)
|
60
|
+
end
|
61
|
+
str_ptr = ptr.read_pointer
|
62
|
+
|
63
|
+
return str_ptr.null? ? nil : str_ptr.read_string
|
64
|
+
end
|
65
|
+
|
66
|
+
def to_proj4
|
67
|
+
ptr = FFI::MemoryPointer.new :pointer
|
68
|
+
FFIOGR.OSRExportToProj4(@ptr, ptr)
|
69
|
+
str_ptr = ptr.read_pointer
|
70
|
+
return str_ptr.null? ? nil: str_ptr.read_string
|
71
|
+
end
|
72
|
+
|
73
|
+
def ==(other)
|
74
|
+
self.to_wkt == other.to_wkt
|
75
|
+
end
|
76
|
+
|
77
|
+
def find_transformation(out_sr)
|
78
|
+
CoordinateTransformation.find_transformation self, out_sr
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
data/lib/ffi-ogr/tools.rb
CHANGED
@@ -1,26 +1,33 @@
|
|
1
1
|
module OGR
|
2
2
|
module Tools
|
3
3
|
class << self
|
4
|
-
def
|
5
|
-
|
4
|
+
def cast_spatial_reference(sr_ptr, auto_free=true)
|
5
|
+
raise RuntimeError.new("Spatial Reference pointer is NULL") if sr_ptr.null?
|
6
|
+
SpatialReference.new sr_ptr
|
7
|
+
end
|
8
|
+
|
9
|
+
def cast_coordinate_transformation(ct_ptr, auto_free=true)
|
10
|
+
raise RuntimeError.new("Coordinate Transformation pointer is NULL") if ct_ptr.null?
|
11
|
+
CoordinateTransformation.new ct_ptr
|
12
|
+
end
|
13
|
+
|
14
|
+
def cast_data_source(ds_ptr, auto_free=true)
|
6
15
|
raise RuntimeError.new("Data Source pointer is NULL") if ds_ptr.null?
|
7
|
-
DataSource.new ds_ptr
|
16
|
+
DataSource.new ds_ptr
|
8
17
|
end
|
9
18
|
|
10
|
-
def cast_layer(l_ptr,
|
11
|
-
options = {auto_free: true}.merge(options)
|
19
|
+
def cast_layer(l_ptr, auto_free=true)
|
12
20
|
raise RuntimeError.new("Layer pointer is NULL") if l_ptr.null?
|
13
|
-
Layer.new l_ptr
|
21
|
+
Layer.new l_ptr
|
14
22
|
end
|
15
23
|
|
16
|
-
def cast_feature(f_ptr,
|
17
|
-
options = {auto_free: true}.merge(options)
|
24
|
+
def cast_feature(f_ptr, auto_free=true)
|
18
25
|
raise RuntimeError.new("Feature pointer is NULL") if f_ptr.null?
|
19
|
-
Feature.new f_ptr
|
26
|
+
Feature.new f_ptr
|
20
27
|
end
|
21
28
|
|
22
|
-
def cast_geometry(geom_ptr,
|
23
|
-
options = {auto_free: true}.merge(options)
|
29
|
+
def cast_geometry(geom_ptr, auto_free=true)
|
30
|
+
#options = {auto_free: true}.merge(options)
|
24
31
|
raise RuntimeError.new("Geometry pointer is NULL") if geom_ptr.null?
|
25
32
|
|
26
33
|
geom_type = FFIOGR.OGR_G_GetGeometryType(geom_ptr)
|
@@ -58,7 +65,7 @@ module OGR
|
|
58
65
|
OGR::GeometryCollection25D
|
59
66
|
end
|
60
67
|
|
61
|
-
klass.new(geom_ptr
|
68
|
+
klass.new(geom_ptr)
|
62
69
|
end
|
63
70
|
end
|
64
71
|
end
|
data/lib/ffi-ogr/version.rb
CHANGED
data/lib/ffi-ogr/writer.rb
CHANGED
@@ -2,15 +2,15 @@ module OGR
|
|
2
2
|
class Writer
|
3
3
|
include OGR::FFIOGR
|
4
4
|
|
5
|
-
attr_accessor :
|
5
|
+
attr_accessor :ptr
|
6
6
|
|
7
7
|
def initialize;end
|
8
8
|
|
9
9
|
def set_output(path, options={})
|
10
10
|
path = File.expand_path(path)
|
11
11
|
ds = OGR_Dr_CreateDataSource(@driver, path, nil)
|
12
|
-
@
|
13
|
-
@
|
12
|
+
@ptr = OGR::Tools.cast_data_source(ds)
|
13
|
+
@ptr
|
14
14
|
end
|
15
15
|
|
16
16
|
def self.from_file_type(path)
|
@@ -36,7 +36,7 @@ module OGR
|
|
36
36
|
writer = Writer.from_file_type output_path
|
37
37
|
data_source = writer.ds
|
38
38
|
|
39
|
-
# @
|
39
|
+
# @ptr -> data_source
|
40
40
|
end
|
41
41
|
end
|
42
42
|
end
|
data/lib/ffi-ogr.rb
CHANGED
@@ -4,6 +4,11 @@ require 'multi_json'
|
|
4
4
|
module OGR
|
5
5
|
OGR_BASE = File.join(File.dirname(__FILE__), 'ffi-ogr')
|
6
6
|
|
7
|
+
DRIVER_TYPES = {
|
8
|
+
'shapefile' => 'ESRI Shapefile',
|
9
|
+
'geojson' => 'GeoJSON'
|
10
|
+
}
|
11
|
+
|
7
12
|
autoload :Reader, File.join(OGR_BASE, 'reader')
|
8
13
|
autoload :GenericReader, File.join(OGR_BASE, 'generic_reader')
|
9
14
|
autoload :ShpReader, File.join(OGR_BASE, 'shp_reader')
|
@@ -34,6 +39,10 @@ module OGR
|
|
34
39
|
autoload :MultiLineString25D, File.join(OGR_BASE, 'multi_line_string_25d')
|
35
40
|
autoload :MultiPolygon25D, File.join(OGR_BASE, 'multi_polygon_25d')
|
36
41
|
autoload :GeometryCollection25D, File.join(OGR_BASE, 'geometry_collection_25d')
|
42
|
+
autoload :Envelope, File.join(OGR_BASE, 'envelope')
|
43
|
+
autoload :SpatialReference, File.join(OGR_BASE, 'spatial_reference')
|
44
|
+
autoload :CoordinateTransformation, File.join(OGR_BASE, 'coordinate_transformation')
|
45
|
+
autoload :OptionsStruct, File.join(OGR_BASE, 'options_struct')
|
37
46
|
|
38
47
|
module FFIOGR
|
39
48
|
def self.search_paths
|
@@ -109,12 +118,17 @@ module OGR
|
|
109
118
|
:right, 2
|
110
119
|
]
|
111
120
|
|
121
|
+
attach_function :GDALVersionInfo, [:string], :string
|
122
|
+
|
123
|
+
attach_function :CPLSetConfigOption, [:string, :string], :void
|
124
|
+
attach_function :CPLSetThreadLocalConfigOption, [:string, :string], :void
|
125
|
+
|
112
126
|
attach_function :OGRRegisterAll, [], :void
|
113
127
|
attach_function :OGR_Dr_GetName, [:pointer], :string
|
114
128
|
attach_function :OGR_Dr_Open, [:pointer, :string, :int], :pointer
|
115
129
|
attach_function :OGR_Dr_TestCapability, [:pointer, :string], :int
|
116
|
-
attach_function :OGR_Dr_CreateDataSource, [:pointer, :string, :
|
117
|
-
attach_function :OGR_Dr_CopyDataSource, [:pointer, :pointer, :string, :
|
130
|
+
attach_function :OGR_Dr_CreateDataSource, [:pointer, :string, :pointer], :pointer
|
131
|
+
attach_function :OGR_Dr_CopyDataSource, [:pointer, :pointer, :string, :pointer], :pointer
|
118
132
|
attach_function :OGR_Dr_DeleteDataSource, [:pointer, :string], :pointer
|
119
133
|
attach_function :OGRGetDriverCount, [], :int
|
120
134
|
attach_function :OGRGetDriver, [:int], :pointer
|
@@ -127,7 +141,7 @@ module OGR
|
|
127
141
|
attach_function :OGR_DS_GetLayerByName, [:pointer, :string], :pointer
|
128
142
|
attach_function :OGR_DS_DeleteLayer, [:pointer, :int], :pointer
|
129
143
|
attach_function :OGR_DS_GetDriver, [:pointer], :pointer
|
130
|
-
attach_function :OGR_DS_CreateLayer, [:pointer, :string, :pointer, :ogr_geometry_type, :
|
144
|
+
attach_function :OGR_DS_CreateLayer, [:pointer, :string, :pointer, :ogr_geometry_type, :pointer], :pointer
|
131
145
|
attach_function :OGR_DS_CopyLayer, [:pointer, :pointer, :string, :string], :pointer
|
132
146
|
attach_function :OGR_DS_TestCapability, [:pointer, :string], :int
|
133
147
|
attach_function :OGR_DS_ExecuteSQL, [:pointer, :string, :pointer, :string], :pointer
|
@@ -195,6 +209,7 @@ module OGR
|
|
195
209
|
attach_function :OGR_F_GetGeometryRef, [:pointer], :pointer
|
196
210
|
attach_function :OGR_F_GetFID, [:pointer], :long
|
197
211
|
attach_function :OGR_F_SetFID, [:pointer, :long], :pointer
|
212
|
+
attach_function :OGR_F_StealGeometry, [:pointer], :pointer
|
198
213
|
attach_function :OGR_F_SetGeometry, [:pointer, :pointer], :pointer
|
199
214
|
attach_function :OGR_F_SetGeometryDirectly, [:pointer, :pointer], :pointer
|
200
215
|
attach_function :OGR_G_CreateFromWkb, [:pointer, :pointer, :pointer, :int], :pointer
|
@@ -279,13 +294,36 @@ module OGR
|
|
279
294
|
attach_function :OGR_G_AddGeometryDirectly, [:pointer, :pointer], :pointer
|
280
295
|
attach_function :OGR_G_RemoveGeometry, [:pointer, :int, :int], :pointer
|
281
296
|
attach_function :OGR_F_Destroy, [:pointer], :void
|
297
|
+
|
298
|
+
# SRS Functions
|
299
|
+
|
300
|
+
attach_function :OSRNewSpatialReference, [:pointer], :pointer
|
301
|
+
attach_function :OSRImportFromWkt, [:pointer, :pointer], :pointer
|
302
|
+
attach_function :OSRImportFromProj4, [:pointer, :string], :pointer
|
303
|
+
attach_function :OSRImportFromEPSG, [:pointer, :int], :pointer
|
304
|
+
attach_function :OSRExportToWkt, [:pointer, :pointer], :pointer
|
305
|
+
attach_function :OSRExportToPrettyWkt, [:pointer, :pointer, :int], :pointer
|
306
|
+
attach_function :OSRExportToProj4, [:pointer, :pointer], :pointer
|
307
|
+
attach_function :OSRDestroySpatialReference, [:pointer], :void
|
308
|
+
attach_function :OCTNewCoordinateTransformation, [:pointer, :pointer], :pointer
|
309
|
+
attach_function :OCTDestroyCoordinateTransformation, [:pointer], :void
|
310
|
+
|
311
|
+
OGRRegisterAll() # register all available OGR drivers
|
282
312
|
end
|
283
313
|
|
284
314
|
class << self
|
315
|
+
def gdal_version
|
316
|
+
FFIOGR.GDALVersionInfo('RELEASE_NAME')
|
317
|
+
end
|
318
|
+
|
285
319
|
def to_binary(data)
|
286
320
|
buf = FFI::MemoryPointer.new(:char, value.size)
|
287
321
|
buf.put_bytes(0, data)
|
288
322
|
buf
|
289
323
|
end
|
324
|
+
|
325
|
+
def string_to_pointer(str)
|
326
|
+
FFI::MemoryPointer.from_string(str)
|
327
|
+
end
|
290
328
|
end
|
291
329
|
end
|
metadata
CHANGED
@@ -1,15 +1,15 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: ffi-ogr
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.1
|
5
|
-
prerelease:
|
4
|
+
version: 0.0.1
|
5
|
+
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
8
8
|
- Scooter Wadsworth
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2013-
|
12
|
+
date: 2013-04-11 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: ffi
|
@@ -18,7 +18,7 @@ dependencies:
|
|
18
18
|
requirements:
|
19
19
|
- - ! '>='
|
20
20
|
- !ruby/object:Gem::Version
|
21
|
-
version: 1.
|
21
|
+
version: 1.6.0
|
22
22
|
type: :runtime
|
23
23
|
prerelease: false
|
24
24
|
version_requirements: !ruby/object:Gem::Requirement
|
@@ -26,23 +26,23 @@ dependencies:
|
|
26
26
|
requirements:
|
27
27
|
- - ! '>='
|
28
28
|
- !ruby/object:Gem::Version
|
29
|
-
version: 1.
|
29
|
+
version: 1.6.0
|
30
30
|
- !ruby/object:Gem::Dependency
|
31
31
|
name: multi_json
|
32
32
|
requirement: !ruby/object:Gem::Requirement
|
33
33
|
none: false
|
34
34
|
requirements:
|
35
|
-
- -
|
35
|
+
- - '='
|
36
36
|
- !ruby/object:Gem::Version
|
37
|
-
version:
|
37
|
+
version: 1.7.2
|
38
38
|
type: :runtime
|
39
39
|
prerelease: false
|
40
40
|
version_requirements: !ruby/object:Gem::Requirement
|
41
41
|
none: false
|
42
42
|
requirements:
|
43
|
-
- -
|
43
|
+
- - '='
|
44
44
|
- !ruby/object:Gem::Version
|
45
|
-
version:
|
45
|
+
version: 1.7.2
|
46
46
|
- !ruby/object:Gem::Dependency
|
47
47
|
name: rake
|
48
48
|
requirement: !ruby/object:Gem::Requirement
|
@@ -85,7 +85,9 @@ extra_rdoc_files: []
|
|
85
85
|
files:
|
86
86
|
- README.md
|
87
87
|
- bin/ogr_console
|
88
|
+
- lib/ffi-ogr/coordinate_transformation.rb
|
88
89
|
- lib/ffi-ogr/data_source.rb
|
90
|
+
- lib/ffi-ogr/envelope.rb
|
89
91
|
- lib/ffi-ogr/feature.rb
|
90
92
|
- lib/ffi-ogr/generic_reader.rb
|
91
93
|
- lib/ffi-ogr/generic_writer.rb
|
@@ -105,6 +107,7 @@ files:
|
|
105
107
|
- lib/ffi-ogr/multi_point_25d.rb
|
106
108
|
- lib/ffi-ogr/multi_polygon.rb
|
107
109
|
- lib/ffi-ogr/multi_polygon_25d.rb
|
110
|
+
- lib/ffi-ogr/options_struct.rb
|
108
111
|
- lib/ffi-ogr/point.rb
|
109
112
|
- lib/ffi-ogr/point_25d.rb
|
110
113
|
- lib/ffi-ogr/polygon.rb
|
@@ -113,6 +116,7 @@ files:
|
|
113
116
|
- lib/ffi-ogr/shapefile.rb
|
114
117
|
- lib/ffi-ogr/shp_reader.rb
|
115
118
|
- lib/ffi-ogr/shp_writer.rb
|
119
|
+
- lib/ffi-ogr/spatial_reference.rb
|
116
120
|
- lib/ffi-ogr/tools.rb
|
117
121
|
- lib/ffi-ogr/version.rb
|
118
122
|
- lib/ffi-ogr/writer.rb
|