columbus3 0.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.
Files changed (49) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +9 -0
  3. data/.travis.yml +4 -0
  4. data/Gemfile +4 -0
  5. data/LICENSE.txt +21 -0
  6. data/README.md +41 -0
  7. data/Rakefile +10 -0
  8. data/bin/console +14 -0
  9. data/bin/setup +7 -0
  10. data/bower_components/leaflet/.bower.json +34 -0
  11. data/bower_components/leaflet/CHANGELOG.md +929 -0
  12. data/bower_components/leaflet/CONTRIBUTING.md +155 -0
  13. data/bower_components/leaflet/Jakefile.js +48 -0
  14. data/bower_components/leaflet/LICENSE +23 -0
  15. data/bower_components/leaflet/PLUGIN-GUIDE.md +127 -0
  16. data/bower_components/leaflet/README.md +34 -0
  17. data/bower_components/leaflet/bower.json +24 -0
  18. data/bower_components/leaflet/component.json +20 -0
  19. data/bower_components/leaflet/dist/images/layers-2x.png +0 -0
  20. data/bower_components/leaflet/dist/images/layers.png +0 -0
  21. data/bower_components/leaflet/dist/images/marker-icon-2x.png +0 -0
  22. data/bower_components/leaflet/dist/images/marker-icon.png +0 -0
  23. data/bower_components/leaflet/dist/images/marker-shadow.png +0 -0
  24. data/bower_components/leaflet/dist/leaflet-src.js +9180 -0
  25. data/bower_components/leaflet/dist/leaflet.css +478 -0
  26. data/bower_components/leaflet/dist/leaflet.js +9 -0
  27. data/bower_components/leaflet/package.json +33 -0
  28. data/bower_components/leaflet-providers/.bower.json +35 -0
  29. data/bower_components/leaflet-providers/CONTRIBUTING.md +10 -0
  30. data/bower_components/leaflet-providers/README.md +54 -0
  31. data/bower_components/leaflet-providers/bower.json +25 -0
  32. data/bower_components/leaflet-providers/css/gh-fork-ribbon.css +127 -0
  33. data/bower_components/leaflet-providers/css/gh-fork-ribbon.ie.css +68 -0
  34. data/bower_components/leaflet-providers/leaflet-providers.js +630 -0
  35. data/bower_components/leaflet-providers/license.md +9 -0
  36. data/bower_components/leaflet-providers/package.json +38 -0
  37. data/columbus3.gemspec +28 -0
  38. data/exe/columbus3 +144 -0
  39. data/lib/columbus3/metadata/query_parser.racc +160 -0
  40. data/lib/columbus3/metadata/query_parser.tab.rb +349 -0
  41. data/lib/columbus3/metadata/sidecar.rb +48 -0
  42. data/lib/columbus3/renderer/renderer.rb +73 -0
  43. data/lib/columbus3/v900track/v900track.rb +157 -0
  44. data/lib/columbus3/v900track/v900waypoint.rb +51 -0
  45. data/lib/columbus3/version.rb +3 -0
  46. data/lib/columbus3.rb +6 -0
  47. data/lib/html/show.html.erb +84 -0
  48. data/lib/html/track.js.erb +15 -0
  49. metadata +164 -0
