citysdk 0.1.2.5 → 1.0

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.
@@ -7,12 +7,11 @@ require 'tmpdir'
7
7
 
8
8
  module CitySDK
9
9
 
10
-
11
10
  class FileReader
12
11
 
13
- RE_Y = /lat|(y.*coord)|(y.*loc(atie|ation)?)/i
14
- RE_X = /lon|lng|(x.*coord)|(x.*loc(atie|ation)?)/i
15
- RE_GEO = /^geom(etry)?|location|locatie$/i
12
+ RE_Y = /lat|(y.*coord)|(y.*pos.*)|(y.*loc(atie|ation)?)/i
13
+ RE_X = /lon|lng|(x.*coord)|(x.*pos.*)|(x.*loc(atie|ation)?)/i
14
+ RE_GEO = /^(geom(etry)?|location|locatie|coords|coordinates)$/i
16
15
  RE_NAME = /(title|titel|naam|name)/i
17
16
  RE_A_NAME = /^(naam|name|title|titel)$/i
18
17
 
@@ -41,68 +40,74 @@ module CitySDK
41
40
  end
42
41
  end
43
42
 
44
-
45
43
  @params[:rowcount] = @content.length
46
44
  getFields unless @params[:fields]
47
45
  guessName unless @params[:name]
48
46
  guessSRID unless @params[:srid]
49
47
  findUniqueField unless @params[:unique_id]
50
48
  getAddress unless @params[:hasaddress]
51
- @params[:hasgeometry] = 'unknown' if @params[:hasgeometry].nil?
49
+ setId_Name
52
50
  end
53
51
 
54
52
  def getAddress
55
53
  pd = pc = hn = ad = false
54
+ @params[:housenumber] = nil
55
+ @params[:hasaddress] = 'unknown'
56
+ @params[:postcode] = nil
56
57
  @params[:fields].reverse.each do |f|
57
- pd = f if ( f.to_s =~ /postcode|post/i )
58
58
  pc = f if ( f.to_s =~ /^(post|zip|postal)code$/i )
59
59
  hn = f if ( f.to_s =~ /huisnummer|housenumber|(house|huis)(nr|no)|number/i)
60
60
  ad = f if ( f.to_s =~ /address|street|straat|adres/i)
61
61
  end
62
- @params[:hasaddress] = 'unknown'
63
- if (ad or hn)
64
- if pc
65
- @params[:hasaddress] = 'certain'
66
- @params[:postcode] = pc
67
- elsif pd
68
- @params[:hasaddress] = 'maybe'
69
- @params[:postcode] = pd
70
- end
71
- @params[:housenumber] = hn ? hn : ad
62
+ if pc and (ad or hn)
63
+ @params[:hasaddress] = 'certain'
72
64
  end
73
- end
74
-
65
+ @params[:postcode] = pc
66
+ @params[:housenumber] = hn ? hn : ad
75
67
 
68
+ end
76
69
 
70
+ def setId_Name
71
+ count = 123456
72
+ if @params[:unique_id]
73
+ @content.each do |h|
74
+ h[:properties][:id] = h[:properties][:data][@params[:unique_id]]
75
+ h[:properties][:title] = h[:properties][:data][@params[:name]] if @params[:name]
76
+ end
77
+ else
78
+ @params[:unique_id] = :csdk_gen
79
+ # @params[:fields] << :csdk_gen
80
+ # @params[:original_fields] << :csdk_gen
81
+ # @params[:alternate_fields][:csdk_gen] = :csdk_gen
82
+ @content.each do |h|
83
+ h[:properties][:id] = "cg_#{count}"
84
+ h[:properties][:title] = h[:properties][:data][@params[:name]] if @params[:name]
85
+ count += 1
86
+ end
87
+ end
88
+ end
89
+
77
90
  def findUniqueField
78
91
  fields = {}
79
- unfield = nil
80
-
81
- return if @content[0][:id]
82
-
92
+ @params[:unique_id] = nil
83
93
  @content.each do |h|
