nofxx-georuby 1.3.7
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.
- data/History.txt +4 -0
- data/LICENSE +21 -0
- data/README.txt +59 -0
- data/Rakefile +49 -0
- data/VERSION.yml +4 -0
- data/lib/geo_ruby.rb +21 -0
- data/lib/geo_ruby/base/envelope.rb +167 -0
- data/lib/geo_ruby/base/ewkb_parser.rb +216 -0
- data/lib/geo_ruby/base/ewkt_parser.rb +336 -0
- data/lib/geo_ruby/base/geometry.rb +234 -0
- data/lib/geo_ruby/base/geometry_collection.rb +136 -0
- data/lib/geo_ruby/base/geometry_factory.rb +81 -0
- data/lib/geo_ruby/base/georss_parser.rb +135 -0
- data/lib/geo_ruby/base/helper.rb +18 -0
- data/lib/geo_ruby/base/line_string.rb +184 -0
- data/lib/geo_ruby/base/linear_ring.rb +12 -0
- data/lib/geo_ruby/base/multi_line_string.rb +39 -0
- data/lib/geo_ruby/base/multi_point.rb +41 -0
- data/lib/geo_ruby/base/multi_polygon.rb +37 -0
- data/lib/geo_ruby/base/point.rb +310 -0
- data/lib/geo_ruby/base/polygon.rb +150 -0
- data/lib/geo_ruby/shp4r/dbf.rb +180 -0
- data/lib/geo_ruby/shp4r/shp.rb +701 -0
- data/spec/data/multipoint.dbf +0 -0
- data/spec/data/multipoint.shp +0 -0
- data/spec/data/multipoint.shx +0 -0
- data/spec/data/point.dbf +0 -0
- data/spec/data/point.shp +0 -0
- data/spec/data/point.shx +0 -0
- data/spec/data/polygon.dbf +0 -0
- data/spec/data/polygon.shp +0 -0
- data/spec/data/polygon.shx +0 -0
- data/spec/data/polyline.dbf +0 -0
- data/spec/data/polyline.shp +0 -0
- data/spec/data/polyline.shx +0 -0
- data/spec/geo_ruby/base/envelope_spec.rb +45 -0
- data/spec/geo_ruby/base/ewkb_parser_spec.rb +158 -0
- data/spec/geo_ruby/base/ewkt_parser_spec.rb +179 -0
- data/spec/geo_ruby/base/geometry_collection_spec.rb +55 -0
- data/spec/geo_ruby/base/geometry_factory_spec.rb +11 -0
- data/spec/geo_ruby/base/geometry_spec.rb +32 -0
- data/spec/geo_ruby/base/georss_parser_spec.rb +218 -0
- data/spec/geo_ruby/base/line_string_spec.rb +208 -0
- data/spec/geo_ruby/base/linear_ring_spec.rb +14 -0
- data/spec/geo_ruby/base/multi_line_string_spec.rb +35 -0
- data/spec/geo_ruby/base/multi_point_spec.rb +29 -0
- data/spec/geo_ruby/base/multi_polygon_spec.rb +35 -0
- data/spec/geo_ruby/base/point_spec.rb +275 -0
- data/spec/geo_ruby/base/polygon_spec.rb +108 -0
- data/spec/geo_ruby/shp4r/shp_spec.rb +238 -0
- data/spec/geo_ruby_spec.rb +27 -0
- data/spec/spec.opts +6 -0
- data/spec/spec_helper.rb +12 -0
- metadata +123 -0
@@ -0,0 +1,336 @@
|
|
1
|
+
require 'geo_ruby/base/point'
|
2
|
+
require 'geo_ruby/base/line_string'
|
3
|
+
require 'geo_ruby/base/linear_ring'
|
4
|
+
require 'geo_ruby/base/polygon'
|
5
|
+
require 'geo_ruby/base/multi_point'
|
6
|
+
require 'geo_ruby/base/multi_line_string'
|
7
|
+
require 'geo_ruby/base/multi_polygon'
|
8
|
+
require 'geo_ruby/base/geometry_collection'
|
9
|
+
|
10
|
+
require 'strscan'
|
11
|
+
|
12
|
+
module GeoRuby
|
13
|
+
module Base
|
14
|
+
|
15
|
+
#Raised when an error in the EWKT string is detected
|
16
|
+
class EWKTFormatError < StandardError
|
17
|
+
end
|
18
|
+
|
19
|
+
#Parses EWKT strings and notifies of events (such as the beginning of the definition of geometry, the value of the SRID...) the factory passed as argument to the constructor.
|
20
|
+
#
|
21
|
+
#=Example
|
22
|
+
# factory = GeometryFactory::new
|
23
|
+
# ewkt_parser = EWKTParser::new(factory)
|
24
|
+
# ewkt_parser.parse(<EWKT String>)
|
25
|
+
# geometry = @factory.geometry
|
26
|
+
#
|
27
|
+
#You can also use directly the static method Geometry.from_ewkt
|
28
|
+
class EWKTParser
|
29
|
+
|
30
|
+
def initialize(factory)
|
31
|
+
@factory = factory
|
32
|
+
@parse_options ={
|
33
|
+
"POINT" => method(:parse_point),
|
34
|
+
"LINESTRING" => method(:parse_line_string),
|
35
|
+
"POLYGON" => method(:parse_polygon),
|
36
|
+
"MULTIPOINT" => method(:parse_multi_point),
|
37
|
+
"MULTILINESTRING" => method(:parse_multi_line_string),
|
38
|
+
"MULTIPOLYGON" => method(:parse_multi_polygon),
|
39
|
+
"GEOMETRYCOLLECTION" => method(:parse_geometry_collection)
|
40
|
+
}
|
41
|
+
end
|
42
|
+
|
43
|
+
#Parses the ewkt string passed as argument and notifies the factory of events
|
44
|
+
def parse(ewkt)
|
45
|
+
@factory.reset
|
46
|
+
@tokenizer_structure = TokenizerStructure.new(ewkt)
|
47
|
+
@with_z=false
|
48
|
+
@with_m=false
|
49
|
+
@is_3dm = false
|
50
|
+
parse_geometry(true)
|
51
|
+
@srid=nil
|
52
|
+
end
|
53
|
+
|
54
|
+
private
|
55
|
+
def parse_geometry(srid_allowed)
|
56
|
+
|
57
|
+
token = @tokenizer_structure.get_next_token
|
58
|
+
if token == 'SRID'
|
59
|
+
#SRID present
|
60
|
+
raise EWKTFormatError.new("SRID not allowed at this position") if(!srid_allowed)
|
61
|
+
if @tokenizer_structure.get_next_token != '='
|
62
|
+
raise EWKTFormatError.new("Invalid SRID expression")
|
63
|
+
else
|
64
|
+
@srid = @tokenizer_structure.get_next_token.to_i
|
65
|
+
raise EWKTFormatError.new("Invalid SRID separator") if @tokenizer_structure.get_next_token != ';'
|
66
|
+
geom_type = @tokenizer_structure.get_next_token
|
67
|
+
end
|
68
|
+
|
69
|
+
else
|
70
|
+
#to manage multi geometries : the srid is not present in sub_geometries, therefore we take the srid of the parent ; if it is the root, we take the default srid
|
71
|
+
@srid= @srid || @@default_srid
|
72
|
+
geom_type = token
|
73
|
+
end
|
74
|
+
|
75
|
+
if geom_type[-1] == ?M
|
76
|
+
@is_3dm=true
|
77
|
+
@with_m=true
|
78
|
+
geom_type.chop! #remove the M
|
79
|
+
end
|
80
|
+
|
81
|
+
if @parse_options.has_key?(geom_type)
|
82
|
+
@parse_options[geom_type].call
|
83
|
+
else
|
84
|
+
raise EWKTFormatError.new("Urecognized geometry type: #{geom_type}")
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
def parse_geometry_collection
|
89
|
+
if @tokenizer_structure.get_next_token !='('
|
90
|
+
raise EWKTFormatError.new('Invalid GeometryCollection')
|
91
|
+
end
|
92
|
+
|
93
|
+
@factory.begin_geometry(GeometryCollection,@srid)
|
94
|
+
|
95
|
+
token = ''
|
96
|
+
while token != ')'
|
97
|
+
parse_geometry(false)
|
98
|
+
token = @tokenizer_structure.get_next_token
|
99
|
+
if token.nil?
|
100
|
+
raise EWKTFormatError.new("EWKT string not correctly terminated")
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
@factory.end_geometry(@with_z,@with_m)
|
105
|
+
end
|
106
|
+
|
107
|
+
def parse_multi_polygon
|
108
|
+
if @tokenizer_structure.get_next_token !='('
|
109
|
+
raise EWKTFormatError.new('Invalid MultiLineString')
|
110
|
+
end
|
111
|
+
|
112
|
+
@factory.begin_geometry(MultiPolygon,@srid)
|
113
|
+
token = ''
|
114
|
+
while token != ')'
|
115
|
+
parse_polygon
|
116
|
+
token = @tokenizer_structure.get_next_token
|
117
|
+
if token.nil?
|
118
|
+
raise EWKTFormatError.new("EWKT string not correctly terminated")
|
119
|
+
end
|
120
|
+
end
|
121
|
+
|
122
|
+
@factory.end_geometry(@with_z,@with_m)
|
123
|
+
end
|
124
|
+
|
125
|
+
def parse_multi_line_string
|
126
|
+
if @tokenizer_structure.get_next_token !='('
|
127
|
+
raise EWKTFormatError.new('Invalid MultiLineString')
|
128
|
+
end
|
129
|
+
|
130
|
+
@factory.begin_geometry(MultiLineString,@srid)
|
131
|
+
|
132
|
+
token = ''
|
133
|
+
while token != ')'
|
134
|
+
parse_line_string
|
135
|
+
token = @tokenizer_structure.get_next_token
|
136
|
+
if token.nil?
|
137
|
+
raise EWKTFormatError.new("EWKT string not correctly terminated")
|
138
|
+
end
|
139
|
+
end
|
140
|
+
|
141
|
+
@factory.end_geometry(@with_z,@with_m)
|
142
|
+
end
|
143
|
+
|
144
|
+
def parse_polygon
|
145
|
+
if @tokenizer_structure.get_next_token !='('
|
146
|
+
raise EWKTFormatError.new('Invalid Polygon')
|
147
|
+
end
|
148
|
+
|
149
|
+
@factory.begin_geometry(Polygon,@srid)
|
150
|
+
|
151
|
+
token = ''
|
152
|
+
while token != ')'
|
153
|
+
parse_linear_ring
|
154
|
+
token = @tokenizer_structure.get_next_token
|
155
|
+
if token.nil?
|
156
|
+
raise EWKTFormatError.new("EWKT string not correctly terminated")
|
157
|
+
end
|
158
|
+
end
|
159
|
+
|
160
|
+
@factory.end_geometry(@with_z,@with_m)
|
161
|
+
end
|
162
|
+
|
163
|
+
#must support the PostGIS form and the one in the specification
|
164
|
+
def parse_multi_point
|
165
|
+
if @tokenizer_structure.get_next_token !='('
|
166
|
+
raise EWKTFormatError.new('Invalid MultiPoint')
|
167
|
+
end
|
168
|
+
|
169
|
+
token = @tokenizer_structure.check_next_token
|
170
|
+
if token == '('
|
171
|
+
#specification
|
172
|
+
@factory.begin_geometry(MultiPoint,@srid)
|
173
|
+
|
174
|
+
token = ''
|
175
|
+
while token != ')'
|
176
|
+
parse_point
|
177
|
+
token = @tokenizer_structure.get_next_token
|
178
|
+
if token.nil?
|
179
|
+
raise EWKTFormatError.new("EWKT string not correctly terminated")
|
180
|
+
end
|
181
|
+
end
|
182
|
+
|
183
|
+
@factory.end_geometry(@with_z,@with_m)
|
184
|
+
else
|
185
|
+
#postgis
|
186
|
+
parse_point_list(MultiPoint)
|
187
|
+
end
|
188
|
+
end
|
189
|
+
|
190
|
+
def parse_linear_ring
|
191
|
+
if @tokenizer_structure.get_next_token !='('
|
192
|
+
raise EWKTFormatError.new('Invalid Linear ring')
|
193
|
+
end
|
194
|
+
|
195
|
+
parse_point_list(LinearRing)
|
196
|
+
end
|
197
|
+
|
198
|
+
def parse_line_string
|
199
|
+
if @tokenizer_structure.get_next_token !='('
|
200
|
+
raise EWKTFormatError.new('Invalid Line string')
|
201
|
+
end
|
202
|
+
|
203
|
+
parse_point_list(LineString)
|
204
|
+
end
|
205
|
+
|
206
|
+
#used to parse line_strings and linear_rings and the PostGIS form of multi_points
|
207
|
+
def parse_point_list(geometry_type)
|
208
|
+
@factory.begin_geometry(geometry_type,@srid)
|
209
|
+
|
210
|
+
token = ''
|
211
|
+
while token != ')'
|
212
|
+
@factory.begin_geometry(Point,@srid)
|
213
|
+
token = parse_coords
|
214
|
+
if token.nil?
|
215
|
+
raise EWKTFormatError.new("EWKT string not correctly terminated")
|
216
|
+
end
|
217
|
+
@factory.end_geometry(@with_z,@with_m)
|
218
|
+
end
|
219
|
+
|
220
|
+
@factory.end_geometry(@with_z,@with_m)
|
221
|
+
end
|
222
|
+
|
223
|
+
def parse_point
|
224
|
+
if @tokenizer_structure.get_next_token !='('
|
225
|
+
raise EWKTFormatError.new('Invalid Point')
|
226
|
+
end
|
227
|
+
|
228
|
+
@factory.begin_geometry(Point,@srid)
|
229
|
+
|
230
|
+
token = parse_coords
|
231
|
+
|
232
|
+
if token != ')'
|
233
|
+
raise EWKTFormatError.new("EWKT string not correctly terminated")
|
234
|
+
end
|
235
|
+
|
236
|
+
@factory.end_geometry(@with_z,@with_m)
|
237
|
+
end
|
238
|
+
|
239
|
+
def parse_coords
|
240
|
+
coords = Array.new
|
241
|
+
x = @tokenizer_structure.get_next_token
|
242
|
+
y = @tokenizer_structure.get_next_token
|
243
|
+
|
244
|
+
if x.nil? or y.nil?
|
245
|
+
raise EWKTFormatError.new("Bad Point format")
|
246
|
+
end
|
247
|
+
|
248
|
+
if @is_3dm
|
249
|
+
m = @tokenizer_structure.get_next_token
|
250
|
+
|
251
|
+
if m.nil? or m == ',' or m == ')'
|
252
|
+
raise EWKTFormatError.new("No M dimension found")
|
253
|
+
else
|
254
|
+
@factory.add_point_x_y_m(x.to_f,y.to_f,m.to_f)
|
255
|
+
@tokenizer_structure.get_next_token
|
256
|
+
end
|
257
|
+
else
|
258
|
+
z = @tokenizer_structure.get_next_token
|
259
|
+
|
260
|
+
if z.nil?
|
261
|
+
raise EWKTFormatError.new("EWKT string not correctly terminated")
|
262
|
+
end
|
263
|
+
|
264
|
+
if z == ',' or z == ')'
|
265
|
+
#2D : no z no m
|
266
|
+
@factory.add_point_x_y(x.to_f,y.to_f)
|
267
|
+
z
|
268
|
+
else
|
269
|
+
m = @tokenizer_structure.get_next_token
|
270
|
+
if m.nil?
|
271
|
+
raise EWKTFormatError.new("EWKT string not correctly terminated")
|
272
|
+
end
|
273
|
+
|
274
|
+
if m == ',' or m ==')'
|
275
|
+
#3Dz : no m
|
276
|
+
@with_z = true
|
277
|
+
@factory.add_point_x_y_z(x.to_f,y.to_f,z.to_f)
|
278
|
+
m
|
279
|
+
else
|
280
|
+
#4D
|
281
|
+
@with_z = true
|
282
|
+
@with_m = true
|
283
|
+
@factory.add_point_x_y_z_m(x.to_f,y.to_f,z.to_f,m.to_f)
|
284
|
+
@tokenizer_structure.get_next_token
|
285
|
+
end
|
286
|
+
end
|
287
|
+
end
|
288
|
+
end
|
289
|
+
end
|
290
|
+
|
291
|
+
class TokenizerStructure
|
292
|
+
|
293
|
+
def initialize(ewkt)
|
294
|
+
@ewkt = ewkt
|
295
|
+
@scanner = StringScanner.new(ewkt)
|
296
|
+
@regex = /\s*([\w.-]+)s*/
|
297
|
+
end
|
298
|
+
|
299
|
+
def get_next_token
|
300
|
+
if @scanner.scan(@regex).nil?
|
301
|
+
if @scanner.eos?
|
302
|
+
nil
|
303
|
+
else
|
304
|
+
ch = @scanner.getch
|
305
|
+
while ch == ' '
|
306
|
+
ch = @scanner.getch
|
307
|
+
end
|
308
|
+
ch
|
309
|
+
end
|
310
|
+
else
|
311
|
+
@scanner[1]
|
312
|
+
end
|
313
|
+
end
|
314
|
+
|
315
|
+
|
316
|
+
def check_next_token
|
317
|
+
check = @scanner.check(@regex)
|
318
|
+
if check.nil?
|
319
|
+
if @scanner.eos?
|
320
|
+
nil
|
321
|
+
else
|
322
|
+
pos = @scanner.pos
|
323
|
+
while @ewkt[pos].chr == ' '
|
324
|
+
pos+=1
|
325
|
+
end
|
326
|
+
@ewkt[pos].chr
|
327
|
+
end
|
328
|
+
else
|
329
|
+
check
|
330
|
+
end
|
331
|
+
end
|
332
|
+
|
333
|
+
end
|
334
|
+
|
335
|
+
end
|
336
|
+
end
|
@@ -0,0 +1,234 @@
|
|
1
|
+
module GeoRuby#:nodoc:
|
2
|
+
module Base
|
3
|
+
#arbitrary default SRID
|
4
|
+
@@default_srid = 4326
|
5
|
+
|
6
|
+
def self.default_srid
|
7
|
+
@@default_srid
|
8
|
+
end
|
9
|
+
def self.srid=(srid)
|
10
|
+
@@default_srid = srid
|
11
|
+
end
|
12
|
+
|
13
|
+
#Root of all geometric data classes.
|
14
|
+
#Objects of class Geometry should not be instantiated.
|
15
|
+
class Geometry
|
16
|
+
#SRID of the geometry
|
17
|
+
attr_reader :srid #writer defined below
|
18
|
+
#Flag indicating if the z ordinate of the geometry is meaningful
|
19
|
+
attr_accessor :with_z
|
20
|
+
alias :with_z? :with_z
|
21
|
+
#Flag indicating if the m ordinate of the geometry is meaningful
|
22
|
+
attr_accessor :with_m
|
23
|
+
alias :with_m? :with_m
|
24
|
+
|
25
|
+
def initialize(srid=@@default_srid,with_z=false,with_m=false)
|
26
|
+
@srid=srid
|
27
|
+
@with_z=with_z
|
28
|
+
@with_m=with_m
|
29
|
+
end
|
30
|
+
|
31
|
+
def srid=(new_srid)
|
32
|
+
@srid = new_srid
|
33
|
+
unless self.is_a?(Point)
|
34
|
+
self.each do |geom|
|
35
|
+
geom.srid=new_srid
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
#to be implemented in subclasses
|
41
|
+
def bounding_box
|
42
|
+
end
|
43
|
+
|
44
|
+
#to be implemented in subclasses
|
45
|
+
def m_range
|
46
|
+
end
|
47
|
+
|
48
|
+
#Returns an Envelope object for the geometry
|
49
|
+
def envelope
|
50
|
+
Envelope.from_points(bounding_box,srid,with_z)
|
51
|
+
end
|
52
|
+
|
53
|
+
#Outputs the geometry as an EWKB string.
|
54
|
+
#The +allow_srid+, +allow_z+ and +allow_m+ arguments allow the output to include srid, z and m respectively if they are present in the geometry. If these arguments are set to false, srid, z and m are not included, even if they are present in the geometry. By default, the output string contains all the information in the object.
|
55
|
+
def as_ewkb(allow_srid=true,allow_z=true,allow_m=true)
|
56
|
+
ewkb="";
|
57
|
+
|
58
|
+
ewkb << 1.chr #little_endian by default
|
59
|
+
|
60
|
+
type= binary_geometry_type
|
61
|
+
if @with_z and allow_z
|
62
|
+
type = type | Z_MASK
|
63
|
+
end
|
64
|
+
if @with_m and allow_m
|
65
|
+
type = type | M_MASK
|
66
|
+
end
|
67
|
+
if allow_srid
|
68
|
+
type = type | SRID_MASK
|
69
|
+
ewkb << [type,@srid].pack("VV")
|
70
|
+
else
|
71
|
+
ewkb << [type].pack("V")
|
72
|
+
end
|
73
|
+
|
74
|
+
ewkb << binary_representation(allow_z,allow_m)
|
75
|
+
end
|
76
|
+
|
77
|
+
#Outputs the geometry as a strict WKB string.
|
78
|
+
def as_wkb
|
79
|
+
as_ewkb(false,false,false)
|
80
|
+
end
|
81
|
+
|
82
|
+
#Outputs the geometry as a HexEWKB string. It is almost the same as a WKB string, except that each byte of a WKB string is replaced by its hexadecimal 2-character representation in a HexEWKB string.
|
83
|
+
def as_hex_ewkb(allow_srid=true,allow_z=true,allow_m=true)
|
84
|
+
as_ewkb(allow_srid, allow_z, allow_m).unpack('H*').join('').upcase
|
85
|
+
end
|
86
|
+
|
87
|
+
#Outputs the geometry as a strict HexWKB string
|
88
|
+
def as_hex_wkb
|
89
|
+
as_hex_ewkb(false,false,false)
|
90
|
+
end
|
91
|
+
|
92
|
+
#Outputs the geometry as an EWKT string.
|
93
|
+
def as_ewkt(allow_srid=true,allow_z=true,allow_m=true)
|
94
|
+
if allow_srid
|
95
|
+
ewkt="SRID=#{@srid};"
|
96
|
+
else
|
97
|
+
ewkt=""
|
98
|
+
end
|
99
|
+
ewkt << text_geometry_type
|
100
|
+
ewkt << "M" if @with_m and allow_m and (!@with_z or !allow_z) #to distinguish the M from the Z when there is actually no Z...
|
101
|
+
ewkt << "(" << text_representation(allow_z,allow_m) << ")"
|
102
|
+
end
|
103
|
+
|
104
|
+
#Outputs the geometry as strict WKT string.
|
105
|
+
def as_wkt
|
106
|
+
as_ewkt(false,false,false)
|
107
|
+
end
|
108
|
+
|
109
|
+
#Outputs the geometry in georss format.
|
110
|
+
#Assumes the geometries are in latlon format, with x as lon and y as lat.
|
111
|
+
#Pass the <tt>:dialect</tt> option to swhit format. Possible values are: <tt>:simple</tt> (default), <tt>:w3cgeo</tt> and <tt>:gml</tt>.
|
112
|
+
def as_georss(options = {})
|
113
|
+
dialect= options[:dialect] || :simple
|
114
|
+
case(dialect)
|
115
|
+
when :simple
|
116
|
+
geom_attr = ""
|
117
|
+
geom_attr += " featuretypetag=\"#{options[:featuretypetag]}\"" if options[:featuretypetag]
|
118
|
+
geom_attr += " relationshiptag=\"#{options[:relationshiptag]}\"" if options[:relationshiptag]
|
119
|
+
geom_attr += " floor=\"#{options[:floor]}\"" if options[:floor]
|
120
|
+
geom_attr += " radius=\"#{options[:radius]}\"" if options[:radius]
|
121
|
+
geom_attr += " elev=\"#{options[:elev]}\"" if options[:elev]
|
122
|
+
georss_simple_representation(options.merge(:geom_attr => geom_attr))
|
123
|
+
when :w3cgeo
|
124
|
+
georss_w3cgeo_representation(options)
|
125
|
+
when :gml
|
126
|
+
georss_gml_representation(options)
|
127
|
+
end
|
128
|
+
end
|
129
|
+
|
130
|
+
#Iutputs the geometry in kml format : options are <tt>:id</tt>, <tt>:tesselate</tt>, <tt>:extrude</tt>,
|
131
|
+
#<tt>:altitude_mode</tt>. If the altitude_mode option is not present, the Z (if present) will not be output (since
|
132
|
+
#it won't be used by GE anyway: clampToGround is the default)
|
133
|
+
def as_kml(options = {})
|
134
|
+
id_attr = ""
|
135
|
+
id_attr = " id=\"#{options[:id]}\"" if options[:id]
|
136
|
+
|
137
|
+
geom_data = ""
|
138
|
+
geom_data += "<extrude>#{options[:extrude]}</extrude>\n" if options[:extrude]
|
139
|
+
geom_data += "<tesselate>#{options[:tesselate]}</tesselate>\n" if options[:tesselate]
|
140
|
+
geom_data += "<altitudeMode>#{options[:altitude_mode]}</altitudeMode>\n" if options[:altitude_mode]
|
141
|
+
|
142
|
+
allow_z = (with_z || !options[:altitude].nil? )&& (!options[:altitude_mode].nil?) && options[:atitude_mode] != "clampToGround"
|
143
|
+
fixed_z = options[:altitude]
|
144
|
+
|
145
|
+
kml_representation(options.merge(:id_attr => id_attr, :geom_data => geom_data, :allow_z => allow_z, :fixed_z => fixed_z))
|
146
|
+
end
|
147
|
+
|
148
|
+
#Creates a geometry based on a EWKB string. The actual class returned depends of the content of the string passed as argument. Since WKB strings are a subset of EWKB, they are also valid.
|
149
|
+
def self.from_ewkb(ewkb)
|
150
|
+
factory = GeometryFactory::new
|
151
|
+
ewkb_parser= EWKBParser::new(factory)
|
152
|
+
ewkb_parser.parse(ewkb)
|
153
|
+
factory.geometry
|
154
|
+
end
|
155
|
+
#Creates a geometry based on a HexEWKB string
|
156
|
+
def self.from_hex_ewkb(hexewkb)
|
157
|
+
factory = GeometryFactory::new
|
158
|
+
hexewkb_parser= HexEWKBParser::new(factory)
|
159
|
+
hexewkb_parser.parse(hexewkb)
|
160
|
+
factory.geometry
|
161
|
+
end
|
162
|
+
#Creates a geometry based on a EWKT string. Since WKT strings are a subset of EWKT, they are also valid.
|
163
|
+
def self.from_ewkt(ewkt)
|
164
|
+
factory = GeometryFactory::new
|
165
|
+
ewkt_parser= EWKTParser::new(factory)
|
166
|
+
ewkt_parser.parse(ewkt)
|
167
|
+
factory.geometry
|
168
|
+
end
|
169
|
+
|
170
|
+
#sends back a geometry based on the GeoRSS string passed as argument
|
171
|
+
def self.from_georss(georss)
|
172
|
+
georss_parser= GeorssParser::new
|
173
|
+
georss_parser.parse(georss)
|
174
|
+
georss_parser.geometry
|
175
|
+
end
|
176
|
+
#sends back an array: The first element is the goemetry based on the GeoRSS string passed as argument. The second one is the GeoRSSTags (found only with the Simple format)
|
177
|
+
def self.from_georss_with_tags(georss)
|
178
|
+
georss_parser= GeorssParser::new
|
179
|
+
georss_parser.parse(georss,true)
|
180
|
+
[georss_parser.geometry, georss_parser.georss_tags]
|
181
|
+
end
|
182
|
+
|
183
|
+
#Sends back a geometry from a KML encoded geometry string.
|
184
|
+
#Limitations : Only supports points, linestrings and polygons (no collection for now).
|
185
|
+
#Addapted from Pramukta's code
|
186
|
+
def self.from_kml(kml)
|
187
|
+
return GeoRuby::Base::Geometry.from_ewkt(kml_to_wkt(kml))
|
188
|
+
end
|
189
|
+
|
190
|
+
require 'rexml/document'
|
191
|
+
def self.kml_to_wkt(kml)
|
192
|
+
doc = REXML::Document.new(kml)
|
193
|
+
wkt = ""
|
194
|
+
if ["Point", "LineString", "Polygon" ].include?(doc.root.name)
|
195
|
+
case doc.root.name
|
196
|
+
when "Point" then
|
197
|
+
coords = doc.elements["/Point/coordinates"].text.gsub(/\n/," ")
|
198
|
+
wkt = doc.root.name.upcase + "(" + split_coords(coords).join(' ') + ")"
|
199
|
+
when "LineString" then
|
200
|
+
coords = doc.elements["/LineString/coordinates"].text.gsub(/\n/," ")
|
201
|
+
coords = split_coords(coords)
|
202
|
+
wkt = doc.root.name.upcase + "(" + coords.join(",") + ")"
|
203
|
+
when "Polygon" then
|
204
|
+
# polygons have one outer ring and zero or more inner rings
|
205
|
+
bounds = []
|
206
|
+
bounds << doc.elements["/Polygon/outerBoundaryIs/LinearRing/coordinates"].text
|
207
|
+
inner_coords_elements = doc.elements.each("/Polygon/innerBoundaryIs/LinearRing/coordinates") do |inner_coords|
|
208
|
+
inner_coords = inner_coords.text
|
209
|
+
bounds << inner_coords
|
210
|
+
end
|
211
|
+
|
212
|
+
wkt = doc.root.name.upcase + "(" + bounds.map do |bound|
|
213
|
+
bound.gsub!(/\n/, " ")
|
214
|
+
bound = split_coords(bound)
|
215
|
+
if bound.first != bound.last
|
216
|
+
bound.push bound.first
|
217
|
+
end
|
218
|
+
"(" + bound.join(",") + ")"
|
219
|
+
end.join(",") + ")"
|
220
|
+
end
|
221
|
+
end
|
222
|
+
return wkt
|
223
|
+
end
|
224
|
+
|
225
|
+
private
|
226
|
+
|
227
|
+
def self.split_coords(coords)
|
228
|
+
coords.split(" ").collect { |coord|
|
229
|
+
coord.gsub(","," ")
|
230
|
+
}
|
231
|
+
end
|
232
|
+
end
|
233
|
+
end
|
234
|
+
end
|