@@ -0,0 +1,349 @@
1
+ #
2
+ # DO NOT MODIFY!!!!
3
+ # This file is automatically generated by Racc 1.4.12
4
+ # from Racc grammer file "".
5
+ #
6
+
7
+ require 'racc/parser.rb'
8
+
9
+ require 'date'
10
+ class QueryParser < Racc::Parser
11
+
12
+ module_eval(<<'...end query_parser.racc/module_eval...', 'query_parser.racc', 86)
13
+ attr_accessor :result
14
+
15
+ def parse(str)
16
+ @tokens = make_tokens str
17
+ do_parse
18
+ end
19
+
20
+ def next_token
21
+ @tokens.shift
22
+ end
23
+
24
+ LOCATION_GEN = /location/
25
+ LOCATION = /(start|end)_location/
26
+ DATE_GEN = /date/
27
+ DATE_FIELD = /(start|end)_date/
28
+ YEAR = /year/
29
+ FIELD = /(duration|distance(_aerial)?|(min|max)_height|(min|max)_speed|points|bearing)/
30
+
31
+ def make_tokens str
32
+ require 'strscan'
33
+ result = []
34
+ scanner = StringScanner.new str
35
+ until scanner.empty?
36
+ case
37
+ when match = scanner.scan(/(or|OR)/)
38
+ result << [:OR, nil]
39
+ when match = scanner.scan(/(and|AND)/)
40
+ result << [:AND, nil]
41
+ when match = scanner.scan(/\(/)
42
+ result << ['(', nil]
43
+ when match = scanner.scan(/\)/)
44
+ result << [')', nil]
45
+ when match = scanner.scan(/[0-9]+-[0-9]+-[0-9]+/)
46
+ result << [:DATE, match]
47
+ when match = scanner.scan(/([0-9]+):([0-9]+):([0-9]+)/)
48
+ seconds = match[6..7].to_i + match[3..4].to_i * 60 + match[0..1].to_i * 3600
49
+ result << [:DURATION, seconds]
50
+ when match = scanner.scan(/[0-9]+(\.[0-9]+)?/)
51
+ result << [:NUMBER, match]
52
+ when match = scanner.scan(LOCATION_GEN)
53
+ result << [:LOCATION_GEN, nil]
54
+ when match = scanner.scan(LOCATION)
55
+ result << [:LOCATION, match]
56
+ when match = scanner.scan(DATE_GEN)
57
+ result << [:DATE_GEN, nil]
58
+ when match = scanner.scan(DATE_FIELD)
59
+ result << [:DATE_FIELD, match]
60
+ when match = scanner.scan(YEAR)
61
+ result << [:YEAR, nil]
62
+ when match = scanner.scan(FIELD)
63
+ result << [:FIELD, match]
64
+ when match = scanner.scan(/"[^"]+"/)
65
+ result << [:STRING, match ]
66
+ when match = scanner.scan(/~/)
67
+ result << [:MATCH, '~']
68
+ when match = scanner.scan(/==/)
69
+ result << [:EQUAL, '==']
70
+ when match = scanner.scan(/>=/)
71
+ result << [:OP, '>=']
72
+ when match = scanner.scan(/>/)
73
+ result << [:OP, '>']
74
+ when match = scanner.scan(/<=/)
75
+ result << [:OP, '<=']
76
+ when match = scanner.scan(/</)
77
+ result << [:OP, '<']
78
+ when scanner.scan(/\s+/)
79
+ # ignore whitespace
80
+ else
81
+ raise "The lexer can't recognize <#{scanner.peek(5)}>"
82
+ end
83
+ end
84
+ result << [false, false]
85
+ return result
86
+ end
87
+ ...end query_parser.racc/module_eval...
88
+ ##### State transition tables begin ###
89
+
90
+ racc_action_table = [
91
+ 6, 7, 8, 9, 10, 11, 6, 7, 8, 9,
92
+ 10, 11, 5, 13, 14, 4, 29, 30, 5, 16,
93
+ 17, 4, 6, 7, 8, 9, 10, 11, 6, 7,
94
+ 8, 9, 10, 11, 5, 22, 21, 4, 22, 21,
95
+ 5, 22, 21, 4, 22, 21, 39, 40, 13, 14,
96
+ 18, 19, 12, 31, 32, 33, 35, 35, 37, 26,
97
+ 13 ]
98
+
99
+ racc_action_check = [
100
+ 0, 0, 0, 0, 0, 0, 14, 14, 14, 14,
101
+ 14, 14, 0, 15, 15, 0, 15, 16, 14, 6,
102
+ 6, 14, 4, 4, 4, 4, 4, 4, 13, 13,
103
+ 13, 13, 13, 13, 4, 8, 8, 4, 9, 9,
104
+ 13, 10, 10, 13, 11, 11, 25, 25, 2, 2,
105
+ 7, 7, 1, 17, 18, 19, 20, 23, 24, 12,
106
+ 28 ]
107
+
108
+ racc_action_pointer = [
109
+ -2, 52, 33, nil, 20, nil, 11, 42, 26, 29,
110
+ 32, 35, 59, 26, 4, -2, 3, 39, 40, 41,
111
+ 45, nil, nil, 46, 46, 34, nil, nil, 45, nil,
112
+ nil, nil, nil, nil, nil, nil, nil, nil, nil, nil,
113
+ nil ]
114
+
115
+ racc_action_default = [
116
+ -20, -20, -1, -2, -20, -6, -20, -20, -20, -20,
117
+ -20, -20, -20, -20, -20, -20, -20, -20, -20, -20,
118
+ -20, -16, -17, -20, -20, -20, 41, -3, -4, -5,
119
+ -7, -8, -9, -10, -11, -15, -12, -13, -14, -18,
120
+ -19 ]
121
+
122
+ racc_goto_table = [
123
+ 2, 1, 38, nil, 15, 20, 23, 24, 25, 34,
124
+ nil, nil, 36, 27, 28 ]
125
+
126
+ racc_goto_check = [
127
+ 2, 1, 6, nil, 2, 4, 4, 4, 4, 5,
128
+ nil, nil, 5, 2, 2 ]
129
+
130
+ racc_goto_pointer = [
131
+ nil, 1, 0, nil, -3, -11, -23 ]
132
+
133
+ racc_goto_default = [
134
+ nil, nil, nil, 3, nil, nil, nil ]
135
+
136
+ racc_reduce_table = [
137
+ 0, 0, :racc_error,
138
+ 1, 20, :_reduce_none,
139
+ 1, 21, :_reduce_2,
140
+ 3, 21, :_reduce_3,
141
+ 3, 21, :_reduce_4,
142
+ 3, 21, :_reduce_5,
143
+ 1, 22, :_reduce_6,
144
+ 3, 22, :_reduce_7,
145
+ 3, 22, :_reduce_8,
146
+ 3, 22, :_reduce_9,
147
+ 3, 22, :_reduce_10,
148
+ 3, 22, :_reduce_11,
149
+ 3, 22, :_reduce_12,
150
+ 3, 22, :_reduce_13,
151
+ 3, 22, :_reduce_14,
152
+ 1, 24, :_reduce_15,
153
+ 1, 23, :_reduce_none,
154
+ 1, 23, :_reduce_none,
155
+ 1, 25, :_reduce_none,
156
+ 1, 25, :_reduce_none ]
157
+
158
+ racc_reduce_n = 20
159
+
160
+ racc_shift_n = 41
161
+
162
+ racc_token_table = {
163
+ false => 0,
164
+ :error => 1,
165
+ :LOCATION_GEN => 2,
166
+ :LOCATION => 3,
167
+ :DATE_GEN => 4,
168
+ :DATE_FIELD => 5,
169
+ :YEAR_FIELD => 6,
170
+ :FIELD => 7,
171
+ :MATCH => 8,
172
+ :EQUAL => 9,
173
+ :OP => 10,
174
+ :DATE => 11,
175
+ :NUMBER => 12,
176
+ :DURATION => 13,
177
+ :STRING => 14,
178
+ :AND => 15,
179
+ :OR => 16,
180
+ "(" => 17,
181
+ ")" => 18 }
182
+
183
+ racc_nt_base = 19
184
+
185
+ racc_use_result_var = true
186
+
187
+ Racc_arg = [
188
+ racc_action_table,
189
+ racc_action_check,
190
+ racc_action_default,
191
+ racc_action_pointer,
192
+ racc_goto_table,
193
+ racc_goto_check,
194
+ racc_goto_default,
195
+ racc_goto_pointer,
196
+ racc_nt_base,
197
+ racc_reduce_table,
198
+ racc_token_table,
199
+ racc_shift_n,
200
+ racc_reduce_n,
201
+ racc_use_result_var ]
202
+
203
+ Racc_token_to_s_table = [
204
+ "$end",
205
+ "error",
206
+ "LOCATION_GEN",
207
+ "LOCATION",
208
+ "DATE_GEN",
209
+ "DATE_FIELD",
210
+ "YEAR_FIELD",
211
+ "FIELD",
212
+ "MATCH",
213
+ "EQUAL",
214
+ "OP",
215
+ "DATE",
216
+ "NUMBER",
217
+ "DURATION",
218
+ "STRING",
219
+ "AND",
220
+ "OR",
221
+ "\"(\"",
222
+ "\")\"",
223
+ "$start",
224
+ "start",
225
+ "exp",
226
+ "simple_exp",
227
+ "op_or_equal",
228
+ "date",
229
+ "value" ]
230
+
231
+ Racc_debug_parser = false
232
+
233
+ ##### State transition tables end #####
234
+
235
+ # reduce 0 omitted
236
+
237
+ # reduce 1 omitted
238
+
239
+ module_eval(<<'.,.,', 'query_parser.racc', 50)
240
+ def _reduce_2(val, _values, result)
241
+ result = "#{val[0]}"
242
+ result
243
+ end
244
+ .,.,
245
+
246
+ module_eval(<<'.,.,', 'query_parser.racc', 51)
247
+ def _reduce_3(val, _values, result)
248
+ result = "(#{val[0]} and #{val[2]})"
249
+ result
250
+ end
251
+ .,.,
252
+
253
+ module_eval(<<'.,.,', 'query_parser.racc', 52)
254
+ def _reduce_4(val, _values, result)
255
+ result = "(#{val[0]} or #{val[2]})"
256
+ result
257
+ end
258
+ .,.,
259
+
260
+ module_eval(<<'.,.,', 'query_parser.racc', 53)
261
+ def _reduce_5(val, _values, result)
262
+ result = "(#{val[1]})"
263
+ result
264
+ end
265
+ .,.,
266
+
267
+ module_eval(<<'.,.,', 'query_parser.racc', 55)
268
+ def _reduce_6(val, _values, result)
269
+ result = "x[:start_location].include?(#{val[0]}) or x[:end_location].include?(#{val[0]})"
270
+ result
271
+ end
272
+ .,.,
273
+
274
+ module_eval(<<'.,.,', 'query_parser.racc', 57)
275
+ def _reduce_7(val, _values, result)
276
+ result = "x[:start_location].include?(#{val[2]}) or x[:end_location].include?(#{val[2]})"
277
+ result
278
+ end
279
+ .,.,
280
+
281
+ module_eval(<<'.,.,', 'query_parser.racc', 59)
282
+ def _reduce_8(val, _values, result)
283
+ result = "x[:start_location] == #{val[2]} or x[:end_location] == #{val[2]}"
284
+ result
285
+ end
286
+ .,.,
287
+
288
+ module_eval(<<'.,.,', 'query_parser.racc', 61)
289
+ def _reduce_9(val, _values, result)
290
+ result = "x[:#{val[0]}].include?(#{val[2]})"
291
+ result
292
+ end
293
+ .,.,
294
+
295
+ module_eval(<<'.,.,', 'query_parser.racc', 63)
296
+ def _reduce_10(val, _values, result)
297
+ result = "x[:#{val[0]}] == #{val[2]}"
298
+ result
299
+ end
300
+ .,.,
301
+
302
+ module_eval(<<'.,.,', 'query_parser.racc', 65)
303
+ def _reduce_11(val, _values, result)
304
+ result = "x[:start_date] #{val[1]} #{val[2]} or x[:end_date] #{val[1]} #{val[2]}"
305
+ result
306
+ end
307
+ .,.,
308
+
309
+ module_eval(<<'.,.,', 'query_parser.racc', 67)
310
+ def _reduce_12(val, _values, result)
311
+ result = "#{val[0]} #{val[1]} #{val[2]}"
312
+ result
313
+ end
314
+ .,.,
315
+
316
+ module_eval(<<'.,.,', 'query_parser.racc', 69)
317
+ def _reduce_13(val, _values, result)
318
+ result = "x[:start_date].year #{val[1]} #{val[2]} or x[:end_date].year #{val[1]} #{val[2]}"
319
+ result
320
+ end
321
+ .,.,
322
+
323
+ module_eval(<<'.,.,', 'query_parser.racc', 71)
324
+ def _reduce_14(val, _values, result)
325
+ result = "x[:#{val[0]}] #{val[1]} #{val[2]}"
326
+ result
327
+ end
328
+ .,.,
329
+
330
+ module_eval(<<'.,.,', 'query_parser.racc', 73)
331
+ def _reduce_15(val, _values, result)
332
+ result = "Date.parse(\"#{val[0]}\")"
333
+ result
334
+ end
335
+ .,.,
336
+
337
+ # reduce 16 omitted
338
+
339
+ # reduce 17 omitted
340
+
341
+ # reduce 18 omitted
342
+
343
+ # reduce 19 omitted
344
+
345
+ def _reduce_none(val, _values, result)
346
+ val[0]
347
+ end
348
+
349
+ end # class QueryParser
@@ -0,0 +1,48 @@
1
+ require 'yaml'
2
+
3
+ module Columbus3
4
+ class Sidecar
5
+ def initialize filename
6
+ @metadata = Hash.new
7
+ @metadata[:filename] = filename
8
+ end
9
+
10
+ def metadata= metadata
11
+ filename = @metadata[:filename]
12
+ @metadata = metadata
13
+ @metadata[:filename] = filename
14
+ end
15
+
16
+ def metadata
17
+ @metadata
18
+ end
19
+
20
+ def keys
21
+ @metadata.keys
22
+ end
23
+
24
+ def load
25
+ YAML.load(File.read(@metadata[:filename] + ".yaml", "r"))
26
+ end
27
+
28
+ def save
29
+ File.open(@metadata[:filename] + ".yaml", "w") do |file|
30
+ file << @metadata.to_yaml
31
+ end
32
+ end
33
+ end
34
+
35
+ class SidecarSearch
36
+ def initialize
37
+ @metadata = Array.new
38
+ end
39
+
40
+ def load array
41
+ @metadata = array.each.map { |x| YAML.load(File.read(x)) }
42
+ end
43
+
44
+ def search term
45
+ @metadata.select { |x| eval(term) }
46
+ end
47
+ end
48
+ end
@@ -0,0 +1,73 @@
1
+ require 'erb'
2
+ require 'yaml'
3
+
4
+ module Columbus3
5
+ # renderer controls the transformation of a V900 tracks into a displayable format,
6
+ # whatever this means
7
+ module LeafletRenderer
8
+ # apply the ERB in html/show.html.erb (which includes all the tracks to display)
9
+ # and save it in the current directory, under _show.html
10
+ def self.show files
11
+ template = File.join(File.dirname(__FILE__), "/../../html/show.html.erb")
12
+ renderer = ERB.new(File.read(template))
13
+
14
+ # context: location of css and js + list of files to show
15
+ bower_dir = File.join(File.dirname(__FILE__), "/../../../bower_components")
16
+ @leaflet_providers = File.join(bower_dir, 'leaflet-providers/leaflet-providers.js')
17
+ @leaflet_js = File.join(bower_dir, 'leaflet/dist/leaflet.js')
18
+ @leaflet_css = File.join(bower_dir, 'leaflet/dist/leaflet.css')
19
+ @files = files
20
+
21
+ # generate the output
22
+ html = renderer.result(binding)
23
+
24
+ # save it to file
25
+ File.open("_show.html", "w") do |file|
26
+ file << html
27
+ end
28
+ end
29
+
30
+ # make a v900 track into a leaflet layer cached to disk
31
+ def self.to_leaflet filename, force = false
32
+
33
+ target = to_leaflet_filename filename
34
+
35
+ if force or not File.exists? target
36
+ track = V900Track.new filename
37
+ File.open(target, "w") do |file|
38
+ id = sanitize filename
39
+
40
+ file.printf <<EOS
41
+ latlong_#{id} = #{track.range.each.map { |i| track[i].lat_lon }};\n
42
+ start_#{id} = L.marker(#{track.first.lat_lon}).bindPopup('Start');\n
43
+ end_#{id} = L.marker(#{track.last.lat_lon}).bindPopup('End');\n
44
+ poly_#{id} = L.polyline(latlong_#{id}, {color: 'red'});\n
45
+
46
+ max_speed_#{id} = L.marker(#{track[track.max_speed_idx].lat_lon}).bindPopup('Max speed #{track.max_speed}')\n;
47
+ max_height_#{id} = L.marker(#{track[track.max_height_idx].lat_lon}).bindPopup('Max height #{track.max_height}')\n;
48
+ min_height_#{id} = L.marker(#{track[track.min_height_idx].lat_lon}).bindPopup('Min height #{track.min_height}')\n;
49
+
50
+ #{to_leaflet_layername filename} = L.layerGroup([start_#{id}, end_#{id}, poly_#{id}, max_speed_#{id}, max_height_#{id}, min_height_#{id}]);\n
51
+ #{to_leaflet_layername filename}.addTo(map);\n
52
+ EOS
53
+ end
54
+ end
55
+
56
+ end
57
+
58
+ def self.to_leaflet_filename filename
59
+ filename + ".js"
60
+ end
61
+
62
+ def self.to_leaflet_layername filename
63
+ "layer_" + sanitize(filename)
64
+ end
65
+
66
+ private
67
+
68
+ def self.sanitize filename
69
+ filename.gsub(/[^0-9A-Za-z\-]/, "_")
70
+ end
71
+
72
+ end
73
+ end
@@ -0,0 +1,157 @@
1
+ require 'csv'
2
+ require 'geocoder'
3
+
4
+ require 'columbus3/v900track/v900waypoint'
5
+
6
+ class V900Track
7
+ def initialize filename
8
+ read filename
9
+ end
10
+
11
+ def read filename
12
+ @data = CSV::read(filename, :headers => true).each.map { |item| V900Waypoint.new(item) }
13
+ end
14
+
15
+ def size
16
+ @data.size
17
+ end
18
+
19
+ # an alias for size
20
+ def points
21
+ @data.size
22
+ end
23
+
24
+ def range
25
+ (0..self.size - 1)
26
+ end
27
+
28
+ # to enumerate (till I can solve the each issue)
29
+ def to_a
30
+ @data
31
+ end
32
+
33
+ # it does not work
34
+ #def each
35
+ # @data.each
36
+ #end
37
+
38
+ def get i
39
+ self[i]
40
+ end
41
+
42
+ def [](i)
43
+ @data[i]
44
+ end
45
+
46
+ def first
47
+ @data[0]
48
+ end
49
+
50
+ def last
51
+ @data[size - 1]
52
+ end
53
+
54
+ # statistics
55
+
56
+ def start_date
57
+ first.time
58
+ end
59
+
60
+ def end_date
61
+ last.time
62
+ end
63
+
64
+ def duration
65
+ last.time - first.time
66
+ end
67
+
68
+ def min_speed
69
+ get :<, :speed
70
+ end
71
+
72
+ def max_speed
73
+ get :>, :speed
74
+ end
75
+
76
+ def min_height
77
+ get :<, :height
78
+ end
79
+
80
+ def max_height
81
+ get :>, :height
82
+ end
83
+
84
+ def min_speed_idx
85
+ get_idx :<, :speed
86
+ end
87
+
88
+ def max_speed_idx
89
+ get_idx :>, :speed
90
+ end
91
+
92
+ def min_height_idx
93
+ get_idx :<, :height
94
+ end
95
+
96
+ def max_height_idx
97
+ get_idx :>, :height
98
+ end
99
+
100
+ def start_location
101
+ Geocoder.address(first.lat_lon)
102
+ end
103
+
104
+ def end_location
105
+ Geocoder.address(last.lat_lon)
106
+ end
107
+
108
+ def bearing
109
+ Geocoder::Calculations.compass_point(Geocoder::Calculations.bearing_between(first.lat_lon, last.lat_lon))
110
+ end
111
+
112
+ def distance_aerial
113
+ Geocoder::Calculations.distance_between(first.lat_lon, last.lat_lon, :units => :km)
114
+ end
115
+
116
+ def distance
117
+ distance = 0
118
+ range.each do |i|
119
+ distance += Geocoder::Calculations.distance_between(self[i].lat_lon, self[i-1].lat_lon, :units => :km)
120
+ end
121
+ distance
122
+ end
123
+
124
+ # return a hash with all the metadata
125
+ # ... it could be a nice metamethod, creating a key for each public methods
126
+ def metadata
127
+ metadata = Hash.new
128
+
129
+ [:start_date, :end_date, :duration, :size, :start_location, :end_location, :min_speed, :max_speed, :min_height, :max_height, :bearing, :distance, :distance_aerial].map { |x| metadata[x] = self.send(x) }
130
+
131
+ metadata
132
+ end
133
+
134
+ private
135
+
136
+ def get comparison, method
137
+ current = self[0].send(method) # initialize max or min to the first value in the file
138
+ range.each do |i|
139
+ current = self[i].send(method) if self[i].send(method).send(comparison, current)
140
+ end
141
+ current
142
+ end
143
+
144
+ def get_idx comparison, method
145
+ current = self[0].send(method) # initialize max or min to the first value in the file
146
+ idx = 0
147
+ range.each do |i|
148
+ if self[i].send(method).send(comparison, current) then
149
+ current = self[i].send(method)
150
+ idx = i
151
+ end
152
+ end
153
+ idx
154
+ end
155
+
156
+ end
157
+
@@ -0,0 +1,51 @@
1
+ require 'time'
2
+
3
+ # a facade which presents a CSV::row as a v900 waypoint
4
+ class V900Waypoint
5
+ def initialize row
6
+ @row = row
7
+ end
8
+
9
+ def index
10
+ @row["INDEX"].to_i
11
+ end
12
+
13
+ def tag
14
+ @row["TAG"]
15
+ end
16
+
17
+ def time
18
+ date = @row["DATE"]
19
+ time = @row["TIME"]
20
+ # make sure it is understood as ZULU time (UTC) and pad time to six numbers 75858 -> 075858
21
+ Time.parse("#{date}T" + ("%06d" % time) + "Z")
22
+ end
23
+
24
+ def lon
25
+ value = @row["LONGITUDE E/W"]
26
+ value.match(/(N|E)/) ? value[0..-2].to_f : -1 * value[0..-2].to_f
27
+ end
28
+
29
+ def lat
30
+ value = @row["LATITUDE N/S"]
31
+ value.match(/(N|E)/) ? value[0..-2].to_f : -1 * value[0..-2].to_f
32
+ end
33
+
34
+ # return an array with lat and lon: [lat, lon]
35
+ def lat_lon
36
+ [lat, lon]
37
+ end
38
+
39
+ def height
40
+ @row["HEIGHT"].to_i
41
+ end
42
+
43
+ def speed
44
+ @row["SPEED"].to_i
45
+ end
46
+
47
+ def heading
48
+ @row["HEADING"].to_i
49
+ end
50
+
51
+ end
@@ -0,0 +1,3 @@
1
+ module Columbus3
2
+ VERSION = "0.1.0"
3
+ end
data/lib/columbus3.rb ADDED
@@ -0,0 +1,6 @@
1
+ require "columbus3/version"
2
+ require "columbus3/metadata/query_parser.tab"
3
+ require "columbus3/metadata/sidecar"
4
+ require "columbus3/v900track/v900track"
5
+ require "columbus3/v900track/v900waypoint"
6
+ require "columbus3/renderer/renderer"