84
- h[:properties].each do |k,v|
85
- fields[k] = {} if fields[k].nil?
86
- (fields[k][v] == nil) ? fields[k][v] = 1 : fields[k][v] += 1
94
+ h[:properties][:data].each do |k,v|
95
+ fields[k] = Hash.new(0) if fields[k].nil?
96
+ fields[k][v] += 1
87
97
  end
88
98
  end
89
99
 
90
100
  fields.each_key do |k|
91
101
  if fields[k].length == @params[:rowcount]
92
- @params[:unique_id] = unfield = k
102
+ @params[:unique_id] = k
93
103
  break
94
104
  end
95
105
  end
96
-
97
- if unfield
98
- @content.each do |h|
99
- h[:id] = h[:properties][unfield]
100
- end
101
- end
102
-
106
+
103
107
  end
104
108
 
105
109
  def guessName
110
+ @params[:name] = nil
106
111
  @params[:fields].reverse.each do |k|
107
112
  if(k.to_s =~ RE_A_NAME)
108
113
  @params[:name] = k
@@ -116,13 +121,18 @@ module CitySDK
116
121
 
117
122
  def getFields
118
123
  @params[:fields] = []
119
- @content[0][:properties].each_key do |k|
120
- @params[:fields] << (k.to_sym rescue k) || k
124
+ @params[:original_fields] = []
125
+ @params[:alternate_fields] = {}
126
+ @content[0][:properties][:data].each_key do |k|
127
+ k = (k.to_sym rescue k) || k
128
+ @params[:fields] << k
129
+ @params[:original_fields] << k
130
+ @params[:alternate_fields][k] = k
121
131
  end
122
132
  end
123
133
 
124
134
  def guessSRID
125
- return if @content[0][:geometry].nil?
135
+ return unless @content[0][:geometry] and @content[0][:geometry].class == Hash
126
136
  @params[:srid] = 4326
127
137
  g = @content[0][:geometry][:coordinates]
128
138
  if(g)
@@ -133,11 +143,13 @@ module CitySDK
133
143
  lat = g[1]
134
144
  # if lon > -180.0 and lon < 180.0 and lat > -90.0 and lat < 90.0
135
145
  # @params[:srid] = 4326
136
- # els
137
- if lon > -7000.0 and lon < 300000.0 and lat > 289000.0 and lat < 629000.0
146
+ # else
147
+ if lon.between?(-7000.0,300000.0) and lat.between?(289000.0,629000.0)
138
148
  # Dutch new rd system
139
149
  @params[:srid] = 28992
140
150
  end
151
+ else
152
+
141
153
  end
142
154
  end
143
155
 
@@ -157,18 +169,36 @@ module CitySDK
157
169
  p.parse(s)
158
170
  g = f.geometry
159
171
  return g.srid,g.as_json[:type],g
160
- rescue Exception=>e
172
+ rescue => e
173
+ end
174
+ nil
175
+ end
176
+
177
+ def isWktGeometry(s)
178
+ begin
179
+ f = GeoRuby::SimpleFeatures::GeometryFactory::new
180
+ p = GeoRuby::SimpleFeatures::EWKTParser.new(f)
181
+ p.parse(s)
182
+ g = f.geometry
183
+ return g.srid,g.as_json[:type],g
184
+ rescue => e
161
185
  end
162
186
  nil
163
187
  end
164
188
 
189
+ GEOMETRIES = ["point", "multipoint", "linestring", "multilinestring", "polygon", "multipolygon"]
165
190
  def isGeoJSON(s)
191
+ return nil if s.class != Hash
166
192
  begin
167
- if ['Point', 'MultiPoint', 'LineString', 'MultiLineString', 'Polygon', 'MultiPolygon', 'GeometryCollection'].include?(s[:type])
193
+ if GEOMETRIES.include?(s[:type].downcase)
168
194
  srid = 4326
169
- if s[:crs] && s[:crs][:type] == 'OGC'
170
- urn = s[:crs][:properties][:urn].split(':')
171
- srid = urn.last.to_i if (urn[4] == 'EPSG')
195
+ if s[:crs] and s[:crs][:properties]
196
+ if s[:crs][:type] == 'OGC'
197
+ urn = s[:crs][:properties][:urn].split(':')
198
+ srid = urn.last.to_i if (urn[4] == 'EPSG')
199
+ elsif s[:crs][:type] == 'EPSG'
200
+ srid = s[:crs][:properties][:code]
201
+ end
172
202
  end
