georuby 2.3.0 → 2.5.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +16 -9
- data/Rakefile +13 -14
- data/lib/geo_ruby/ewk.rb +2 -0
- data/lib/geo_ruby/{simple_features → ewk}/ewkb_parser.rb +206 -218
- data/lib/geo_ruby/ewk/ewkt_parser.rb +321 -0
- data/lib/geo_ruby/geojson.rb +27 -32
- data/lib/geo_ruby/georss.rb +88 -66
- data/lib/geo_ruby/gpx.rb +113 -1
- data/lib/geo_ruby/kml.rb +43 -31
- data/lib/geo_ruby/shp.rb +1 -0
- data/lib/geo_ruby/shp4r/dbf.rb +7 -3
- data/lib/geo_ruby/shp4r/shp.rb +297 -284
- data/lib/geo_ruby/simple_features.rb +2 -6
- data/lib/geo_ruby/simple_features/circle.rb +15 -13
- data/lib/geo_ruby/simple_features/envelope.rb +84 -77
- data/lib/geo_ruby/simple_features/geometry.rb +89 -69
- data/lib/geo_ruby/simple_features/geometry_collection.rb +46 -43
- data/lib/geo_ruby/simple_features/geometry_factory.rb +50 -47
- data/lib/geo_ruby/simple_features/helper.rb +14 -14
- data/lib/geo_ruby/simple_features/line_string.rb +94 -97
- data/lib/geo_ruby/simple_features/linear_ring.rb +4 -9
- data/lib/geo_ruby/simple_features/multi_line_string.rb +18 -21
- data/lib/geo_ruby/simple_features/multi_point.rb +18 -20
- data/lib/geo_ruby/simple_features/multi_polygon.rb +19 -25
- data/lib/geo_ruby/simple_features/point.rb +134 -128
- data/lib/geo_ruby/simple_features/polygon.rb +60 -59
- data/lib/geo_ruby/version.rb +1 -1
- data/spec/data/geojson/feature.json +9 -0
- data/spec/data/geojson/feature_collection.json +3 -4
- data/spec/geo_ruby/{simple_features → ewk}/ewkb_parser_spec.rb +56 -57
- data/spec/geo_ruby/{simple_features → ewk}/ewkt_parser_spec.rb +62 -63
- data/spec/geo_ruby/geojson_spec.rb +34 -17
- data/spec/geo_ruby/georss_spec.rb +76 -64
- data/spec/geo_ruby/{gpx4r/gpx_spec.rb → gpx_spec.rb} +25 -25
- data/spec/geo_ruby/kml_spec.rb +40 -36
- data/spec/geo_ruby/shp4r/shp_spec.rb +51 -51
- data/spec/geo_ruby/simple_features/circle_spec.rb +2 -2
- data/spec/geo_ruby/simple_features/envelope_spec.rb +8 -8
- data/spec/geo_ruby/simple_features/geometry_collection_spec.rb +26 -26
- data/spec/geo_ruby/simple_features/geometry_factory_spec.rb +5 -5
- data/spec/geo_ruby/simple_features/geometry_spec.rb +8 -8
- data/spec/geo_ruby/simple_features/line_string_spec.rb +102 -102
- data/spec/geo_ruby/simple_features/linear_ring_spec.rb +7 -7
- data/spec/geo_ruby/simple_features/multi_line_string_spec.rb +20 -20
- data/spec/geo_ruby/simple_features/multi_point_spec.rb +16 -16
- data/spec/geo_ruby/simple_features/multi_polygon_spec.rb +19 -19
- data/spec/geo_ruby/simple_features/point_spec.rb +180 -174
- data/spec/geo_ruby/simple_features/polygon_spec.rb +55 -56
- data/spec/geo_ruby_spec.rb +4 -4
- data/spec/spec_helper.rb +19 -13
- metadata +10 -9
- data/lib/geo_ruby/gpx4r/gpx.rb +0 -118
- data/lib/geo_ruby/simple_features/ewkt_parser.rb +0 -336
data/lib/geo_ruby/shp.rb
CHANGED
data/lib/geo_ruby/shp4r/dbf.rb
CHANGED
@@ -9,6 +9,7 @@ rescue LoadError
|
|
9
9
|
end
|
10
10
|
|
11
11
|
module GeoRuby
|
12
|
+
# Ruby .shp files
|
12
13
|
module Shp4r
|
13
14
|
Dbf = DBF
|
14
15
|
|
@@ -20,11 +21,12 @@ module GeoRuby
|
|
20
21
|
end
|
21
22
|
|
22
23
|
class Field < Column::Base
|
23
|
-
def initialize(name, type, length, decimal = 0, version=1,
|
24
|
-
super(name, type, length, decimal, version,
|
24
|
+
def initialize(name, type, length, decimal = 0, version = 1, enc = nil)
|
25
|
+
super(name, type, length, decimal, version, enc)
|
25
26
|
end
|
26
27
|
end
|
27
28
|
|
29
|
+
# Main DBF File Reader
|
28
30
|
class Reader < Table
|
29
31
|
alias_method :fields, :columns
|
30
32
|
def header_length
|
@@ -35,7 +37,9 @@ module GeoRuby
|
|
35
37
|
new(f)
|
36
38
|
end
|
37
39
|
|
38
|
-
def close
|
40
|
+
def close
|
41
|
+
nil
|
42
|
+
end
|
39
43
|
end
|
40
44
|
end
|
41
45
|
end
|
data/lib/geo_ruby/shp4r/shp.rb
CHANGED
@@ -1,12 +1,10 @@
|
|
1
1
|
require 'date'
|
2
|
-
require 'fileutils'
|
3
|
-
require File.dirname(__FILE__) + '/dbf'
|
4
|
-
|
2
|
+
require 'fileutils' unless defined?(FileUtils)
|
5
3
|
|
6
4
|
module GeoRuby
|
7
5
|
module Shp4r
|
8
|
-
|
9
|
-
#
|
6
|
+
# Enumerates all the types of SHP geometries.
|
7
|
+
# The MULTIPATCH one is the only one not currently supported by Geo_ruby.
|
10
8
|
module ShpType
|
11
9
|
NULL_SHAPE = 0
|
12
10
|
POINT = 1
|
@@ -23,33 +21,39 @@ module GeoRuby
|
|
23
21
|
MULTIPOINTM = 28
|
24
22
|
end
|
25
23
|
|
26
|
-
#An interface to an ESRI shapefile (actually 3 files : shp, shx and dbf).
|
24
|
+
# An interface to an ESRI shapefile (actually 3 files : shp, shx and dbf).
|
25
|
+
# Currently supports only the reading of geometries.
|
27
26
|
class ShpFile
|
28
|
-
attr_reader :shp_type, :record_count, :xmin, :ymin, :xmax, :ymax,
|
27
|
+
attr_reader :shp_type, :record_count, :xmin, :ymin, :xmax, :ymax,
|
28
|
+
:zmin, :zmax, :mmin, :mmax, :file_root, :file_length
|
29
29
|
|
30
30
|
include Enumerable
|
31
31
|
|
32
|
-
#Opens a SHP file. Both "abc.shp" and "abc" are accepted.
|
32
|
+
# Opens a SHP file. Both "abc.shp" and "abc" are accepted.
|
33
|
+
# The files "abc.shp", "abc.shx" and "abc.dbf" must be present
|
33
34
|
def initialize(file)
|
34
|
-
#strip the shp out of the file if present
|
35
|
-
@file_root = file.gsub(/.shp$/i,
|
36
|
-
#check existence of shp, dbf and shx files
|
37
|
-
unless File.
|
38
|
-
|
35
|
+
# strip the shp out of the file if present
|
36
|
+
@file_root = file.gsub(/.shp$/i, '')
|
37
|
+
# check existence of shp, dbf and shx files
|
38
|
+
unless File.exist?(@file_root + '.shp') && File.exist?(@file_root + '.dbf') && File.exist?(@file_root + '.shx')
|
39
|
+
fail MalformedShpException.new("Missing one of shp, dbf or shx for: #{@file}")
|
39
40
|
end
|
40
41
|
|
41
|
-
@dbf = Dbf::Reader.open(@file_root +
|
42
|
-
@shx = File.open(@file_root +
|
43
|
-
@shp = File.open(@file_root +
|
42
|
+
@dbf = Dbf::Reader.open(@file_root + '.dbf')
|
43
|
+
@shx = File.open(@file_root + '.shx', 'rb')
|
44
|
+
@shp = File.open(@file_root + '.shp', 'rb')
|
44
45
|
read_index
|
45
46
|
end
|
46
47
|
|
47
|
-
#force the reopening of the files compsing the shp.
|
48
|
+
# force the reopening of the files compsing the shp.
|
49
|
+
# Close before calling this.
|
48
50
|
def reload!
|
49
51
|
initialize(@file_root)
|
50
52
|
end
|
51
53
|
|
52
|
-
#opens a SHP "file". If a block is given, the ShpFile object
|
54
|
+
# opens a SHP "file". If a block is given, the ShpFile object
|
55
|
+
# is yielded to it and is closed upon return.
|
56
|
+
# Else a call to <tt>open</tt> is equivalent to <tt>ShpFile.new(...)</tt>.
|
53
57
|
def self.open(file)
|
54
58
|
shpfile = ShpFile.new(file)
|
55
59
|
if block_given?
|
@@ -60,40 +64,42 @@ module GeoRuby
|
|
60
64
|
end
|
61
65
|
end
|
62
66
|
|
63
|
-
#create a new Shapefile of the specified shp type (see ShpType) and
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
67
|
+
# create a new Shapefile of the specified shp type (see ShpType) and
|
68
|
+
# with the attribute specified in the +fields+ array (see Dbf::Field).
|
69
|
+
# If a block is given, the ShpFile object newly created is passed to it.
|
70
|
+
def self.create(file, shp_type, fields, &proc)
|
71
|
+
file_root = file.gsub(/.shp$/i, '')
|
72
|
+
shx_io = File.open(file_root + '.shx', 'wb')
|
73
|
+
shp_io = File.open(file_root + '.shp', 'wb')
|
74
|
+
dbf_io = File.open(file_root + '.dbf', 'wb')
|
75
|
+
str = [9994, 0, 0, 0, 0, 0, 50, 1000, shp_type, 0, 0, 0, 0, 0, 0, 0, 0].pack('N7V2E8')
|
70
76
|
shp_io << str
|
71
77
|
shx_io << str
|
72
|
-
rec_length = 1 + fields.
|
73
|
-
dbf_io << [3,107,7,7,0,33 + 32 * fields.length,rec_length
|
78
|
+
rec_length = 1 + fields.reduce(0) { |s, f| s + f.length } #+1 for the prefixed space (active record marker)
|
79
|
+
dbf_io << [3, 107, 7, 7, 0, 33 + 32 * fields.length, rec_length].pack('c4Vv2x20') # 32 bytes for first part of header
|
74
80
|
fields.each do |field|
|
75
|
-
dbf_io << [field.name,field.type,field.length,field.decimal].pack(
|
81
|
+
dbf_io << [field.name, field.type, field.length, field.decimal].pack('a10xax4CCx14')
|
76
82
|
end
|
77
|
-
dbf_io << ['0d'].pack(
|
83
|
+
dbf_io << ['0d'].pack('H2')
|
78
84
|
|
79
85
|
shx_io.close
|
80
86
|
shp_io.close
|
81
87
|
dbf_io.close
|
82
88
|
|
83
|
-
open(file
|
84
|
-
|
89
|
+
open(file, &proc)
|
85
90
|
end
|
86
91
|
|
87
|
-
#Closes a shapefile
|
92
|
+
# Closes a shapefile
|
88
93
|
def close
|
89
94
|
@dbf.close
|
90
95
|
@shx.close
|
91
96
|
@shp.close
|
92
97
|
end
|
93
98
|
|
94
|
-
#starts a transaction, to buffer physical file operations
|
99
|
+
# starts a transaction, to buffer physical file operations
|
100
|
+
# on the shapefile components.
|
95
101
|
def transaction
|
96
|
-
trs = ShpTransaction.new(self
|
102
|
+
trs = ShpTransaction.new(self, @dbf)
|
97
103
|
if block_given?
|
98
104
|
answer = yield trs
|
99
105
|
if answer == :rollback
|
@@ -106,30 +112,30 @@ module GeoRuby
|
|
106
112
|
end
|
107
113
|
end
|
108
114
|
|
109
|
-
#return the description of data fields
|
115
|
+
# return the description of data fields
|
110
116
|
def fields
|
111
117
|
@dbf.fields
|
112
118
|
end
|
113
119
|
|
114
|
-
#Tests if the file has no record
|
120
|
+
# Tests if the file has no record
|
115
121
|
def empty?
|
116
122
|
record_count == 0
|
117
123
|
end
|
118
124
|
|
119
|
-
#Goes through each record
|
125
|
+
# Goes through each record
|
120
126
|
def each
|
121
127
|
(0...record_count).each do |i|
|
122
128
|
yield get_record(i)
|
123
129
|
end
|
124
130
|
end
|
125
|
-
|
131
|
+
alias_method :each_record, :each
|
126
132
|
|
127
|
-
#Returns record +i+
|
133
|
+
# Returns record +i+
|
128
134
|
def [](i)
|
129
135
|
get_record(i)
|
130
136
|
end
|
131
137
|
|
132
|
-
#Returns all the records
|
138
|
+
# Returns all the records
|
133
139
|
def records
|
134
140
|
Array.new(record_count) do |i|
|
135
141
|
get_record(i)
|
@@ -137,61 +143,64 @@ module GeoRuby
|
|
137
143
|
end
|
138
144
|
|
139
145
|
private
|
146
|
+
|
140
147
|
def read_index
|
141
|
-
@file_length, @shp_type, @xmin, @ymin, @xmax, @ymax, @zmin, @zmax, @mmin
|
148
|
+
@file_length, @shp_type, @xmin, @ymin, @xmax, @ymax, @zmin, @zmax, @mmin, @mmax = @shx.read(100).unpack('x24Nx4VE8')
|
142
149
|
@record_count = (@file_length - 50) / 4
|
143
150
|
if @record_count == 0
|
144
|
-
#initialize the bboxes to default values so if data added, they will be replaced
|
145
|
-
@xmin, @ymin, @xmax, @ymax, @zmin, @zmax, @mmin
|
151
|
+
# initialize the bboxes to default values so if data added, they will be replaced
|
152
|
+
@xmin, @ymin, @xmax, @ymax, @zmin, @zmax, @mmin, @mmax = Float::MAX, Float::MAX, -Float::MAX, -Float::MAX, Float::MAX, -Float::MAX, Float::MAX, -Float::MAX
|
146
153
|
end
|
147
154
|
unless @record_count == @dbf.record_count
|
148
|
-
|
155
|
+
fail MalformedShpException.new('Not the same number of records in SHP and DBF')
|
149
156
|
end
|
150
157
|
end
|
151
158
|
|
152
|
-
#TODO : refactor to minimize redundant code
|
153
|
-
def get_record(
|
154
|
-
return nil if record_count <=
|
155
|
-
dbf_record = @dbf.record(
|
156
|
-
@shx.seek(100 + 8 *
|
157
|
-
offset,length = @shx.read(8).unpack(
|
159
|
+
# TODO : refactor to minimize redundant code
|
160
|
+
def get_record(index)
|
161
|
+
return nil if record_count <= index || index < 0
|
162
|
+
dbf_record = @dbf.record(index)
|
163
|
+
@shx.seek(100 + 8 * index) # 100 is the header length
|
164
|
+
offset, length = @shx.read(8).unpack('N2')
|
158
165
|
@shp.seek(offset * 2 + 8)
|
159
|
-
rec_shp_type = @shp.read(4).unpack(
|
166
|
+
rec_shp_type = @shp.read(4).unpack('V')[0]
|
160
167
|
|
161
|
-
case(rec_shp_type)
|
168
|
+
case (rec_shp_type)
|
162
169
|
when ShpType::POINT
|
163
|
-
x, y = @shp.read(16).unpack(
|
164
|
-
geometry = GeoRuby::SimpleFeatures::Point.from_x_y(x,y)
|
165
|
-
when ShpType::POLYLINE #actually creates a multi_polyline
|
166
|
-
@shp.seek(32,IO::SEEK_CUR) #extent
|
167
|
-
num_parts, num_points = @shp.read(8).unpack(
|
168
|
-
parts = @shp.read(num_parts * 4).unpack(
|
169
|
-
parts << num_points #indexes for LS of idx i go to parts of idx i to idx i +1
|
170
|
+
x, y = @shp.read(16).unpack('E2')
|
171
|
+
geometry = GeoRuby::SimpleFeatures::Point.from_x_y(x, y)
|
172
|
+
when ShpType::POLYLINE # actually creates a multi_polyline
|
173
|
+
@shp.seek(32, IO::SEEK_CUR) # extent
|
174
|
+
num_parts, num_points = @shp.read(8).unpack('V2')
|
175
|
+
parts = @shp.read(num_parts * 4).unpack('V' + num_parts.to_s)
|
176
|
+
parts << num_points # indexes for LS of idx i go to parts of idx i to idx i +1
|
170
177
|
points = Array.new(num_points) do
|
171
|
-
x, y = @shp.read(16).unpack(
|
172
|
-
GeoRuby::SimpleFeatures::Point.from_x_y(x,y)
|
178
|
+
x, y = @shp.read(16).unpack('E2')
|
179
|
+
GeoRuby::SimpleFeatures::Point.from_x_y(x, y)
|
173
180
|
end
|
174
181
|
line_strings = Array.new(num_parts) do |i|
|
175
|
-
GeoRuby::SimpleFeatures::LineString.from_points(points[(parts[i])...(parts[i+1])])
|
182
|
+
GeoRuby::SimpleFeatures::LineString.from_points(points[(parts[i])...(parts[i + 1])])
|
176
183
|
end
|
177
184
|
geometry = GeoRuby::SimpleFeatures::MultiLineString.from_line_strings(line_strings)
|
178
185
|
when ShpType::POLYGON
|
179
|
-
#TODO : TO CORRECT
|
180
|
-
#does not take into account the possibility that the outer loop could
|
181
|
-
#
|
182
|
-
|
183
|
-
|
184
|
-
|
185
|
-
|
186
|
+
# TODO : TO CORRECT
|
187
|
+
# does not take into account the possibility that the outer loop could
|
188
|
+
# be after the inner loops in the SHP + more than one outer loop
|
189
|
+
# Still sends back a multi polygon (so the correction above won't
|
190
|
+
# change what gets sent back)
|
191
|
+
@shp.seek(32, IO::SEEK_CUR)
|
192
|
+
num_parts, num_points = @shp.read(8).unpack('V2')
|
193
|
+
parts = @shp.read(num_parts * 4).unpack('V' + num_parts.to_s)
|
194
|
+
parts << num_points # indexes for LS of idx i go to parts of idx i to idx i +1
|
186
195
|
points = Array.new(num_points) do
|
187
|
-
x, y = @shp.read(16).unpack(
|
188
|
-
GeoRuby::SimpleFeatures::Point.from_x_y(x,y)
|
196
|
+
x, y = @shp.read(16).unpack('E2')
|
197
|
+
GeoRuby::SimpleFeatures::Point.from_x_y(x, y)
|
189
198
|
end
|
190
199
|
linear_rings = Array.new(num_parts) do |i|
|
191
|
-
GeoRuby::SimpleFeatures::LinearRing.from_points(points[(parts[i])...(parts[i+1])])
|
200
|
+
GeoRuby::SimpleFeatures::LinearRing.from_points(points[(parts[i])...(parts[i + 1])])
|
192
201
|
end
|
193
202
|
# geometry = GeoRuby::SimpleFeatures::MultiPolygon.from_polygons([GeoRuby::SimpleFeatures::Polygon.from_linear_rings(linear_rings)])
|
194
|
-
outer, inner = linear_rings.partition
|
203
|
+
outer, inner = linear_rings.partition(&:clockwise?)
|
195
204
|
|
196
205
|
# Make polygons from the outer rings so we can concatenate
|
197
206
|
# them with inner rings.
|
@@ -207,216 +216,210 @@ module GeoRuby
|
|
207
216
|
# TODO - what to do here? technically the geometry is
|
208
217
|
# not well formed (or our above assumption does not
|
209
218
|
# hold).
|
210
|
-
$stderr.puts
|
219
|
+
$stderr.puts 'Failed to find polygon for inner ring!'
|
211
220
|
end
|
212
221
|
end
|
213
222
|
|
214
223
|
geometry = GeoRuby::SimpleFeatures::MultiPolygon.from_polygons(outer)
|
215
224
|
when ShpType::MULTIPOINT
|
216
|
-
@shp.seek(32,IO::SEEK_CUR)
|
217
|
-
num_points = @shp.read(4).unpack(
|
225
|
+
@shp.seek(32, IO::SEEK_CUR)
|
226
|
+
num_points = @shp.read(4).unpack('V')[0]
|
218
227
|
points = Array.new(num_points) do
|
219
|
-
x, y = @shp.read(16).unpack(
|
220
|
-
GeoRuby::SimpleFeatures::Point.from_x_y(x,y)
|
228
|
+
x, y = @shp.read(16).unpack('E2')
|
229
|
+
GeoRuby::SimpleFeatures::Point.from_x_y(x, y)
|
221
230
|
end
|
222
231
|
geometry = GeoRuby::SimpleFeatures::MultiPoint.from_points(points)
|
223
232
|
|
224
|
-
|
225
233
|
when ShpType::POINTZ
|
226
|
-
x, y, z, m = @shp.read(24).unpack(
|
227
|
-
geometry = GeoRuby::SimpleFeatures::Point.from_x_y_z_m(x,y,z,m)
|
228
|
-
|
234
|
+
x, y, z, m = @shp.read(24).unpack('E4')
|
235
|
+
geometry = GeoRuby::SimpleFeatures::Point.from_x_y_z_m(x, y, z, m)
|
229
236
|
|
230
237
|
when ShpType::POLYLINEZ
|
231
|
-
@shp.seek(32,IO::SEEK_CUR)
|
232
|
-
num_parts, num_points = @shp.read(8).unpack(
|
233
|
-
parts = @shp.read(num_parts * 4).unpack(
|
234
|
-
parts << num_points #indexes for LS of idx i go to parts of idx i to idx i +1
|
235
|
-
xys = Array.new(num_points) { @shp.read(16).unpack(
|
236
|
-
@shp.seek(16,IO::SEEK_CUR)
|
237
|
-
zs = Array.new(num_points) {@shp.read(8).unpack(
|
238
|
-
@shp.seek(16,IO::SEEK_CUR)
|
239
|
-
ms = Array.new(num_points) {@shp.read(8).unpack(
|
238
|
+
@shp.seek(32, IO::SEEK_CUR)
|
239
|
+
num_parts, num_points = @shp.read(8).unpack('V2')
|
240
|
+
parts = @shp.read(num_parts * 4).unpack('V' + num_parts.to_s)
|
241
|
+
parts << num_points # indexes for LS of idx i go to parts of idx i to idx i +1
|
242
|
+
xys = Array.new(num_points) { @shp.read(16).unpack('E2') }
|
243
|
+
@shp.seek(16, IO::SEEK_CUR)
|
244
|
+
zs = Array.new(num_points) { @shp.read(8).unpack('E')[0] }
|
245
|
+
@shp.seek(16, IO::SEEK_CUR)
|
246
|
+
ms = Array.new(num_points) { @shp.read(8).unpack('E')[0] }
|
240
247
|
points = Array.new(num_points) do |i|
|
241
|
-
GeoRuby::SimpleFeatures::Point.from_x_y_z_m(xys[i][0],xys[i][1],zs[i],ms[i])
|
248
|
+
GeoRuby::SimpleFeatures::Point.from_x_y_z_m(xys[i][0], xys[i][1], zs[i], ms[i])
|
242
249
|
end
|
243
250
|
line_strings = Array.new(num_parts) do |i|
|
244
|
-
GeoRuby::SimpleFeatures::LineString.from_points(points[(parts[i])...(parts[i+1])],GeoRuby::SimpleFeatures::DEFAULT_SRID,true,true)
|
251
|
+
GeoRuby::SimpleFeatures::LineString.from_points(points[(parts[i])...(parts[i + 1])], GeoRuby::SimpleFeatures::DEFAULT_SRID, true, true)
|
245
252
|
end
|
246
|
-
geometry = GeoRuby::SimpleFeatures::MultiLineString.from_line_strings(line_strings,GeoRuby::SimpleFeatures::DEFAULT_SRID,true,true)
|
247
|
-
|
253
|
+
geometry = GeoRuby::SimpleFeatures::MultiLineString.from_line_strings(line_strings, GeoRuby::SimpleFeatures::DEFAULT_SRID, true, true)
|
248
254
|
|
249
255
|
when ShpType::POLYGONZ
|
250
|
-
#TODO : CORRECT
|
251
|
-
|
252
|
-
@shp.seek(32,IO::SEEK_CUR)#extent
|
253
|
-
num_parts, num_points = @shp.read(8).unpack(
|
254
|
-
parts = @shp.read(num_parts * 4).unpack(
|
255
|
-
parts << num_points #indexes for LS of idx i go to parts of idx i to idx i +1
|
256
|
-
xys = Array.new(num_points) { @shp.read(16).unpack(
|
257
|
-
@shp.seek(16,IO::SEEK_CUR)#extent
|
258
|
-
zs = Array.new(num_points) {@shp.read(8).unpack(
|
259
|
-
@shp.seek(16,IO::SEEK_CUR)#extent
|
260
|
-
ms = Array.new(num_points) {@shp.read(8).unpack(
|
256
|
+
# TODO : CORRECT
|
257
|
+
|
258
|
+
@shp.seek(32, IO::SEEK_CUR) # extent
|
259
|
+
num_parts, num_points = @shp.read(8).unpack('V2')
|
260
|
+
parts = @shp.read(num_parts * 4).unpack('V' + num_parts.to_s)
|
261
|
+
parts << num_points # indexes for LS of idx i go to parts of idx i to idx i +1
|
262
|
+
xys = Array.new(num_points) { @shp.read(16).unpack('E2') }
|
263
|
+
@shp.seek(16, IO::SEEK_CUR) # extent
|
264
|
+
zs = Array.new(num_points) { @shp.read(8).unpack('E')[0] }
|
265
|
+
@shp.seek(16, IO::SEEK_CUR) # extent
|
266
|
+
ms = Array.new(num_points) { @shp.read(8).unpack('E')[0] }
|
261
267
|
points = Array.new(num_points) do |i|
|
262
|
-
GeoRuby::SimpleFeatures::Point.from_x_y_z_m(xys[i][0],xys[i][1],zs[i],ms[i])
|
268
|
+
GeoRuby::SimpleFeatures::Point.from_x_y_z_m(xys[i][0], xys[i][1], zs[i], ms[i])
|
263
269
|
end
|
264
270
|
linear_rings = Array.new(num_parts) do |i|
|
265
|
-
GeoRuby::SimpleFeatures::LinearRing.from_points(points[(parts[i])...(parts[i+1])],GeoRuby::SimpleFeatures::DEFAULT_SRID,true,true)
|
271
|
+
GeoRuby::SimpleFeatures::LinearRing.from_points(points[(parts[i])...(parts[i + 1])], GeoRuby::SimpleFeatures::DEFAULT_SRID, true, true)
|
266
272
|
end
|
267
|
-
geometry = GeoRuby::SimpleFeatures::MultiPolygon.from_polygons([GeoRuby::SimpleFeatures::Polygon.from_linear_rings(linear_rings)],GeoRuby::SimpleFeatures::DEFAULT_SRID,true,true)
|
268
|
-
|
273
|
+
geometry = GeoRuby::SimpleFeatures::MultiPolygon.from_polygons([GeoRuby::SimpleFeatures::Polygon.from_linear_rings(linear_rings)], GeoRuby::SimpleFeatures::DEFAULT_SRID, true, true)
|
269
274
|
|
270
275
|
when ShpType::MULTIPOINTZ
|
271
|
-
@shp.seek(32,IO::SEEK_CUR)
|
272
|
-
num_points = @shp.read(4).unpack(
|
273
|
-
xys = Array.new(num_points) { @shp.read(16).unpack(
|
274
|
-
@shp.seek(16,IO::SEEK_CUR)
|
275
|
-
zs = Array.new(num_points) {@shp.read(8).unpack(
|
276
|
-
@shp.seek(16,IO::SEEK_CUR)
|
277
|
-
ms = Array.new(num_points) {@shp.read(8).unpack(
|
276
|
+
@shp.seek(32, IO::SEEK_CUR)
|
277
|
+
num_points = @shp.read(4).unpack('V')[0]
|
278
|
+
xys = Array.new(num_points) { @shp.read(16).unpack('E2') }
|
279
|
+
@shp.seek(16, IO::SEEK_CUR)
|
280
|
+
zs = Array.new(num_points) { @shp.read(8).unpack('E')[0] }
|
281
|
+
@shp.seek(16, IO::SEEK_CUR)
|
282
|
+
ms = Array.new(num_points) { @shp.read(8).unpack('E')[0] }
|
278
283
|
|
279
284
|
points = Array.new(num_points) do |i|
|
280
|
-
GeoRuby::SimpleFeatures::Point.from_x_y_z_m(xys[i][0],xys[i][1],zs[i],ms[i])
|
285
|
+
GeoRuby::SimpleFeatures::Point.from_x_y_z_m(xys[i][0], xys[i][1], zs[i], ms[i])
|
281
286
|
end
|
282
287
|
|
283
|
-
geometry = GeoRuby::SimpleFeatures::MultiPoint.from_points(points,GeoRuby::SimpleFeatures::DEFAULT_SRID,true,true)
|
288
|
+
geometry = GeoRuby::SimpleFeatures::MultiPoint.from_points(points, GeoRuby::SimpleFeatures::DEFAULT_SRID, true, true)
|
284
289
|
|
285
290
|
when ShpType::POINTM
|
286
|
-
x, y, m = @shp.read(24).unpack(
|
287
|
-
geometry = GeoRuby::SimpleFeatures::Point.from_x_y_m(x,y,m)
|
291
|
+
x, y, m = @shp.read(24).unpack('E3')
|
292
|
+
geometry = GeoRuby::SimpleFeatures::Point.from_x_y_m(x, y, m)
|
288
293
|
|
289
294
|
when ShpType::POLYLINEM
|
290
|
-
@shp.seek(32,IO::SEEK_CUR)
|
291
|
-
num_parts, num_points = @shp.read(8).unpack(
|
292
|
-
parts = @shp.read(num_parts * 4).unpack(
|
293
|
-
parts << num_points #indexes for LS of idx i go to parts of idx i to idx i +1
|
294
|
-
xys = Array.new(num_points) { @shp.read(16).unpack(
|
295
|
-
@shp.seek(16,IO::SEEK_CUR)
|
296
|
-
ms = Array.new(num_points) {@shp.read(8).unpack(
|
295
|
+
@shp.seek(32, IO::SEEK_CUR)
|
296
|
+
num_parts, num_points = @shp.read(8).unpack('V2')
|
297
|
+
parts = @shp.read(num_parts * 4).unpack('V' + num_parts.to_s)
|
298
|
+
parts << num_points # indexes for LS of idx i go to parts of idx i to idx i +1
|
299
|
+
xys = Array.new(num_points) { @shp.read(16).unpack('E2') }
|
300
|
+
@shp.seek(16, IO::SEEK_CUR)
|
301
|
+
ms = Array.new(num_points) { @shp.read(8).unpack('E')[0] }
|
297
302
|
points = Array.new(num_points) do |i|
|
298
|
-
GeoRuby::SimpleFeatures::Point.from_x_y_m(xys[i][0],xys[i][1],ms[i])
|
303
|
+
GeoRuby::SimpleFeatures::Point.from_x_y_m(xys[i][0], xys[i][1], ms[i])
|
299
304
|
end
|
300
305
|
line_strings = Array.new(num_parts) do |i|
|
301
|
-
GeoRuby::SimpleFeatures::LineString.from_points(points[(parts[i])...(parts[i+1])],GeoRuby::SimpleFeatures::DEFAULT_SRID,false,true)
|
306
|
+
GeoRuby::SimpleFeatures::LineString.from_points(points[(parts[i])...(parts[i + 1])], GeoRuby::SimpleFeatures::DEFAULT_SRID, false, true)
|
302
307
|
end
|
303
|
-
geometry = GeoRuby::SimpleFeatures::MultiLineString.from_line_strings(line_strings,GeoRuby::SimpleFeatures::DEFAULT_SRID,false,true)
|
304
|
-
|
308
|
+
geometry = GeoRuby::SimpleFeatures::MultiLineString.from_line_strings(line_strings, GeoRuby::SimpleFeatures::DEFAULT_SRID, false, true)
|
305
309
|
|
306
310
|
when ShpType::POLYGONM
|
307
|
-
#TODO : CORRECT
|
308
|
-
|
309
|
-
@shp.seek(32,IO::SEEK_CUR)
|
310
|
-
num_parts, num_points = @shp.read(8).unpack(
|
311
|
-
parts = @shp.read(num_parts * 4).unpack(
|
312
|
-
parts << num_points #indexes for LS of idx i go to parts of idx i to idx i +1
|
313
|
-
xys = Array.new(num_points) { @shp.read(16).unpack(
|
314
|
-
@shp.seek(16,IO::SEEK_CUR)
|
315
|
-
ms = Array.new(num_points) {@shp.read(8).unpack(
|
311
|
+
# TODO : CORRECT
|
312
|
+
|
313
|
+
@shp.seek(32, IO::SEEK_CUR)
|
314
|
+
num_parts, num_points = @shp.read(8).unpack('V2')
|
315
|
+
parts = @shp.read(num_parts * 4).unpack('V' + num_parts.to_s)
|
316
|
+
parts << num_points # indexes for LS of idx i go to parts of idx i to idx i +1
|
317
|
+
xys = Array.new(num_points) { @shp.read(16).unpack('E2') }
|
318
|
+
@shp.seek(16, IO::SEEK_CUR)
|
319
|
+
ms = Array.new(num_points) { @shp.read(8).unpack('E')[0] }
|
316
320
|
points = Array.new(num_points) do |i|
|
317
|
-
GeoRuby::SimpleFeatures::Point.from_x_y_m(xys[i][0],xys[i][1],ms[i])
|
321
|
+
GeoRuby::SimpleFeatures::Point.from_x_y_m(xys[i][0], xys[i][1], ms[i])
|
318
322
|
end
|
319
323
|
linear_rings = Array.new(num_parts) do |i|
|
320
|
-
GeoRuby::SimpleFeatures::LinearRing.from_points(points[(parts[i])...(parts[i+1])],GeoRuby::SimpleFeatures::DEFAULT_SRID,false,true)
|
324
|
+
GeoRuby::SimpleFeatures::LinearRing.from_points(points[(parts[i])...(parts[i + 1])], GeoRuby::SimpleFeatures::DEFAULT_SRID, false, true)
|
321
325
|
end
|
322
|
-
geometry = GeoRuby::SimpleFeatures::MultiPolygon.from_polygons([GeoRuby::SimpleFeatures::Polygon.from_linear_rings(linear_rings)],GeoRuby::SimpleFeatures::DEFAULT_SRID,false,true)
|
323
|
-
|
326
|
+
geometry = GeoRuby::SimpleFeatures::MultiPolygon.from_polygons([GeoRuby::SimpleFeatures::Polygon.from_linear_rings(linear_rings)], GeoRuby::SimpleFeatures::DEFAULT_SRID, false, true)
|
324
327
|
|
325
328
|
when ShpType::MULTIPOINTM
|
326
|
-
@shp.seek(32,IO::SEEK_CUR)
|
327
|
-
num_points = @shp.read(4).unpack(
|
328
|
-
xys = Array.new(num_points) { @shp.read(16).unpack(
|
329
|
-
@shp.seek(16,IO::SEEK_CUR)
|
330
|
-
ms = Array.new(num_points) {@shp.read(8).unpack(
|
329
|
+
@shp.seek(32, IO::SEEK_CUR)
|
330
|
+
num_points = @shp.read(4).unpack('V')[0]
|
331
|
+
xys = Array.new(num_points) { @shp.read(16).unpack('E2') }
|
332
|
+
@shp.seek(16, IO::SEEK_CUR)
|
333
|
+
ms = Array.new(num_points) { @shp.read(8).unpack('E')[0] }
|
331
334
|
|
332
335
|
points = Array.new(num_points) do |i|
|
333
|
-
GeoRuby::SimpleFeatures::Point.from_x_y_m(xys[i][0],xys[i][1],ms[i])
|
336
|
+
GeoRuby::SimpleFeatures::Point.from_x_y_m(xys[i][0], xys[i][1], ms[i])
|
334
337
|
end
|
335
338
|
|
336
|
-
geometry = GeoRuby::SimpleFeatures::MultiPoint.from_points(points,GeoRuby::SimpleFeatures::DEFAULT_SRID,false,true)
|
339
|
+
geometry = GeoRuby::SimpleFeatures::MultiPoint.from_points(points, GeoRuby::SimpleFeatures::DEFAULT_SRID, false, true)
|
337
340
|
else
|
338
341
|
geometry = nil
|
339
342
|
end
|
340
343
|
|
341
|
-
ShpRecord.new(geometry,dbf_record)
|
344
|
+
ShpRecord.new(geometry, dbf_record)
|
342
345
|
end
|
343
346
|
end
|
344
347
|
|
345
|
-
#A SHP record : contains both the geometry and the data fields (from the DBF)
|
348
|
+
# A SHP record : contains both the geometry and the data fields (from the DBF)
|
346
349
|
class ShpRecord
|
347
|
-
attr_reader :geometry
|
350
|
+
attr_reader :geometry, :data
|
348
351
|
|
349
352
|
def initialize(geometry, data)
|
350
353
|
@geometry = geometry
|
351
354
|
@data = data
|
352
355
|
end
|
353
356
|
|
354
|
-
#Tests if the geometry is a NULL SHAPE
|
357
|
+
# Tests if the geometry is a NULL SHAPE
|
355
358
|
def has_null_shape?
|
356
359
|
@geometry.nil?
|
357
360
|
end
|
358
361
|
end
|
359
362
|
|
360
|
-
#An object returned from ShpFile#transaction. Buffers updates to a Shapefile
|
363
|
+
# An object returned from ShpFile#transaction. Buffers updates to a Shapefile
|
361
364
|
class ShpTransaction
|
362
365
|
attr_reader :rollbacked
|
363
366
|
|
364
367
|
def initialize(shp, dbf)
|
365
|
-
@deleted =
|
366
|
-
@added =
|
368
|
+
@deleted = {}
|
369
|
+
@added = []
|
367
370
|
@shp = shp
|
368
371
|
@dbf = dbf
|
369
372
|
end
|
370
373
|
|
371
|
-
#delete a record. Does not take into account the records added in the current transaction
|
374
|
+
# delete a record. Does not take into account the records added in the current transaction
|
372
375
|
def delete(i)
|
373
|
-
|
376
|
+
fail UnexistantRecordException.new("Invalid index : #{i}") if @shp.record_count <= i
|
374
377
|
@deleted[i] = true
|
375
378
|
end
|
376
379
|
|
377
|
-
#Update a record. In effect just a delete followed by an add.
|
380
|
+
# Update a record. In effect just a delete followed by an add.
|
378
381
|
def update(i, record)
|
379
382
|
delete(i)
|
380
383
|
add(record)
|
381
384
|
end
|
382
385
|
|
383
|
-
#add a ShpRecord at the end
|
386
|
+
# add a ShpRecord at the end
|
384
387
|
def add(record)
|
385
388
|
record_type = to_shp_type(record.geometry)
|
386
|
-
|
389
|
+
fail IncompatibleGeometryException.new('Incompatible type') unless record_type == @shp.shp_type
|
387
390
|
@added << record
|
388
391
|
end
|
389
392
|
|
390
|
-
#updates the physical files
|
393
|
+
# updates the physical files
|
391
394
|
def commit
|
392
395
|
@shp.close
|
393
|
-
@shp_r = open(@shp.file_root +
|
394
|
-
@dbf_r = open(@shp.file_root +
|
395
|
-
@shp_io = open(@shp.file_root +
|
396
|
-
@shx_io = open(@shp.file_root +
|
397
|
-
@dbf_io = open(@shp.file_root +
|
396
|
+
@shp_r = open(@shp.file_root + '.shp', 'rb')
|
397
|
+
@dbf_r = open(@shp.file_root + '.dbf', 'rb')
|
398
|
+
@shp_io = open(@shp.file_root + '.shp.tmp.shp', 'wb')
|
399
|
+
@shx_io = open(@shp.file_root + '.shx.tmp.shx', 'wb')
|
400
|
+
@dbf_io = open(@shp.file_root + '.dbf.tmp.dbf', 'wb')
|
398
401
|
index = commit_delete
|
399
|
-
min_x,max_x,min_y,max_y,min_z,max_z,min_m,max_m = commit_add(index)
|
400
|
-
commit_finalize(min_x,max_x,min_y,max_y,min_z,max_z,min_m,max_m)
|
402
|
+
min_x, max_x, min_y, max_y, min_z, max_z, min_m, max_m = commit_add(index)
|
403
|
+
commit_finalize(min_x, max_x, min_y, max_y, min_z, max_z, min_m, max_m)
|
401
404
|
@shp_r.close
|
402
405
|
@dbf_r.close
|
403
406
|
@dbf_io.close
|
404
407
|
@shp_io.close
|
405
408
|
@shx_io.close
|
406
|
-
FileUtils.move(@shp.file_root +
|
407
|
-
FileUtils.move(@shp.file_root +
|
408
|
-
FileUtils.move(@shp.file_root +
|
409
|
+
FileUtils.move(@shp.file_root + '.shp.tmp.shp', @shp.file_root + '.shp')
|
410
|
+
FileUtils.move(@shp.file_root + '.shx.tmp.shx', @shp.file_root + '.shx')
|
411
|
+
FileUtils.move(@shp.file_root + '.dbf.tmp.dbf', @shp.file_root + '.dbf')
|
409
412
|
|
410
|
-
@deleted =
|
411
|
-
@added =
|
413
|
+
@deleted = {}
|
414
|
+
@added = []
|
412
415
|
|
413
416
|
@shp.reload!
|
414
417
|
end
|
415
418
|
|
416
|
-
#prevents the udpate from taking place
|
419
|
+
# prevents the udpate from taking place
|
417
420
|
def rollback
|
418
|
-
@deleted =
|
419
|
-
@added =
|
421
|
+
@deleted = {}
|
422
|
+
@added = []
|
420
423
|
@rollbacked = true
|
421
424
|
end
|
422
425
|
|
@@ -424,47 +427,47 @@ module GeoRuby
|
|
424
427
|
|
425
428
|
def to_shp_type(geom)
|
426
429
|
root = if geom.is_a? GeoRuby::SimpleFeatures::Point
|
427
|
-
|
430
|
+
'POINT'
|
428
431
|
elsif geom.is_a? GeoRuby::SimpleFeatures::LineString
|
429
|
-
|
430
|
-
elsif geom.is_a?
|
431
|
-
|
432
|
-
elsif geom.is_a?
|
433
|
-
|
434
|
-
elsif geom.is_a?
|
435
|
-
|
436
|
-
elsif geom.is_a?
|
437
|
-
|
432
|
+
'POLYLINE'
|
433
|
+
elsif geom.is_a? GeoRuby::SimpleFeatures::Polygon
|
434
|
+
'POLYGON'
|
435
|
+
elsif geom.is_a? GeoRuby::SimpleFeatures::MultiPoint
|
436
|
+
'MULTIPOINT'
|
437
|
+
elsif geom.is_a? GeoRuby::SimpleFeatures::MultiLineString
|
438
|
+
'POLYLINE'
|
439
|
+
elsif geom.is_a? GeoRuby::SimpleFeatures::MultiPolygon
|
440
|
+
'POLYGON'
|
438
441
|
else
|
439
442
|
false
|
440
443
|
end
|
441
|
-
return false
|
444
|
+
return false unless root
|
442
445
|
|
443
446
|
if geom.with_z
|
444
|
-
root = root +
|
447
|
+
root = root + 'Z'
|
445
448
|
elsif geom.with_m
|
446
|
-
root = root +
|
449
|
+
root = root + 'M'
|
447
450
|
end
|
448
|
-
eval
|
451
|
+
eval 'ShpType::' + root
|
449
452
|
end
|
450
453
|
|
451
454
|
def commit_add(index)
|
452
|
-
max_x, min_x, max_y, min_y,max_z,min_z,max_m,min_m = @shp.xmax
|
455
|
+
max_x, min_x, max_y, min_y, max_z, min_z, max_m, min_m = @shp.xmax, @shp.xmin, @shp.ymax, @shp.ymin, @shp.zmax, @shp.zmin, @shp.mmax, @shp.mmin
|
453
456
|
@added.each do |record|
|
454
457
|
@dbf_io << ['20'].pack('H2')
|
455
458
|
@dbf.fields.each do |field|
|
456
459
|
data = record.data[field.name]
|
457
460
|
str = if field.type == 'D'
|
458
|
-
sprintf(
|
461
|
+
sprintf('%04i%02i%02i', data.year, data.month, data.mday)
|
459
462
|
elsif field.type == 'L'
|
460
|
-
data ?
|
463
|
+
data ? 'T' : 'F'
|
461
464
|
else
|
462
465
|
data.to_s
|
463
466
|
end
|
464
467
|
@dbf_io << [str].pack("A#{field.length}")
|
465
468
|
end
|
466
469
|
|
467
|
-
shp_str,min_xp,max_xp,min_yp,max_yp,min_zp,max_zp,min_mp,max_mp = build_shp_geometry(record.geometry)
|
470
|
+
shp_str, min_xp, max_xp, min_yp, max_yp, min_zp, max_zp, min_mp, max_mp = build_shp_geometry(record.geometry)
|
468
471
|
max_x = max_xp if max_xp > max_x
|
469
472
|
min_x = min_xp if min_xp < min_x
|
470
473
|
max_y = max_yp if max_yp > max_y
|
@@ -473,16 +476,16 @@ module GeoRuby
|
|
473
476
|
min_z = min_zp if min_zp < min_z
|
474
477
|
max_m = max_mp if max_mp > max_m
|
475
478
|
min_m = min_mp if min_mp < min_m
|
476
|
-
length = (shp_str.length/2 + 2).to_i #num of 16-bit words; geom type is included (+2)
|
477
|
-
@shx_io << [(@shp_io.pos/2).to_i,length].pack(
|
478
|
-
@shp_io << [index,length
|
479
|
+
length = (shp_str.length / 2 + 2).to_i # num of 16-bit words; geom type is included (+2)
|
480
|
+
@shx_io << [(@shp_io.pos / 2).to_i, length].pack('N2')
|
481
|
+
@shp_io << [index, length, @shp.shp_type].pack('N2V')
|
479
482
|
@shp_io << shp_str
|
480
483
|
index += 1
|
481
484
|
end
|
482
485
|
@shp_io.flush
|
483
486
|
@shx_io.flush
|
484
487
|
@dbf_io.flush
|
485
|
-
[min_x,max_x,min_y,max_y,min_z,max_z,min_m,max_m]
|
488
|
+
[min_x, max_x, min_y, max_y, min_z, max_z, min_m, max_m]
|
486
489
|
end
|
487
490
|
|
488
491
|
def commit_delete
|
@@ -491,15 +494,15 @@ module GeoRuby
|
|
491
494
|
@shp_io << header
|
492
495
|
@shx_io << header
|
493
496
|
index = 1
|
494
|
-
|
495
|
-
icur,length = @shp_r.read(8).unpack(
|
496
|
-
unless
|
497
|
-
@shx_io << [(@shp_io.pos/2).to_i,length].pack(
|
498
|
-
@shp_io << [index,length].pack(
|
497
|
+
until @shp_r.eof?
|
498
|
+
icur, length = @shp_r.read(8).unpack('N2')
|
499
|
+
unless @deleted[icur - 1]
|
500
|
+
@shx_io << [(@shp_io.pos / 2).to_i, length].pack('N2')
|
501
|
+
@shp_io << [index, length].pack('N2')
|
499
502
|
@shp_io << @shp_r.read(length * 2)
|
500
503
|
index += 1
|
501
504
|
else
|
502
|
-
@shp_r.seek(length * 2,IO::SEEK_CUR)
|
505
|
+
@shp_r.seek(length * 2, IO::SEEK_CUR)
|
503
506
|
end
|
504
507
|
end
|
505
508
|
@shp_io.flush
|
@@ -508,11 +511,11 @@ module GeoRuby
|
|
508
511
|
@dbf_r.rewind
|
509
512
|
@dbf_io << @dbf_r.read(@dbf.header_length)
|
510
513
|
icur = 0
|
511
|
-
|
512
|
-
unless
|
514
|
+
until @dbf_r.eof?
|
515
|
+
unless @deleted[icur]
|
513
516
|
@dbf_io << @dbf_r.read(@dbf.record_length)
|
514
517
|
else
|
515
|
-
@dbf_r.seek(@dbf.record_length,IO::SEEK_CUR)
|
518
|
+
@dbf_r.seek(@dbf.record_length, IO::SEEK_CUR)
|
516
519
|
end
|
517
520
|
icur += 1
|
518
521
|
end
|
@@ -520,24 +523,24 @@ module GeoRuby
|
|
520
523
|
index
|
521
524
|
end
|
522
525
|
|
523
|
-
def commit_finalize(min_x,max_x,min_y,max_y,min_z,max_z,min_m,max_m)
|
524
|
-
#update size in shp and dbf + extent and num records in dbf
|
525
|
-
@shp_io.seek(0,IO::SEEK_END)
|
526
|
+
def commit_finalize(min_x, max_x, min_y, max_y, min_z, max_z, min_m, max_m)
|
527
|
+
# update size in shp and dbf + extent and num records in dbf
|
528
|
+
@shp_io.seek(0, IO::SEEK_END)
|
526
529
|
shp_size = @shp_io.pos / 2
|
527
|
-
@shx_io.seek(0,IO::SEEK_END)
|
528
|
-
shx_size= @shx_io.pos / 2
|
530
|
+
@shx_io.seek(0, IO::SEEK_END)
|
531
|
+
shx_size = @shx_io.pos / 2
|
529
532
|
@shp_io.seek(24)
|
530
|
-
@shp_io.write([shp_size].pack(
|
533
|
+
@shp_io.write([shp_size].pack('N'))
|
531
534
|
@shx_io.seek(24)
|
532
|
-
@shx_io.write([shx_size].pack(
|
535
|
+
@shx_io.write([shx_size].pack('N'))
|
533
536
|
@shp_io.seek(36)
|
534
537
|
@shx_io.seek(36)
|
535
|
-
str = [min_x,min_y,max_x,max_y,min_z,max_z,min_m,max_m].pack(
|
538
|
+
str = [min_x, min_y, max_x, max_y, min_z, max_z, min_m, max_m].pack('E8')
|
536
539
|
@shp_io.write(str)
|
537
540
|
@shx_io.write(str)
|
538
541
|
|
539
542
|
@dbf_io.seek(4)
|
540
|
-
@dbf_io.write([@dbf.record_count + @added.length - @deleted.length].pack(
|
543
|
+
@dbf_io.write([@dbf.record_count + @added.length - @deleted.length].pack('V'))
|
541
544
|
end
|
542
545
|
|
543
546
|
def build_shp_geometry(geometry)
|
@@ -546,119 +549,129 @@ module GeoRuby
|
|
546
549
|
case @shp.shp_type
|
547
550
|
when ShpType::POINT
|
548
551
|
bbox = geometry.bounding_box
|
549
|
-
[geometry.x,geometry.y].pack(
|
552
|
+
[geometry.x, geometry.y].pack('E2')
|
550
553
|
when ShpType::POLYLINE
|
551
|
-
str,bbox = create_bbox(geometry)
|
552
|
-
build_polyline(geometry,str)
|
554
|
+
str, bbox = create_bbox(geometry)
|
555
|
+
build_polyline(geometry, str)
|
553
556
|
when ShpType::POLYGON
|
554
|
-
str,bbox = create_bbox(geometry)
|
555
|
-
build_polygon(geometry,str)
|
557
|
+
str, bbox = create_bbox(geometry)
|
558
|
+
build_polygon(geometry, str)
|
556
559
|
when ShpType::MULTIPOINT
|
557
|
-
str,bbox = create_bbox(geometry)
|
558
|
-
build_multi_point(geometry,str)
|
560
|
+
str, bbox = create_bbox(geometry)
|
561
|
+
build_multi_point(geometry, str)
|
559
562
|
when ShpType::POINTZ
|
560
563
|
bbox = geometry.bounding_box
|
561
|
-
[geometry.x,geometry.y,geometry.z,geometry.m].pack(
|
564
|
+
[geometry.x, geometry.y, geometry.z, geometry.m].pack('E4')
|
562
565
|
when ShpType::POLYLINEZ
|
563
|
-
str,bbox = create_bbox(geometry)
|
566
|
+
str, bbox = create_bbox(geometry)
|
564
567
|
m_range = geometry.m_range
|
565
|
-
build_polyline(geometry,str)
|
566
|
-
build_polyline_zm(geometry
|
567
|
-
build_polyline_zm(geometry
|
568
|
+
build_polyline(geometry, str)
|
569
|
+
build_polyline_zm(geometry, :@z, [bbox[0].z, bbox[1].z], str)
|
570
|
+
build_polyline_zm(geometry, :@m, m_range, str)
|
568
571
|
when ShpType::POLYGONZ
|
569
|
-
str,bbox = create_bbox(geometry)
|
572
|
+
str, bbox = create_bbox(geometry)
|
570
573
|
m_range = geometry.m_range
|
571
|
-
build_polygon(geometry,str)
|
572
|
-
build_polygon_zm(geometry
|
573
|
-
build_polygon_zm(geometry
|
574
|
+
build_polygon(geometry, str)
|
575
|
+
build_polygon_zm(geometry, :@z, [bbox[0].z, bbox[1].z], str)
|
576
|
+
build_polygon_zm(geometry, :@m, m_range, str)
|
574
577
|
when ShpType::MULTIPOINTZ
|
575
|
-
str,bbox = create_bbox(geometry)
|
578
|
+
str, bbox = create_bbox(geometry)
|
576
579
|
m_range = geometry.m_range
|
577
|
-
build_multi_point(geometry,str)
|
578
|
-
build_multi_point_zm(geometry
|
579
|
-
build_multi_point_zm(geometry
|
580
|
+
build_multi_point(geometry, str)
|
581
|
+
build_multi_point_zm(geometry, :@z, [bbox[0].z, bbox[1].z], str)
|
582
|
+
build_multi_point_zm(geometry, :@m, m_range, str)
|
580
583
|
when ShpType::POINTM
|
581
584
|
bbox = geometry.bounding_box
|
582
|
-
[geometry.x,geometry.y,geometry.m].pack(
|
585
|
+
[geometry.x, geometry.y, geometry.m].pack('E3')
|
583
586
|
when ShpType::POLYLINEM
|
584
|
-
str,bbox = create_bbox(geometry)
|
587
|
+
str, bbox = create_bbox(geometry)
|
585
588
|
m_range = geometry.m_range
|
586
|
-
build_polyline(geometry,str)
|
587
|
-
build_polyline_zm(geometry
|
589
|
+
build_polyline(geometry, str)
|
590
|
+
build_polyline_zm(geometry, :@m, m_range, str)
|
588
591
|
when ShpType::POLYGONM
|
589
|
-
str,bbox = create_bbox(geometry)
|
592
|
+
str, bbox = create_bbox(geometry)
|
590
593
|
m_range = geometry.m_range
|
591
|
-
build_polygon(geometry,str)
|
592
|
-
build_polygon_zm(geometry
|
594
|
+
build_polygon(geometry, str)
|
595
|
+
build_polygon_zm(geometry, :@m, m_range, str)
|
593
596
|
when ShpType::MULTIPOINTM
|
594
|
-
str,bbox = create_bbox(geometry)
|
597
|
+
str, bbox = create_bbox(geometry)
|
595
598
|
m_range = geometry.m_range
|
596
|
-
build_multi_point(geometry,str)
|
597
|
-
build_multi_point_zm(geometry
|
599
|
+
build_multi_point(geometry, str)
|
600
|
+
build_multi_point_zm(geometry, :@m, m_range, str)
|
598
601
|
end
|
599
|
-
m_range ||= [0,0]
|
600
|
-
[answer,bbox[0].x,bbox[1].x,bbox[0].y,bbox[1].y,bbox[0].z || 0, bbox[1].z || 0, m_range[0], m_range[1]]
|
602
|
+
m_range ||= [0, 0]
|
603
|
+
[answer, bbox[0].x, bbox[1].x, bbox[0].y, bbox[1].y, bbox[0].z || 0, bbox[1].z || 0, m_range[0], m_range[1]]
|
601
604
|
end
|
602
605
|
|
603
606
|
def create_bbox(geometry)
|
604
607
|
bbox = geometry.bounding_box
|
605
|
-
[[bbox[0].x,bbox[0].y,bbox[1].x,bbox[1].y].pack(
|
608
|
+
[[bbox[0].x, bbox[0].y, bbox[1].x, bbox[1].y].pack('E4'), bbox]
|
606
609
|
end
|
607
610
|
|
608
|
-
def build_polyline(geometry,str)
|
611
|
+
def build_polyline(geometry, str)
|
609
612
|
if geometry.is_a? GeoRuby::SimpleFeatures::LineString
|
610
|
-
str << [1,geometry.length,0].pack(
|
613
|
+
str << [1, geometry.length, 0].pack('V3')
|
611
614
|
geometry.each do |point|
|
612
|
-
|
615
|
+
str << [point.x, point.y].pack('E2')
|
613
616
|
end
|
614
617
|
else
|
615
|
-
#multilinestring
|
616
|
-
str << [geometry.length,geometry.
|
617
|
-
str << geometry.
|
618
|
+
# multilinestring
|
619
|
+
str << [geometry.length, geometry.reduce(0) { |a, e| a + e.length }].pack('V2')
|
620
|
+
str << geometry.reduce([0]) do |a, e|
|
621
|
+
a << (a.last + e.length) # last element of the previous array is dropped
|
622
|
+
end.pack("V#{geometry.length}")
|
618
623
|
geometry.each do |ls|
|
619
624
|
ls.each do |point|
|
620
|
-
str << [point.x,point.y].pack(
|
625
|
+
str << [point.x, point.y].pack('E2')
|
621
626
|
end
|
622
627
|
end
|
623
628
|
end
|
624
629
|
str
|
625
630
|
end
|
626
631
|
|
627
|
-
def build_polyline_zm(geometry,zm,range,str)
|
628
|
-
str << range.pack(
|
632
|
+
def build_polyline_zm(geometry, zm, range, str)
|
633
|
+
str << range.pack('E2')
|
629
634
|
if geometry.is_a? GeoRuby::SimpleFeatures::LineString
|
630
635
|
geometry.each do |point|
|
631
|
-
str << [point.instance_variable_get(zm)].pack(
|
636
|
+
str << [point.instance_variable_get(zm)].pack('E')
|
632
637
|
end
|
633
638
|
else
|
634
|
-
#multilinestring
|
639
|
+
# multilinestring
|
635
640
|
geometry.each do |ls|
|
636
641
|
ls.each do |point|
|
637
|
-
str << [point.instance_variable_get(zm)].pack(
|
642
|
+
str << [point.instance_variable_get(zm)].pack('E')
|
638
643
|
end
|
639
644
|
end
|
640
645
|
end
|
641
646
|
str
|
642
647
|
end
|
643
648
|
|
644
|
-
def build_polygon(geometry,str)
|
649
|
+
def build_polygon(geometry, str)
|
645
650
|
if geometry.is_a? GeoRuby::SimpleFeatures::Polygon
|
646
|
-
str << [geometry.length,
|
647
|
-
|
651
|
+
str << [geometry.length,
|
652
|
+
geometry.reduce(0) { |a, e| a + e.length }
|
653
|
+
].pack('V2')
|
654
|
+
# last element of the previous array is dropped
|
655
|
+
str << geometry.reduce([0]) do |a, e|
|
656
|
+
a << (a.last + e.length)
|
657
|
+
end.pack("V#{geometry.length}")
|
648
658
|
geometry.each do |lr|
|
649
659
|
lr.each do |point|
|
650
|
-
str << [point.x,point.y].pack(
|
660
|
+
str << [point.x, point.y].pack('E2')
|
651
661
|
end
|
652
662
|
end
|
653
663
|
else
|
654
|
-
#multipolygon
|
655
|
-
num_rings = geometry.
|
656
|
-
str << [num_rings, geometry.
|
657
|
-
|
664
|
+
# multipolygon
|
665
|
+
num_rings = geometry.reduce(0) { |a, e| a + e.length }
|
666
|
+
str << [num_rings, geometry.reduce(0) { |l, poly| l + poly.reduce(0) { |l2, lr| l2 + lr.length } }].pack('V2')
|
667
|
+
# last element of the previous array is dropped
|
668
|
+
str << geometry.reduce([0]) do |a, e|
|
669
|
+
e.reduce(a) { |a2, lr| a2 << (a2.last + lr.length) }
|
670
|
+
end.pack("V#{num_rings}")
|
658
671
|
geometry.each do |poly|
|
659
672
|
poly.each do |lr|
|
660
673
|
lr.each do |point|
|
661
|
-
str << [point.x,point.y].pack(
|
674
|
+
str << [point.x, point.y].pack('E2')
|
662
675
|
end
|
663
676
|
end
|
664
677
|
end
|
@@ -666,19 +679,19 @@ module GeoRuby
|
|
666
679
|
str
|
667
680
|
end
|
668
681
|
|
669
|
-
def build_polygon_zm(geometry,zm,range,str)
|
670
|
-
str << range.pack(
|
682
|
+
def build_polygon_zm(geometry, zm, range, str)
|
683
|
+
str << range.pack('E2')
|
671
684
|
if geometry.is_a? GeoRuby::SimpleFeatures::Polygon
|
672
685
|
geometry.each do |lr|
|
673
686
|
lr.each do |point|
|
674
|
-
str << [point.instance_variable_get(zm)].pack(
|
687
|
+
str << [point.instance_variable_get(zm)].pack('E')
|
675
688
|
end
|
676
689
|
end
|
677
690
|
else
|
678
691
|
geometry.each do |poly|
|
679
692
|
poly.each do |lr|
|
680
693
|
lr.each do |point|
|
681
|
-
str << [point.instance_variable_get(zm)].pack(
|
694
|
+
str << [point.instance_variable_get(zm)].pack('E')
|
682
695
|
end
|
683
696
|
end
|
684
697
|
end
|
@@ -686,18 +699,18 @@ module GeoRuby
|
|
686
699
|
str
|
687
700
|
end
|
688
701
|
|
689
|
-
def build_multi_point(geometry,str)
|
690
|
-
str << [geometry.length].pack(
|
702
|
+
def build_multi_point(geometry, str)
|
703
|
+
str << [geometry.length].pack('V')
|
691
704
|
geometry.each do |point|
|
692
|
-
str << [point.x,point.y].pack(
|
705
|
+
str << [point.x, point.y].pack('E2')
|
693
706
|
end
|
694
707
|
str
|
695
708
|
end
|
696
709
|
|
697
|
-
def build_multi_point_zm(geometry,zm,range,str)
|
698
|
-
str << range.pack(
|
710
|
+
def build_multi_point_zm(geometry, zm, range, str)
|
711
|
+
str << range.pack('E2')
|
699
712
|
geometry.each do |point|
|
700
|
-
str << [point.instance_variable_get(zm)].pack(
|
713
|
+
str << [point.instance_variable_get(zm)].pack('E')
|
701
714
|
end
|
702
715
|
str
|
703
716
|
end
|