georuby 2.3.0 → 2.5.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|