173
203
  return srid,s[:type],s
174
204
  end
@@ -176,98 +206,151 @@ module CitySDK
176
206
  end
177
207
  nil
178
208
  end
209
+
210
+ def geomFromText(coords)
211
+ # begin
212
+ # a = factory.parse_wkt(coords)
213
+ # rescue
214
+ # end
215
+
216
+ if coords =~ /^(\w+)(.+)/
217
+ if GEOMETRIES.include?($1.downcase)
218
+ type = $1.capitalize
219
+ coor = $2.gsub('(','[').gsub(')',']')
220
+ coor = coor.gsub(/([-+]?[0-9]*\.?[0-9]+)\s+([-+]?[0-9]*\.?[0-9]+)/) { "[#{$1},#{$2}]" }
221
+ coor = JSON.parse(coor)
222
+ return { :type => type,
223
+ :coordinates => coor }
224
+ end
225
+ end
226
+ {}
227
+ end
179
228
 
180
-
181
- def findGeometry
182
- xfield = nil; xs = true
183
- yfield = nil; ys = true
184
- @content[0][:properties].each do |k,v|
185
- next if k.nil?
186
- if k.to_s =~ RE_GEO
187
- srid,g_type = isWkbGeometry(v)
188
- if(srid)
189
- @params[:srid] = srid
190
- @params[:geomtry_type] = g_type
191
- @content.each do |h|
192
- a,b,g = isWkbGeometry(h[:properties][k])
193
- h[:geometry] = g
194
- h[:properties].delete(k)
229
+ def findGeometry(xfield=nil, yfield=nil)
230
+ unless(xfield and yfield)
231
+ @params[:hasgeometry] = nil
232
+ xs = true
233
+ ys = true
234
+
235
+ @content[0][:properties][:data].each do |k,v|
236
+ next if k.nil?
237
+
238
+ if k.to_s =~ RE_GEO
239
+
240
+ srid,g_type = isWkbGeometry(v)
241
+ if(srid)
242
+ @params[:srid] = srid
243
+ @params[:geomtry_type] = g_type
244
+ @content.each do |h|
245
+ a,b,g = isWkbGeometry(h[:properties][:data][k])
246
+ h[:geometry] = g
247
+ h[:properties][:data].delete(k)
248
+ end
249
+ @params[:hasgeometry] = k
250
+ return true
195
251
  end
196
- @params[:hasgeometry] = 'certain'
197
- return true
198
- end
199
-
200
- srid,g_type = isGeoJSON(v)
201
- if(srid)
202
- @params[:srid] = srid
203
- @params[:geomtry_type] = g_type
204
- @content.each do |h|
205
- h[:geometry] = h[:properties][k]
206
- h[:properties].delete(k)
252
+
253
+
254
+ srid,g_type = isWktGeometry(v)
255
+ if(srid)
256
+ @params[:srid] = srid
257
+ @params[:geomtry_type] = g_type
258
+ @content.each do |h|
259
+ a,b,g = isWktGeometry(h[:properties][:data][k])
260
+ h[:geometry] = g
261
+ h[:properties][:data].delete(k)
262
+ end
263
+ @params[:hasgeometry] = k
264
+ return true
207
265
  end
208
- @params[:hasgeometry] = 'certain'
209
- return true
266
+
267
+ srid,g_type = isGeoJSON(v)
268
+ if(srid)
269
+ @params[:srid] = srid
270
+ @params[:geomtry_type] = g_type
271
+ @content.each do |h|
272
+ h[:geometry] = h[:properties][:data][k]
273
+ h[:properties].delete(k)
274
+ end
275
+ @params[:hasgeometry] = k
276
+ return true
277
+ end
278
+
210
279
  end
211
280
 
