columbus3 0.5.1 → 0.6.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -5
- data/README.md +126 -33
- data/bin/console +0 -0
- data/bin/setup +0 -0
- data/columbus3.gemspec +7 -7
- data/doc/ChangeLog.org +47 -0
- data/doc/todo.org +24 -11
- data/lib/columbus3/cli/command_semantics.rb +71 -192
- data/lib/columbus3/cli/command_syntax.rb +214 -15
- data/lib/columbus3/metadata/sidecar.rb +6 -1
- data/lib/columbus3/renderer/flot_renderer.rb +12 -8
- data/lib/columbus3/renderer/leaflet_renderer.rb +12 -8
- data/lib/columbus3/version.rb +1 -1
- data/lib/html/flot.html.erb +1 -1
- data/lib/html/show.html.erb +1 -1
- data/lib/html/track.js.erb +3 -3
- metadata +18 -18
- data/doc/manual.txt +0 -122
@@ -18,34 +18,107 @@ module Columbus3
|
|
18
18
|
def self.version_opts
|
19
19
|
opts = Slop::Options.new
|
20
20
|
opts.banner = "version -- print version information"
|
21
|
-
|
21
|
+
help = <<EOS
|
22
|
+
NAME
|
23
|
+
#{opts.banner}
|
24
|
+
|
25
|
+
SYNOPSYS
|
26
|
+
#{opts.to_s}
|
27
|
+
|
28
|
+
DESCRIPTION
|
29
|
+
return version information
|
30
|
+
|
31
|
+
EXAMPLES
|
32
|
+
columbus3 version
|
33
|
+
columbus3 version #{VERSION}
|
34
|
+
EOS
|
35
|
+
return { :version => [opts, :version, help] }
|
22
36
|
end
|
23
37
|
|
24
38
|
def self.console_opts
|
25
39
|
opts = Slop::Options.new
|
26
40
|
opts.banner = "console [options] -- Enter the console"
|
27
|
-
|
28
|
-
|
41
|
+
help = <<EOS
|
42
|
+
NAME
|
43
|
+
#{opts.banner}
|
44
|
+
|
45
|
+
SYNOPSYS
|
46
|
+
#{opts.to_s}
|
47
|
+
|
48
|
+
DESCRIPTION
|
49
|
+
Invoke a console, from which you can more easily run
|
50
|
+
columbus3 commands.
|
51
|
+
|
52
|
+
EXAMPLES
|
53
|
+
columbus3 console
|
54
|
+
columbus3:000> process 11010101.CSV
|
55
|
+
columbus3:001> show 11010101.CSV
|
56
|
+
columbus3:002>
|
57
|
+
EOS
|
58
|
+
return { :console => [opts, :console, help] }
|
29
59
|
end
|
30
60
|
|
31
61
|
def self.man_opts
|
32
62
|
opts = Slop::Options.new
|
33
63
|
opts.banner = "man -- print a manual page"
|
34
|
-
|
64
|
+
help = <<EOS
|
65
|
+
NAME
|
66
|
+
#{opts.banner}
|
67
|
+
|
68
|
+
SYNOPSYS
|
69
|
+
#{opts.to_s}
|
70
|
+
|
71
|
+
DESCRIPTION
|
72
|
+
Print the README file of this gem
|
73
|
+
|
74
|
+
EXAMPLES
|
75
|
+
columbus3 man
|
76
|
+
EOS
|
77
|
+
return { :man => [opts, :man, help] }
|
35
78
|
end
|
36
79
|
|
37
80
|
def self.help_opts
|
38
81
|
opts = Slop::Options.new
|
39
82
|
opts.banner = "help [command] -- print usage string"
|
40
|
-
|
83
|
+
help = <<EOS
|
84
|
+
NAME
|
85
|
+
#{opts.banner}
|
86
|
+
|
87
|
+
SYNOPSYS
|
88
|
+
#{opts.to_s}
|
89
|
+
|
90
|
+
DESCRIPTION
|
91
|
+
Print help about a command
|
92
|
+
|
93
|
+
EXAMPLES
|
94
|
+
columbus3 help
|
95
|
+
columbus3 help process
|
96
|
+
EOS
|
97
|
+
return { :help => [opts, :help, help] }
|
41
98
|
end
|
42
99
|
|
43
100
|
def self.process_opts
|
44
101
|
opts = Slop::Options.new
|
45
102
|
opts.banner = "process [track ...] -- generate sidecar files for given tracks"
|
46
103
|
opts.boolean "-f", "--force", "Overwrite existing sidecar file"
|
47
|
-
|
48
|
-
|
104
|
+
help = <<EOS
|
105
|
+
NAME
|
106
|
+
#{opts.banner}
|
107
|
+
|
108
|
+
SYNOPSYS
|
109
|
+
#{opts.to_s}
|
110
|
+
|
111
|
+
DESCRIPTION
|
112
|
+
Generate a sidecar file for the track(s) passed as input.
|
113
|
+
|
114
|
+
Once created a sidecar file usually does not need to be regenerated. You can
|
115
|
+
use the `--force` option to cause the sidecar file to be rewritten.
|
116
|
+
|
117
|
+
EXAMPLES
|
118
|
+
columbus3 process 11010101.CSV 11010201.CSV
|
119
|
+
columbus3 process *
|
120
|
+
EOS
|
121
|
+
return { process: [opts, :process, help] }
|
49
122
|
end
|
50
123
|
|
51
124
|
def self.search_opts
|
@@ -54,10 +127,81 @@ module Columbus3
|
|
54
127
|
|
55
128
|
opts.boolean "--debug", "Show how the query is processed"
|
56
129
|
opts.boolean "-r", "--recurse", "Recurse in subdirectories"
|
57
|
-
opts.string "-d", "--dir", "Directory to search"
|
130
|
+
opts.string "-d", "--dir", "Directory to search (default to current directory)"
|
58
131
|
opts.array "--fields", "Comma separated list of fields to print"
|
132
|
+
help = <<EOS
|
133
|
+
NAME
|
134
|
+
#{opts.banner}
|
135
|
+
|
136
|
+
SYNOPSYS
|
137
|
+
#{opts.to_s}
|
138
|
+
|
139
|
+
DESCRIPTION
|
140
|
+
Search a directory for tracks matching your search criteria.
|
141
|
+
|
142
|
+
By default columbus3 searches in the current dir; use the `--dir`
|
143
|
+
option to choose a different directory.
|
144
|
+
|
145
|
+
Use `--recurse` to recurce in subdirectories as well.
|
146
|
+
|
147
|
+
Use `--fields` to choose what information is displayed in the output.
|
148
|
+
|
149
|
+
Terms you can search for:
|
150
|
+
|
151
|
+
location, start_location, end_location
|
152
|
+
date, start_date, end_date
|
153
|
+
year
|
154
|
+
duration
|
155
|
+
max_speed
|
156
|
+
min_height
|
157
|
+
max_height
|
158
|
+
|
159
|
+
Numerical operators:
|
59
160
|
|
60
|
-
|
161
|
+
<, <=, ==, >=, >
|
162
|
+
|
163
|
+
String operators (locations):
|
164
|
+
|
165
|
+
~ (contains), == (is exactly)
|
166
|
+
|
167
|
+
Complex Terms:
|
168
|
+
|
169
|
+
Use "and" and "or" to build complex queries
|
170
|
+
|
171
|
+
Examples of simple searches
|
172
|
+
|
173
|
+
'location ~ "USA"' any track whose start or end location contains USA
|
174
|
+
'date > 2015-02-14' any track whose start or end date is after Feb 14, 2015
|
175
|
+
'year == 2015' any track whose start or end date is in 2015
|
176
|
+
'duration <= 01:02:03' any track with a duration of less than 1h, 2min, and 3secs
|
177
|
+
'max_speed > 120' any track with a max speed greater than 120 km/h
|
178
|
+
'min_height == 10' any track with a min height lower than 10 meters
|
179
|
+
|
180
|
+
Examples of complex searches
|
181
|
+
'location ~ "USA" and start_date >= 2015-01-01' tracks in the USA after or on Jan 1, 2015
|
182
|
+
'start_location ~ "Trenton" and end_location ~ "New York"' trips from Trenton to New York
|
183
|
+
|
184
|
+
List of supported fields in the output list:
|
185
|
+
|
186
|
+
yaml -> full pathname of the YAML metadata file
|
187
|
+
path -> full pathname of the CSV file
|
188
|
+
filename -> basename of the CSV file
|
189
|
+
start_location -> start location
|
190
|
+
end_location -> end location
|
191
|
+
start_date -> start date (and time)
|
192
|
+
end_date -> end date (and time)
|
193
|
+
duration -> duration in seconds
|
194
|
+
min_speed -> minimum speed in km/h
|
195
|
+
max_speed -> maximum speed in km/h
|
196
|
+
min_height -> minimum height in meters
|
197
|
+
max_height -> maximum height in meters
|
198
|
+
|
199
|
+
EXAMPLES
|
200
|
+
|
201
|
+
columbus3 search 'location ~ "USA"'
|
202
|
+
columbus3 search 'location ~ "USA" and speed < 10' --fields path | columbus3 show
|
203
|
+
EOS
|
204
|
+
return { search: [opts, :search, help] }
|
61
205
|
end
|
62
206
|
|
63
207
|
def self.show_opts
|
@@ -66,9 +210,21 @@ module Columbus3
|
|
66
210
|
|
67
211
|
opts.string "-f", "--filename=", "Output filename (default is _show.html)"
|
68
212
|
opts.boolean "--force", "Force rewriting of the js file, even if it already exists"
|
69
|
-
|
213
|
+
help = <<EOS
|
214
|
+
NAME
|
215
|
+
#{opts.banner}
|
216
|
+
|
217
|
+
SYNOPSYS
|
218
|
+
#{opts.to_s}
|
219
|
+
|
220
|
+
DESCRIPTION
|
221
|
+
Generate an html file which shows the track on a map.
|
70
222
|
|
71
|
-
|
223
|
+
EXAMPLES
|
224
|
+
columbus3 show 11010101.CSV 11010201.CSV
|
225
|
+
columbus3 search 'location ~ "USA" and speed < 10' --fields path | columbus3 show --filename "us_tracks.html"
|
226
|
+
EOS
|
227
|
+
return { show: [opts, :show, help] }
|
72
228
|
end
|
73
229
|
|
74
230
|
def self.graph_opts
|
@@ -76,18 +232,61 @@ module Columbus3
|
|
76
232
|
opts.banner = "graph [--filename filename] [--force] track -- plot speed and height profile of track"
|
77
233
|
|
78
234
|
opts.boolean "--force", "Force rewriting of the js file, even if it already exists"
|
235
|
+
help = <<EOS
|
236
|
+
NAME
|
237
|
+
#{opts.banner}
|
79
238
|
|
80
|
-
|
239
|
+
SYNOPSYS
|
240
|
+
#{opts.to_s}
|
241
|
+
|
242
|
+
DESCRIPTION
|
243
|
+
Plot speed and height profile of a single track.
|
244
|
+
|
245
|
+
EXAMPLES
|
246
|
+
columbus3 graph 11010101.CSV
|
247
|
+
EOS
|
248
|
+
return { graph: [opts, :graph, help] }
|
81
249
|
end
|
82
250
|
|
83
251
|
def self.convert_opts
|
84
252
|
opts = Slop::Options.new
|
85
253
|
opts.banner = "convert track -- convert a GPX into a set of CSV files"
|
86
|
-
opts.boolean "--force", "Force rewriting of the csv files, even if
|
254
|
+
opts.boolean "--force", "Force rewriting of the csv files, even if they already exist"
|
255
|
+
help = <<EOS
|
256
|
+
NAME
|
257
|
+
#{opts.banner}
|
87
258
|
|
88
|
-
|
89
|
-
|
259
|
+
SYNOPSYS
|
260
|
+
#{opts.to_s}
|
261
|
+
|
262
|
+
DESCRIPTION
|
263
|
+
Convert a GPX track to a CSV track
|
264
|
+
|
265
|
+
The command is useful if you are using different loggers for generating your
|
266
|
+
tracks:
|
267
|
+
|
268
|
+
columbus3 convert file.gpx
|
90
269
|
|
270
|
+
will generate
|
271
|
+
|
272
|
+
file-1.csv
|
273
|
+
file-2.csv
|
274
|
+
...
|
275
|
+
|
276
|
+
one per track in the GPX file.
|
277
|
+
|
278
|
+
EXAMPLES
|
279
|
+
columbus3 convert track.gpx
|
280
|
+
|
281
|
+
BUGS AND LIMITATIONS
|
282
|
+
|
283
|
+
The Columbus V900 format has fields with fixed width, and uses ^@ as a filler.
|
284
|
+
The CSV file generated by the convert command generates fields of variable width
|
285
|
+
(standard CSV files, I dare say). The heading field is not computed
|
286
|
+
and the field is filled with -1.
|
287
|
+
EOS
|
288
|
+
return { convert: [opts, :convert, help] }
|
289
|
+
end
|
91
290
|
|
92
291
|
# def self.split_opts
|
93
292
|
# opts = Slop::Options.new
|
@@ -21,6 +21,11 @@ module Columbus3
|
|
21
21
|
@metadata.keys
|
22
22
|
end
|
23
23
|
|
24
|
+
# it always works because initialization requires a filename
|
25
|
+
def filename
|
26
|
+
@metadata[:filename] + ".yaml"
|
27
|
+
end
|
28
|
+
|
24
29
|
def load
|
25
30
|
@metadata = YAML.load(File.read(@metadata[:filename] + ".yaml"))
|
26
31
|
end
|
@@ -47,7 +52,7 @@ module Columbus3
|
|
47
52
|
end
|
48
53
|
|
49
54
|
def load array
|
50
|
-
@metadata = array.each.map { |x| YAML.load(File.read(x)).merge({ :
|
55
|
+
@metadata = array.each.map { |x| YAML.load(File.read(x)).merge({ path: x.gsub(/\.yaml$/, ''), yaml: x }) }
|
51
56
|
end
|
52
57
|
|
53
58
|
def search term
|
@@ -5,9 +5,14 @@ require 'columbus3/renderer/sanitizer'
|
|
5
5
|
module Columbus3
|
6
6
|
# make a track into a flot graph (speed and height)
|
7
7
|
module FlotRenderer
|
8
|
-
|
9
|
-
|
10
|
-
|
8
|
+
OUTPUT_FILENAME = "_graph.html"
|
9
|
+
|
10
|
+
# apply the ERB in html/flot.html.erb and save it in the current directory
|
11
|
+
# use filename if provided or the default OUTPUT_FILENAME
|
12
|
+
def self.show hash
|
13
|
+
filename = hash[:filename] || OUTPUT_FILENAME
|
14
|
+
files = hash[:files] || []
|
15
|
+
|
11
16
|
template = File.join(File.dirname(__FILE__), "/../../html/flot.html.erb")
|
12
17
|
renderer = ERB.new(File.read(template))
|
13
18
|
|
@@ -19,7 +24,7 @@ module Columbus3
|
|
19
24
|
File.join(bower_dir, 'flot/jquery.flot.time.js'),
|
20
25
|
File.join(bower_dir, 'flot/jquery.flot.selection.js')
|
21
26
|
]
|
22
|
-
@file =
|
27
|
+
@file = files[0]
|
23
28
|
# TODO: manage the case of sidecar not existing
|
24
29
|
@track_info = Sidecar.new @file
|
25
30
|
@track_info.load
|
@@ -34,8 +39,8 @@ module Columbus3
|
|
34
39
|
end
|
35
40
|
|
36
41
|
# make a v900 track into a graph layer cached to disk
|
37
|
-
def self.
|
38
|
-
target =
|
42
|
+
def self.to_javascript_file filename, force = false
|
43
|
+
target = to_javascript_filename filename
|
39
44
|
|
40
45
|
if force or not File.exists? target
|
41
46
|
track = V900Track.new filename: filename
|
@@ -50,10 +55,9 @@ height_#{id} = #{track.range.each.map { |i|[track[i].time.to_i * 1000, track[i].
|
|
50
55
|
EOS
|
51
56
|
end
|
52
57
|
end
|
53
|
-
|
54
58
|
end
|
55
59
|
|
56
|
-
def self.
|
60
|
+
def self.to_javascript_filename filename
|
57
61
|
filename + "_graph.js"
|
58
62
|
end
|
59
63
|
|
@@ -6,9 +6,14 @@ module Columbus3
|
|
6
6
|
# renderer controls the transformation of a V900 tracks into a displayable format,
|
7
7
|
# whatever this means
|
8
8
|
module LeafletRenderer
|
9
|
+
OUTPUT_FILENAME = "_show.html"
|
10
|
+
|
9
11
|
# apply the ERB in html/show.html.erb (which includes all the tracks to display)
|
10
12
|
# and save it in the current directory, under _show.html
|
11
|
-
def self.show
|
13
|
+
def self.show hash
|
14
|
+
filename = hash[:filename] || OUTPUT_FILENAME
|
15
|
+
files = hash[:files] || []
|
16
|
+
|
12
17
|
template = File.join(File.dirname(__FILE__), "/../../html/show.html.erb")
|
13
18
|
renderer = ERB.new(File.read(template))
|
14
19
|
|
@@ -25,10 +30,9 @@ module Columbus3
|
|
25
30
|
end
|
26
31
|
end
|
27
32
|
|
28
|
-
# make a v900 track into a
|
29
|
-
def self.
|
30
|
-
|
31
|
-
target = to_geojson_filename filename
|
33
|
+
# make a v900 track into a geojson file
|
34
|
+
def self.to_javascript_file filename, force = false
|
35
|
+
target = to_javascript_filename filename
|
32
36
|
|
33
37
|
if force or not File.exists? target
|
34
38
|
# load the template
|
@@ -47,15 +51,15 @@ module Columbus3
|
|
47
51
|
|
48
52
|
end
|
49
53
|
|
50
|
-
def self.
|
54
|
+
def self.to_javascript_filename filename
|
51
55
|
filename + ".js"
|
52
56
|
end
|
53
57
|
|
54
58
|
def self.to_leaflet_layername filename
|
55
|
-
|
59
|
+
to_javascript_varname "layer_", Sanitizer::sanitize(filename)
|
56
60
|
end
|
57
61
|
|
58
|
-
def self.
|
62
|
+
def self.to_javascript_varname prefix, filename
|
59
63
|
prefix + Sanitizer::sanitize(filename)
|
60
64
|
end
|
61
65
|
end
|
data/lib/columbus3/version.rb
CHANGED
data/lib/html/flot.html.erb
CHANGED
@@ -35,7 +35,7 @@
|
|
35
35
|
<% end %>
|
36
36
|
</div>
|
37
37
|
|
38
|
-
<script src="<%=
|
38
|
+
<script src="<%= to_javascript_filename @file %>"></script>
|
39
39
|
<script>
|
40
40
|
// required by plot for tooltips (it moves the tooltip, appending it directly to body
|
41
41
|
$("<div id='tooltip'></div>").appendTo("body");
|
data/lib/html/show.html.erb
CHANGED
@@ -38,7 +38,7 @@
|
|
38
38
|
|
39
39
|
<%# insert the requested GPX Tracks (in json format) %>
|
40
40
|
<% @files.each do |file| %>
|
41
|
-
<script src="<%=
|
41
|
+
<script src="<%= to_javascript_filename file %>"></script>
|
42
42
|
<% end %>
|
43
43
|
|
44
44
|
<%# make each track into a layer%>
|
data/lib/html/track.js.erb
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
var <%=
|
1
|
+
var <%= to_javascript_varname "track_", @filename %> =
|
2
2
|
{ "type": "FeatureCollection",
|
3
3
|
"features": [
|
4
4
|
{ "type": "Feature",
|
@@ -39,7 +39,7 @@ var <%= to_varname "track_", @filename %> =
|
|
39
39
|
]
|
40
40
|
};
|
41
41
|
|
42
|
-
<%= to_leaflet_layername @filename %> = L.geoJson(<%=
|
42
|
+
<%= to_leaflet_layername @filename %> = L.geoJson(<%= to_javascript_varname "track_", @filename %>, {
|
43
43
|
onEachFeature: function onEachFeature(feature, layer) {
|
44
44
|
if (feature.properties && feature.properties.name) {
|
45
45
|
layer.bindPopup(feature.properties.name);
|
@@ -58,4 +58,4 @@ var <%= to_varname "track_", @filename %> =
|
|
58
58
|
}
|
59
59
|
*/
|
60
60
|
});
|
61
|
-
|
61
|
+
<%= to_leaflet_layername @filename %>.addTo(map);
|