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.
- checksums.yaml +7 -0
- data/.gitignore +9 -0
- data/.travis.yml +4 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +21 -0
- data/README.md +41 -0
- data/Rakefile +10 -0
- data/bin/console +14 -0
- data/bin/setup +7 -0
- data/bower_components/leaflet/.bower.json +34 -0
- data/bower_components/leaflet/CHANGELOG.md +929 -0
- data/bower_components/leaflet/CONTRIBUTING.md +155 -0
- data/bower_components/leaflet/Jakefile.js +48 -0
- data/bower_components/leaflet/LICENSE +23 -0
- data/bower_components/leaflet/PLUGIN-GUIDE.md +127 -0
- data/bower_components/leaflet/README.md +34 -0
- data/bower_components/leaflet/bower.json +24 -0
- data/bower_components/leaflet/component.json +20 -0
- data/bower_components/leaflet/dist/images/layers-2x.png +0 -0
- data/bower_components/leaflet/dist/images/layers.png +0 -0
- data/bower_components/leaflet/dist/images/marker-icon-2x.png +0 -0
- data/bower_components/leaflet/dist/images/marker-icon.png +0 -0
- data/bower_components/leaflet/dist/images/marker-shadow.png +0 -0
- data/bower_components/leaflet/dist/leaflet-src.js +9180 -0
- data/bower_components/leaflet/dist/leaflet.css +478 -0
- data/bower_components/leaflet/dist/leaflet.js +9 -0
- data/bower_components/leaflet/package.json +33 -0
- data/bower_components/leaflet-providers/.bower.json +35 -0
- data/bower_components/leaflet-providers/CONTRIBUTING.md +10 -0
- data/bower_components/leaflet-providers/README.md +54 -0
- data/bower_components/leaflet-providers/bower.json +25 -0
- data/bower_components/leaflet-providers/css/gh-fork-ribbon.css +127 -0
- data/bower_components/leaflet-providers/css/gh-fork-ribbon.ie.css +68 -0
- data/bower_components/leaflet-providers/leaflet-providers.js +630 -0
- data/bower_components/leaflet-providers/license.md +9 -0
- data/bower_components/leaflet-providers/package.json +38 -0
- data/columbus3.gemspec +28 -0
- data/exe/columbus3 +144 -0
- data/lib/columbus3/metadata/query_parser.racc +160 -0
- data/lib/columbus3/metadata/query_parser.tab.rb +349 -0
- data/lib/columbus3/metadata/sidecar.rb +48 -0
- data/lib/columbus3/renderer/renderer.rb +73 -0
- data/lib/columbus3/v900track/v900track.rb +157 -0
- data/lib/columbus3/v900track/v900waypoint.rb +51 -0
- data/lib/columbus3/version.rb +3 -0
- data/lib/columbus3.rb +6 -0
- data/lib/html/show.html.erb +84 -0
- data/lib/html/track.js.erb +15 -0
- 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
|