212
- @content.each do |h|
213
- h[:geometry] = h[:properties][k]
214
- h[:properties].delete(k)
281
+ hdc = k.to_s.downcase
282
+ if hdc == 'longitude' or hdc == 'lon' or hdc == 'x'
283
+ xfield=k; xs=false
215
284
  end
216
- @params[:hasgeometry] = 'maybe'
217
- return
218
- end
219
-
220
- hdc = k.to_sym.downcase
221
- if hdc == 'longitude' or hdc == 'lon'
222
- xfield=k; xs=false
223
- end
224
- if hdc == 'latitude' or hdc == 'lat'
225
- yfield=k; ys=false
285
+ if hdc == 'latitude' or hdc == 'lat' or hdc == 'y'
286
+ yfield=k; ys=false
287
+ end
288
+ xfield = k if xs and (hdc =~ RE_X)
289
+ yfield = k if ys and (hdc =~ RE_Y)
226
290
  end
227
- xfield = k if xs and (hdc =~ RE_X)
228
- yfield = k if ys and (hdc =~ RE_Y)
229
291
  end
230
292
 
231
293
  if xfield and yfield and (xfield != yfield)
232
- @params[:hasgeometry] = 'certain'
294
+ @params[:hasgeometry] = [xfield,yfield].to_s
233
295
  @content.each do |h|
234
- h[:geometry] = {:type => 'Point', :coordinates => [h[:properties][xfield].gsub(',','.').to_f, h[:properties][yfield].gsub(',','.').to_f]}
235
- h[:properties].delete(yfield)
236
- h[:properties].delete(xfield)
296
+ h[:geometry] = {:type => 'Point', :coordinates => [h[:properties][:data][xfield].gsub(',','.').to_f, h[:properties][:data][yfield].gsub(',','.').to_f]}
297
+ h[:properties][:data].delete(yfield)
298
+ h[:properties][:data].delete(xfield)
237
299
  end
238
300
  @params[:geomtry_type] = 'Point'
301
+ @params[:fields].delete(xfield) if @params[:fields]
302
+ @params[:fields].delete(yfield) if @params[:fields]
303
+ return true
304
+ elsif (xfield and yfield)
305
+ # factory = ::RGeo::Cartesian.preferred_factory()
306
+ @params[:hasgeometry] = "[#{xfield}]"
307
+ @content.each do |h|
308
+ h[:geometry] = geomFromText(h[:properties][:data][xfield])
309
+ h[:properties][:data].delete(xfield) if h[:geometry]
310
+ end
311
+ @params[:geomtry_type] = ''
312
+ @params[:fields].delete(xfield) if @params[:fields]
239
313
  return true
240
314
  end
315
+
316
+
241
317
  false
242
318
  end
243
319
 
244
-
245
320
  def readCsv(path)
246
321
  @file = path
247
322
  c=''
248
323
  File.open(path, "r:bom|utf-8") do |fd|
249
324
  c = fd.read
250
325
  end
251
- if true != @params[:utf8_fixed]
326
+ unless @params[:utf8_fixed]
252
327
  detect = CharlockHolmes::EncodingDetector.detect(c)
253
328
  c = CharlockHolmes::Converter.convert(c, detect[:encoding], 'UTF-8') if detect
254
329
  end
255
330
  c = c.force_encoding('utf-8')
331
+ c = c.gsub(/\r\n?/, "\n")
256
332
  @content = []
257
- @params[:colsep] = findColSep(StringIO.new(c))
333
+ @params[:colsep] = findColSep(StringIO.new(c)) unless @params[:colsep]
258
334
  csv = CSV.new(c, :col_sep => @params[:colsep], :headers => true, :skip_blanks =>true)
259
- csv.each do |row|
260
- r = row.to_hash
261
- h = {}
262
- r.each do |k,v|
263
- h[(k.to_sym rescue k) || k] = v
335
+ csv.header_convert { |h| h.blank? ? '_' : h.strip.gsub(/\s+/,'_') }
336
+ csv.convert { |h| h ? h.strip : '' }
337
+ index = 0
338
+ begin
339
+ csv.each do |row|
340
+ r = row.to_hash
341
+ h = {}
342
+ r.each do |k,v|
343
+ h[(k.to_sym rescue k) || k] = v
344
+ end
345
+ @content << {properties: {data: h} }
346
+ index += 1
264
347
  end
265
- @content << {:properties => h }
348
+ rescue => e
349
+ raise CitySDK::Exception.new("Read CSV; line #{index}; #{e.message}")
266
350
  end
267
351
  findGeometry
268
352
  end
269
353
 
270
-
271
354
  def readJSON(path)
272
355
  @content = []
273
356
  @file = path
@@ -278,20 +361,23 @@ module CitySDK
278
361
  hash = CitySDK::parseJson(raw)
279
362
 
280
363
  if hash.is_a?(Hash) and hash[:type] and (hash[:type] == 'FeatureCollection')
364
+ # GeoJSON
281
365
  hash[:features].each do |f|
282
366
  f.delete(:type)
367
+ f[:properties] = {data: f[:properties]}
283
368
  @content << f
284
369
  end
285
- @params[:hasgeometry] = 'certain'
286
- findUniqueField if @content[0][:id].nil?
370
+ @params[:hasgeometry] = 'GeoJSON'
287
371
  else
372
+ # Free-form JSON
288
373
  val,length = nil,0
289
-
290
374
  if hash.is_a?(Array)
375
+ # one big array
291
376
  val,length = hash,hash.length
292
377
  else
293
378
  hash.each do |k,v|
294
379
  if v.is_a?(Array)
380
+ # the longest array value in the Object
295
381
  val,length = v,v.length if v.length > length
296
382
  end
297
383
  end
@@ -299,19 +385,18 @@ module CitySDK
299
385
 
300
386
  if val
301
387
  val.each do |h|
302
- @content << {:properties => h}
388
+ @content << { :properties => {:data => h} }
303
389
  end
304
390
  end
305
391
  findGeometry
306
392
  end
307
393
  end
308
394
 
309
-
310
395
  def sridFromPrj(str)
311
396
  begin
312
397
  connection = Faraday.new :url => "http://prj2epsg.org"
313
398
  resp = connection.get('/search.json', {:mode => 'wkt', :terms => str})
314
- if resp.status == 200
399
+ if resp.status.between?(200, 299)
315
400
  resp = CitySDK::parseJson resp.body
316
401
  @params[:srid] = resp[:codes][0][:code].to_i
317
402
  end
@@ -328,19 +413,19 @@ module CitySDK
328
413
  prj = File.exists?(prj) ? File.read(prj) : nil
329
414
  sridFromPrj(prj) if (prj and @params[:srid].nil?)
330
415
 
331
- @params[:hasgeometry] = 'certain'
416
+ @params[:hasgeometry] = 'ESRI Shape'
332
417
 
333
418
 
334
419
  GeoRuby::Shp4r::ShpFile.open(path) do |shp|
335
420
  shp.each do |shape|
336
421
  h = {}
337
422
  h[:geometry] = CitySDK::parseJson(shape.geometry.to_json) #a GeoRuby SimpleFeature
338
- h[:properties] = {}
423
+ h[:properties] = {:data => {}}
339
424
  att_data = shape.data #a Hash
340
425
  shp.fields.each do |field|
341
426
  s = att_data[field.name]
342
427
  s = s.force_encoding('ISO8859-1') if s.class == String
343
- h[:properties][field.name.to_sym] = s
428
+ h[:properties][:data][field.name.to_sym] = s
344
429
  end
345
430
  @content << h
346
431
  end
@@ -398,13 +483,3 @@ module CitySDK
398
483
 
399
484
  end
400
485
 
401
-
402
-
403
- # {
404
- # :headers => ['aap','noot','titel', 'gid', 'geometry']
405
- # :config => {:geom => 'geometry', :name => 'titel', :id => 'gid', :srid => 28892}
406
- # :data => [
407
- # ['jpo','pipo','naam1','1092',{:type => 'Point', :coordinates => [5.3, 52.4]}],
408
- # ['jpa','popi','naam2','1093',{:type => 'Point', :coordinates => [5.1, 52.1]}]
409
- # ]
410
- # }