geoptima 0.1.18 → 0.1.19

Sign up to get free protection for your applications and to get access to all the features.
data/CONTRIBUTORS CHANGED
@@ -2,4 +2,4 @@ Maintainer:
2
2
  Craig Taverner <craig at amanzi dot com>
3
3
 
4
4
  Contributors:
5
- *
5
+ * ... none yet ...
data/Gemfile CHANGED
@@ -1,5 +1,3 @@
1
- source :gemcutter
2
-
3
1
  gemspec
4
2
 
5
3
  group 'test' do
@@ -10,6 +8,10 @@ group 'test' do
10
8
  gem "test-unit"
11
9
  end
12
10
 
11
+ gem "multi_json", ">= 1.1.0"
12
+ gem "json_pure", ">= 1.6.5"
13
+ gem "json", ">= 1.6.5"
14
+
13
15
  #gem 'ruby-debug-base19' if RUBY_VERSION.include? "1.9"
14
16
  #gem 'ruby-debug-base' if RUBY_VERSION.include? "1.8"
15
17
  #gem "ruby-debug-ide"
data/README.rdoc CHANGED
@@ -24,10 +24,11 @@ This script imports the JSON files on the command-line and then:
24
24
 
25
25
  Which event types to include and various other options are available using the command-line. Run it with the -h option to get a full list of options. The current version should support:
26
26
 
27
- Usage: show_geoptima <-dwvpxomlsafh> <-P export_prefix> <-L limit> <-E types> <-T min,max> <-M mapfile> file <files>
27
+ Usage: show_geoptima <-dwvpxomlsafegh> <-P export_prefix> <-L limit>
28
+ <-E types> <-T min,max> <-M mapfile> file <files>
28
29
  -d debug mode (output more context during processing) (false)
29
30
  -w verbose mode (output extra information to console)
30
- -v print geoptima library version 0.1.7
31
+ -v print geoptima library version 0.1.19
31
32
  -p print mode (print out final results to console)
32
33
  -x export IMEI specific CSV files for further processing
33
34
  -o export field statistis
@@ -36,12 +37,67 @@ Which event types to include and various other options are available using the c
36
37
  -s seperate the export files by event type
37
38
  -a combine all IMEI's into a single dataset
38
39
  -f flush stdout
40
+ -e show error statistics
41
+ -g export GPX traces
42
+ -t split time colum to multiple columns
39
43
  -h show this help
40
44
  -P prefix for exported files (default: ''; current: )
41
45
  -E comma-seperated list of event types to show and export (default: all; current: )
46
+ -A application category map file (default: app names)
42
47
  -T time range to limit results to (default: all; current: )
48
+ -B location limited to specified bounds in one of these formats:
49
+ minlat,minlon,maxlat,maxlon
50
+ minlat..maxlat,minlon..maxlon
51
+ DIST(distance_in_km,lat,lon)
52
+ RANGE[minlat,minlon,maxlat,maxlon]
53
+ RANGE[minlat..maxlat,minlon..maxlon]
54
+ (default: all; current: )
43
55
  -L limit verbose output to specific number of lines (10000)
44
56
  -M mapfile of normal->altered header names:
57
+ -G GPX export options as ';' separated list of key:value pairs
58
+ Current GPX options: {"scale"=>190, "padding"=>5, "limit"=>2,
59
+ "png_limit"=>10, "points"=>true, "point_size"=>2, "point_color"=>"auto"}
60
+ -X Geolocation options as ';' separated list of key:value pairs
61
+ Current geolocation options: {"algorithm"=>"window", "window"=>60}
62
+
63
+ The GPX and Geolocation options require futher explanation:
64
+
65
+ Known supported GPX options (might be more, see data.rb code):
66
+ limit:2 Limit GPX output to traces with at least this number of events
67
+ png_limit:10 Limit PNG output to traces with at least this number of events
68
+ merge: Merge all traces into a single trace
69
+ only_merge: Do not export unmerged traces
70
+ scale:190 Size of print area in PNG output
71
+ padding:5 Space around print area
72
+ points:true Turn on/off points
73
+ point_size:2 Set point size
74
+ point_color:auto Set point color: RRGGBBAA in hex (else 'auto')
75
+ format: Export format: 'gpx', 'csv', 'png', default 'all'
76
+ waypoints: Export waypoints for events: <event_type>, default 'all'
77
+
78
+ PNG images will be 'scale + 2 * padding' big (200 for current settings).
79
+ The scale will be used for the widest dimension, and the other will be reduced
80
+ to fit the actual size of the trace. No projection is used, with the points
81
+ simply mapped to their GPS locations. This will cause visual distortions far
82
+ from the equator where dlat!=dlon.
83
+
84
+ Known supported geolocation options (might be more, see data.rb code):
85
+ algorithm:window Which geolocation algorithm to use
86
+ window:60 Time window in seconds, has slightly different
87
+ meanings for different algorithms
88
+
89
+ Currently supported algorithms:
90
+ window: select GPS point within window seconds of event,
91
+ GPS points after the event take priority.
92
+ (this is the default for geoptima GEM version >= 0.1.19)
93
+ +win: select only GPS points after event (within time window)
94
+ -win: select only GPS points before event (within time window)
95
+ (this is the default for geoptima GEM version < 0.1.19)
96
+ closest: select closest GPS point within window seconds of event
97
+ (similar to window option, but chooses closest)
98
+ interpolate: Linear interpolation between two closest points
99
+ (experimental, do not use yet)
100
+ (read redmine wiki page for explanation of algorithm)
45
101
 
46
102
  Currently the script also locates events that are close enough in time to GPS events. We hope to improve this with interpolation in the near future to be more compatible with the results from the commercial solutions. This time-window is also used for some of the extended header information, like LAC and CI, and effectively duplicates those fields from their own events to others. Take this into account when doing statistics on the results. It is better to use the original values, not the duplicates, if you want reliable statistics.
47
103
 
@@ -150,7 +206,7 @@ To get the optimized json gem installed, or to get chart support working you wil
150
206
 
151
207
  ==== Running on Windows
152
208
 
153
- The best way to run on windows is to edit your system path (usually go to 'my computer->properties->advanced->environment), and add the path to your ruby bin directory (usually C:\Ruby\bin) to the end of the system PATH. After that, open a command-prompt (start->cmd.exe) and type 'ruby -v' to see that it worked. Then you can execute the 'gem install' commands and the 'show_geoptima' commands from this console.
209
+ The best way to run on windows is to edit your system path (usually go to 'my computer->properties->advanced->environment), and add the path to your ruby bin directory (usually C:\\Ruby\\bin) to the end of the system PATH. After that, open a command-prompt (start->cmd.exe) and type 'ruby -v' to see that it worked. Then you can execute the 'gem install' commands and the 'show_geoptima' commands from this console.
154
210
 
155
211
  ==== Installing Gruff for Charting
156
212
 
data/bin/show_geoptima CHANGED
@@ -8,7 +8,7 @@ require 'date'
8
8
  require 'geoptima'
9
9
  require 'geoptima/options'
10
10
 
11
- Geoptima::assert_version(">=0.1.18")
11
+ Geoptima::assert_version(">=0.1.19")
12
12
 
13
13
  $debug=false
14
14
 
@@ -21,6 +21,18 @@ $gpx_options = {
21
21
  'points' => true, 'point_size' => 2, 'point_color' => 'auto'
22
22
  }
23
23
 
24
+ $geolocation_options = {
25
+ 'algorithm' => 'window', 'window' => 60
26
+ }
27
+
28
+ def make_hash_options(arg)
29
+ arg.split(/[\,\;]+/).inject({}) do |a,v|
30
+ k=v.split(/[\:\=]+/)
31
+ a[k[0]]=k[1]||true
32
+ a
33
+ end
34
+ end
35
+
24
36
  $files = Geoptima::Options.process_args do |option|
25
37
  option.p {$print = true}
26
38
  option.x {$export = true}
@@ -38,8 +50,9 @@ $files = Geoptima::Options.process_args do |option|
38
50
  option.B {$location_range = Geoptima::LocationRange.from ARGV.shift}
39
51
  option.L {$print_limit = [1,ARGV.shift.to_i].max}
40
52
  option.M {$mapfile = ARGV.shift}
41
- option.G {$gpx_options.merge! ARGV.shift.split(/[\,\;]+/).inject({}){|a,v| k=v.split(/[\:\=]+/);a[k[0]]=k[1]||true;a}}
53
+ option.G {$gpx_options.merge! make_hash_options(ARGV.shift)}
42
54
  option.A {$app_categories = Geoptima::AppCategories.new(ARGV.shift)}
55
+ option.X {$geolocation_options.merge! make_hash_options(ARGV.shift)}
43
56
  end.map do |file|
44
57
  File.exist?(file) ? file : puts("No such file: #{file}")
45
58
  end.compact
@@ -116,10 +129,33 @@ end
116
129
 
117
130
  exit 0 if($print_version && !$verbose)
118
131
 
132
+ class String
133
+ def wrappad(max=80,pad=8)
134
+ max = [max,pad+1].max
135
+ wrapped = [self.to_s]
136
+ while wrapped[-1].length > max
137
+ a,b = wrapped[-1][0..(max-1)],wrapped[-1][max..-1]
138
+ if (si = a.rindex(/\s+/)) && (a[0..(si-1)] =~ /\S/)
139
+ b = [a[si..-1],b].join.gsub(/^\s+/,'')
140
+ a = a[0..(si-1)]
141
+ else
142
+ a+='-'
143
+ end
144
+ a = a.gsub(/\s+$/,'')
145
+ b = b.gsub(/^\s+/,'')
146
+ wrapped[-1] = a
147
+ wrapped << [' '*pad,b].join
148
+ puts "WRAP[#{max}:#{pad}]: #{wrapped.inspect}"
149
+ end
150
+ wrapped
151
+ end
152
+ end
153
+
119
154
  $help = true if($files.length < 1)
120
155
  if $help
121
156
  puts <<EOHELP
122
- Usage: show_geoptima <-dwvpxomlsafegh> <-P export_prefix> <-L limit> <-E types> <-T min,max> <-M mapfile> file <files>
157
+ Usage: show_geoptima <-dwvpxomlsafegh> <-P export_prefix> <-L limit>
158
+ <-E types> <-T min,max> <-M mapfile> file <files>
123
159
  -d debug mode (output more context during processing) #{cw $debug}
124
160
  -w verbose mode (output extra information to console) #{cw $verbose}
125
161
  -v print geoptima library version #{Geoptima::VERSION}
@@ -149,20 +185,47 @@ Usage: show_geoptima <-dwvpxomlsafegh> <-P export_prefix> <-L limit> <-E types>
149
185
  -L limit verbose output to specific number of lines #{cw $print_limit}
150
186
  -M mapfile of normal->altered header names: #{$mapfile}
151
187
  -G GPX export options as ';' separated list of key:value pairs
152
- Current GPX options: #{$gpx_options.inspect}
153
- Known supported GPX options (might be more, see data.rb code):
154
- limit:#{$gpx_options['limit']}\t\tLimit GPX output to traces with at least this number of events
155
- png_limit:#{$gpx_options['png_limit']}\t\tLimit PNG output to traces with at least this number of events
156
- merge:#{$gpx_options['merge']}\t\tMerge all traces into a single trace
157
- only_merge:#{$gpx_options['merge']}\t\tDo not export unmerged traces
158
- scale:#{$gpx_options['scale']}\t\tSize of print area in PNG output
159
- padding:#{$gpx_options['padding']}\t\tSpace around print area
160
- points:#{$gpx_options['points']}\t\tTurn on/off points
161
- point_size:#{$gpx_options['point_size']}\t\tSet point size
162
- point_color:#{$gpx_options['point_color']}\tSet point color: RRGGBBAA in hex (else 'auto')
163
- format:#{$gpx_options['format']}\t\tExport format: 'gpx', 'csv', 'png', default 'all'
164
- waypoints:#{$gpx_options['waypoints']}\t\tExport waypoints for events: <event_type>, default 'all'
165
- PNG images will be 'scale + 2 * padding' big (#{$gpx_options['scale'].to_i+2*$gpx_options['padding'].to_i} for current settings). The scale will be used for the widest dimension, and the other will be reduced to fit the actual size of the trace. The projection used is non, with the points simply mapped to their GPS locations. This will cause visual distortions far from the equator where dlat!=dlon.
188
+ #{(' Current GPX options: '+$gpx_options.inspect).wrappad(80,6).join("\n")}
189
+ -X Geolocation options as ';' separated list of key:value pairs
190
+ #{(' Current geolocation options: '+$geolocation_options.inspect).wrappad(80,6).join("\n")}
191
+
192
+ The GPX and Geolocation options require futher explanation:
193
+
194
+ Known supported GPX options (might be more, see data.rb code):
195
+ limit:#{$gpx_options['limit']} \t Limit GPX output to traces with at least this number of events
196
+ png_limit:#{$gpx_options['png_limit']}\t Limit PNG output to traces with at least this number of events
197
+ merge:#{$gpx_options['merge']} \t Merge all traces into a single trace
198
+ only_merge:#{$gpx_options['merge']}\t Do not export unmerged traces
199
+ scale:#{$gpx_options['scale']}\t Size of print area in PNG output
200
+ padding:#{$gpx_options['padding']}\t Space around print area
201
+ points:#{$gpx_options['points']}\t Turn on/off points
202
+ point_size:#{$gpx_options['point_size']}\t Set point size
203
+ point_color:#{$gpx_options['point_color']} Set point color: RRGGBBAA in hex (else 'auto')
204
+ format:#{$gpx_options['format']} \t Export format: 'gpx', 'csv', 'png', default 'all'
205
+ waypoints:#{$gpx_options['waypoints']}\t Export waypoints for events: <event_type>, default 'all'
206
+ PNG images will be 'scale + 2 * padding' big (#{$gpx_options['scale'].to_i+2*$gpx_options['padding'].to_i} for current settings).
207
+ The scale will be used for the widest dimension, and the other will be reduced
208
+ to fit the actual size of the trace. No projection is used, with the points
209
+ simply mapped to their GPS locations. This will cause visual distortions far
210
+ from the equator where dlat!=dlon.
211
+
212
+ Known supported geolocation options (might be more, see data.rb code):
213
+ algorithm:#{$geolocation_options['algorithm']} Which geolocation algorithm to use
214
+ window:#{$geolocation_options['window']}\t Time window in seconds, has slightly different
215
+ meanings for different algorithms
216
+
217
+ Currently supported algorithms:
218
+ window: select GPS point within window seconds of event,
219
+ GPS points after the event take priority.
220
+ (this is the default for geoptima GEM version >= 0.1.19)
221
+ +win: select only GPS points after event (within time window)
222
+ -win: select only GPS points before event (within time window)
223
+ (this is the default for geoptima GEM version < 0.1.19)
224
+ closest: select closest GPS point within window seconds of event
225
+ (similar to window option, but chooses closest)
226
+ interpolate: Linear interpolation between two closest points
227
+ (experimental, do not use yet)
228
+ (read redmine wiki page for explanation of algorithm)
166
229
  EOHELP
167
230
  show_header_maps
168
231
  exit 0
@@ -171,7 +234,13 @@ end
171
234
  $verbose = $verbose || $debug
172
235
  show_header_maps if($verbose)
173
236
 
174
- $datasets = Geoptima::Dataset.make_datasets($files, :locate => true, :time_range => $time_range, :location_range => $location_range, :combine_all => $combine_all)
237
+ $datasets = Geoptima::Dataset.make_datasets($files,
238
+ :locate => true,
239
+ :time_range => $time_range,
240
+ :location_range => $location_range,
241
+ :geolocation_options => $geolocation_options,
242
+ :combine_all => $combine_all
243
+ )
175
244
 
176
245
  class Export
177
246
  attr_reader :files, :imei, :names, :headers
@@ -8,7 +8,7 @@ require 'date'
8
8
  require 'geoptima'
9
9
  require 'geoptima/options'
10
10
 
11
- Geoptima::assert_version(">=0.1.18")
11
+ Geoptima::assert_version(">=0.1.19")
12
12
 
13
13
  $debug=false
14
14
 
@@ -21,6 +21,18 @@ $gpx_options = {
21
21
  'points' => true, 'point_size' => 2, 'point_color' => 'auto'
22
22
  }
23
23
 
24
+ $geolocation_options = {
25
+ 'algorithm' => 'window', 'window' => 60
26
+ }
27
+
28
+ def make_hash_options(arg)
29
+ arg.split(/[\,\;]+/).inject({}) do |a,v|
30
+ k=v.split(/[\:\=]+/)
31
+ a[k[0]]=k[1]||true
32
+ a
33
+ end
34
+ end
35
+
24
36
  $files = Geoptima::Options.process_args do |option|
25
37
  option.p {$print = true}
26
38
  option.x {$export = true}
@@ -38,8 +50,9 @@ $files = Geoptima::Options.process_args do |option|
38
50
  option.B {$location_range = Geoptima::LocationRange.from ARGV.shift}
39
51
  option.L {$print_limit = [1,ARGV.shift.to_i].max}
40
52
  option.M {$mapfile = ARGV.shift}
41
- option.G {$gpx_options.merge! ARGV.shift.split(/[\,\;]+/).inject({}){|a,v| k=v.split(/[\:\=]+/);a[k[0]]=k[1]||true;a}}
53
+ option.G {$gpx_options.merge! make_hash_options(ARGV.shift)}
42
54
  option.A {$app_categories = Geoptima::AppCategories.new(ARGV.shift)}
55
+ option.X {$geolocation_options.merge! make_hash_options(ARGV.shift)}
43
56
  end.map do |file|
44
57
  File.exist?(file) ? file : puts("No such file: #{file}")
45
58
  end.compact
@@ -116,10 +129,33 @@ end
116
129
 
117
130
  exit 0 if($print_version && !$verbose)
118
131
 
132
+ class String
133
+ def wrappad(max=80,pad=8)
134
+ max = [max,pad+1].max
135
+ wrapped = [self.to_s]
136
+ while wrapped[-1].length > max
137
+ a,b = wrapped[-1][0..(max-1)],wrapped[-1][max..-1]
138
+ if (si = a.rindex(/\s+/)) && (a[0..(si-1)] =~ /\S/)
139
+ b = [a[si..-1],b].join.gsub(/^\s+/,'')
140
+ a = a[0..(si-1)]
141
+ else
142
+ a+='-'
143
+ end
144
+ a = a.gsub(/\s+$/,'')
145
+ b = b.gsub(/^\s+/,'')
146
+ wrapped[-1] = a
147
+ wrapped << [' '*pad,b].join
148
+ puts "WRAP[#{max}:#{pad}]: #{wrapped.inspect}"
149
+ end
150
+ wrapped
151
+ end
152
+ end
153
+
119
154
  $help = true if($files.length < 1)
120
155
  if $help
121
156
  puts <<EOHELP
122
- Usage: show_geoptima <-dwvpxomlsafegh> <-P export_prefix> <-L limit> <-E types> <-T min,max> <-M mapfile> file <files>
157
+ Usage: show_geoptima <-dwvpxomlsafegh> <-P export_prefix> <-L limit>
158
+ <-E types> <-T min,max> <-M mapfile> file <files>
123
159
  -d debug mode (output more context during processing) #{cw $debug}
124
160
  -w verbose mode (output extra information to console) #{cw $verbose}
125
161
  -v print geoptima library version #{Geoptima::VERSION}
@@ -149,20 +185,47 @@ Usage: show_geoptima <-dwvpxomlsafegh> <-P export_prefix> <-L limit> <-E types>
149
185
  -L limit verbose output to specific number of lines #{cw $print_limit}
150
186
  -M mapfile of normal->altered header names: #{$mapfile}
151
187
  -G GPX export options as ';' separated list of key:value pairs
152
- Current GPX options: #{$gpx_options.inspect}
153
- Known supported GPX options (might be more, see data.rb code):
154
- limit:#{$gpx_options['limit']}\t\tLimit GPX output to traces with at least this number of events
155
- png_limit:#{$gpx_options['png_limit']}\t\tLimit PNG output to traces with at least this number of events
156
- merge:#{$gpx_options['merge']}\t\tMerge all traces into a single trace
157
- only_merge:#{$gpx_options['merge']}\t\tDo not export unmerged traces
158
- scale:#{$gpx_options['scale']}\t\tSize of print area in PNG output
159
- padding:#{$gpx_options['padding']}\t\tSpace around print area
160
- points:#{$gpx_options['points']}\t\tTurn on/off points
161
- point_size:#{$gpx_options['point_size']}\t\tSet point size
162
- point_color:#{$gpx_options['point_color']}\tSet point color: RRGGBBAA in hex (else 'auto')
163
- format:#{$gpx_options['format']}\t\tExport format: 'gpx', 'csv', 'png', default 'all'
164
- waypoints:#{$gpx_options['waypoints']}\t\tExport waypoints for events: <event_type>, default 'all'
165
- PNG images will be 'scale + 2 * padding' big (#{$gpx_options['scale'].to_i+2*$gpx_options['padding'].to_i} for current settings). The scale will be used for the widest dimension, and the other will be reduced to fit the actual size of the trace. The projection used is non, with the points simply mapped to their GPS locations. This will cause visual distortions far from the equator where dlat!=dlon.
188
+ #{(' Current GPX options: '+$gpx_options.inspect).wrappad(80,6).join("\n")}
189
+ -X Geolocation options as ';' separated list of key:value pairs
190
+ #{(' Current geolocation options: '+$geolocation_options.inspect).wrappad(80,6).join("\n")}
191
+
192
+ The GPX and Geolocation options require futher explanation:
193
+
194
+ Known supported GPX options (might be more, see data.rb code):
195
+ limit:#{$gpx_options['limit']} \t Limit GPX output to traces with at least this number of events
196
+ png_limit:#{$gpx_options['png_limit']}\t Limit PNG output to traces with at least this number of events
197
+ merge:#{$gpx_options['merge']} \t Merge all traces into a single trace
198
+ only_merge:#{$gpx_options['merge']}\t Do not export unmerged traces
199
+ scale:#{$gpx_options['scale']}\t Size of print area in PNG output
200
+ padding:#{$gpx_options['padding']}\t Space around print area
201
+ points:#{$gpx_options['points']}\t Turn on/off points
202
+ point_size:#{$gpx_options['point_size']}\t Set point size
203
+ point_color:#{$gpx_options['point_color']} Set point color: RRGGBBAA in hex (else 'auto')
204
+ format:#{$gpx_options['format']} \t Export format: 'gpx', 'csv', 'png', default 'all'
205
+ waypoints:#{$gpx_options['waypoints']}\t Export waypoints for events: <event_type>, default 'all'
206
+ PNG images will be 'scale + 2 * padding' big (#{$gpx_options['scale'].to_i+2*$gpx_options['padding'].to_i} for current settings).
207
+ The scale will be used for the widest dimension, and the other will be reduced
208
+ to fit the actual size of the trace. No projection is used, with the points
209
+ simply mapped to their GPS locations. This will cause visual distortions far
210
+ from the equator where dlat!=dlon.
211
+
212
+ Known supported geolocation options (might be more, see data.rb code):
213
+ algorithm:#{$geolocation_options['algorithm']} Which geolocation algorithm to use
214
+ window:#{$geolocation_options['window']}\t Time window in seconds, has slightly different
215
+ meanings for different algorithms
216
+
217
+ Currently supported algorithms:
218
+ window: select GPS point within window seconds of event,
219
+ GPS points after the event take priority.
220
+ (this is the default for geoptima GEM version >= 0.1.19)
221
+ +win: select only GPS points after event (within time window)
222
+ -win: select only GPS points before event (within time window)
223
+ (this is the default for geoptima GEM version < 0.1.19)
224
+ closest: select closest GPS point within window seconds of event
225
+ (similar to window option, but chooses closest)
226
+ interpolate: Linear interpolation between two closest points
227
+ (experimental, do not use yet)
228
+ (read redmine wiki page for explanation of algorithm)
166
229
  EOHELP
167
230
  show_header_maps
168
231
  exit 0
@@ -171,7 +234,13 @@ end
171
234
  $verbose = $verbose || $debug
172
235
  show_header_maps if($verbose)
173
236
 
174
- $datasets = Geoptima::Dataset.make_datasets($files, :locate => true, :time_range => $time_range, :location_range => $location_range, :combine_all => $combine_all)
237
+ $datasets = Geoptima::Dataset.make_datasets($files,
238
+ :locate => true,
239
+ :time_range => $time_range,
240
+ :location_range => $location_range,
241
+ :geolocation_options => $geolocation_options,
242
+ :combine_all => $combine_all
243
+ )
175
244
 
176
245
  class Export
177
246
  attr_reader :files, :imei, :names, :headers
data/geoptima.gemspec CHANGED
@@ -12,13 +12,39 @@ Gem::Specification.new do |s|
12
12
  s.rubyforge_project = 'geoptima'
13
13
  s.summary = "Ruby access to Geoptima JSON files"
14
14
  s.description = <<-EOF
15
- Geoptima is a suite of applications for measuring and locating mobile/cellular subscriber experience on GPS enabled smartphones.
16
- It is produced by AmanziTel AB in Helsingborg, Sweden, and supports many phone manufacturers, with free downloads from the
17
- various app stores, markets or marketplaces. This Ruby library is only capable of reading the JSON format files priduced by these phones
18
- and reformating them as CSV for further analysis in Excel. This is a simple and independent way of analysing the data, when
19
- compared to the full-featured analysis applications and servers available from AmanziTel. If you want to analyse a limited amount
20
- of data in excel, or with Ruby, then this GEM might be for you. If you want to analyse large amounts of data, from many subscribers, or over long periods of time
21
- then rather consider the NetView and Customer IQ applications from AmanziTel at www.amanzitel.com.
15
+
16
+ Geoptima is a suite of applications for measuring and locating
17
+ mobile/cellular subscriber experience on GPS enabled smartphones. It is
18
+ produced by AmanziTel AB in Helsingborg, Sweden, and supports many phone
19
+ manufacturers, with free downloads from the various app stores, markets or
20
+ marketplaces. This Ruby library is capable of reading the JSON format files
21
+ produced by these phones and reformating them as CSV, GPX and PNG for
22
+ further analysis in Excel. This is a simple and independent way of
23
+ analysing the data, when compared to the full-featured analysis applications
24
+ and servers available from AmanziTel. If you want to analyse a limited
25
+ amount of data in excel, or with Ruby, then this GEM might be for you. If
26
+ you want to analyse large amounts of data, from many subscribers, or over
27
+ long periods of time then rather consider the NetView and Customer IQ
28
+ applications from AmanziTel at www.amanzitel.com.
29
+
30
+ Current features available in the library and the show_geoptima command:
31
+ * Import one or many JSON files
32
+ * Organize data by device id (IMEI) into datasets
33
+ * Split by event type
34
+ * Time ordering and time correlation (associate data from one event to another):
35
+ ** Add GPS locations to other events (time window and interpolation algorithms)
36
+ ** Add signal strenth, battery level, etc. to other events
37
+ * Export event tables to CSV format for further processing in excel
38
+ * Make and export GPS traces in GPX and PNG format for simple map reports
39
+
40
+ The amount of data possible to process is limited by memory, since all data
41
+ is imported in ruby data structures for procssing. If you need to process
42
+ larger amounts of data, you will need a database-driven approach, like that
43
+ provided by AmanziTel's NetView and Customer IQ solutions. This Ruby gem is
44
+ actually used by parts of the data pre-processing chain of 'Customer IQ',
45
+ but it not used by the main database and statistics engine that generates
46
+ the reports.
47
+
22
48
  EOF
23
49
 
24
50
  s.require_path = 'lib'
@@ -0,0 +1,17 @@
1
+ tcp 0 0 127.0.0.1:53748 0.0.0.0:* LISTEN
2
+ tcp 0 0 127.0.0.1:53 0.0.0.0:* LISTEN
3
+ tcp 0 0 192.168.122.1:53 0.0.0.0:* LISTEN
4
+ tcp 0 0 127.0.0.1:34678 0.0.0.0:* LISTEN
5
+ tcp 0 0 0.0.0.0:22 0.0.0.0:* LISTEN
6
+ tcp 0 0 127.0.0.1:631 0.0.0.0:* LISTEN
7
+ tcp 0 0 0.0.0.0:17500 0.0.0.0:* LISTEN
8
+ tcp 0 0 0.0.0.0:445 0.0.0.0:* LISTEN
9
+ tcp 0 0 0.0.0.0:60648 0.0.0.0:* LISTEN
10
+ tcp 0 0 0.0.0.0:139 0.0.0.0:* LISTEN
11
+ tcp6 0 0 127.0.0.1:7473 :::* LISTEN
12
+ tcp6 0 0 127.0.0.1:7474 :::* LISTEN
13
+ tcp6 0 0 :::22 :::* LISTEN
14
+ tcp6 0 0 ::1:631 :::* LISTEN
15
+ tcp6 0 0 :::3000 :::* LISTEN
16
+ tcp6 0 0 :::1337 :::* LISTEN
17
+ tcp6 0 0 :::34495 :::* LISTEN
@@ -0,0 +1,16 @@
1
+ tcp 0 0 127.0.0.1:53748 0.0.0.0:* LISTEN
2
+ tcp 0 0 127.0.0.1:53 0.0.0.0:* LISTEN
3
+ tcp 0 0 192.168.122.1:53 0.0.0.0:* LISTEN
4
+ tcp 0 0 127.0.0.1:34678 0.0.0.0:* LISTEN
5
+ tcp 0 0 0.0.0.0:22 0.0.0.0:* LISTEN
6
+ tcp 0 0 127.0.0.1:631 0.0.0.0:* LISTEN
7
+ tcp 0 0 0.0.0.0:17500 0.0.0.0:* LISTEN
8
+ tcp 0 0 0.0.0.0:445 0.0.0.0:* LISTEN
9
+ tcp 0 0 0.0.0.0:60648 0.0.0.0:* LISTEN
10
+ tcp 0 0 0.0.0.0:139 0.0.0.0:* LISTEN
11
+ tcp6 0 0 127.0.0.1:7473 :::* LISTEN
12
+ tcp6 0 0 127.0.0.1:7474 :::* LISTEN
13
+ tcp6 0 0 :::22 :::* LISTEN
14
+ tcp6 0 0 ::1:631 :::* LISTEN
15
+ tcp6 0 0 :::1337 :::* LISTEN
16
+ tcp6 0 0 :::34495 :::* LISTEN
data/lib/geoptima/data.rb CHANGED
@@ -4,6 +4,7 @@ require 'rubygems'
4
4
  require 'multi_json'
5
5
  require 'geoptima/daterange'
6
6
  require 'geoptima/locationrange'
7
+ require 'geoptima/locator'
7
8
  require 'geoptima/timer'
8
9
  begin
9
10
  require 'png'
@@ -16,8 +17,6 @@ end
16
17
  #
17
18
  module Geoptima
18
19
 
19
- SPERDAY = 60*60*24
20
- MSPERDAY = 1000*60*60*24
21
20
  SHORT = 256*256
22
21
  MIN_VALID_DATETIME = DateTime.parse("1970-01-01")
23
22
  MAX_VALID_DATETIME = DateTime.parse("2040-01-01")
@@ -484,7 +483,8 @@ module Geoptima
484
483
  }
485
484
 
486
485
  include ErrorCounter
487
- attr_reader :file, :header, :name, :data, :fields, :time, :latitude, :longitude, :timeoffset
486
+ include Locatable
487
+ attr_reader :file, :gps, :header, :name, :data, :fields, :time, :latitude, :longitude, :timeoffset
488
488
  def initialize(file,start,name,header,data,previous=nil)
489
489
  @file = file
490
490
  @name = name
@@ -553,14 +553,12 @@ module Geoptima
553
553
  def location
554
554
  @location ||= latitude && Point.new(latitude,longitude)
555
555
  end
556
- def locate(gps)
556
+ def set_location(gps)
557
557
  incr_error "GPS String Data" if(gps['latitude'].is_a? String)
558
558
  @latitude = gps['latitude'].to_f
559
559
  @longitude = gps['longitude'].to_f
560
560
  @location = nil
561
- end
562
- def locate_if_closer_than(gps,seconds=60)
563
- locate(gps) if(closer_than(gps,seconds))
561
+ @gps = gps
564
562
  end
565
563
  def puts line
566
564
  Kernel.puts "#{name}[#{time}]: #{line}"
@@ -868,6 +866,7 @@ module Geoptima
868
866
  @options = options
869
867
  @time_range = options[:time_range] || DateRange.new(Config[:min_datetime],Config[:max_datetime])
870
868
  @location_range = options[:location_range] || LocationRange.everywhere
869
+ @geolocation_options = options[:geolocation_options] || {}
871
870
  @fields = {}
872
871
  end
873
872
 
@@ -1098,20 +1097,14 @@ module Geoptima
1098
1097
  end
1099
1098
 
1100
1099
  def locate_events
1101
- prev_gps = nil
1102
- count = 0
1103
1100
  puts "Locating #{sorted.length} events" if(true||$debug)
1104
- sorted.each do |event|
1105
- timer('locate.each').start
1106
- if event.name === 'gps'
1107
- event.locate(event)
1108
- prev_gps = event
1109
- elsif prev_gps
1110
- count += 1 if(event.locate_if_closer_than(prev_gps,60))
1111
- end
1112
- timer('locate.each').stop
1101
+ locator = Geoptima::Locator.new self.sorted, @geolocation_options
1102
+ timer("locate.all").start
1103
+ locator.locate
1104
+ timer("locate.all").stop
1105
+ if (true||$debug)
1106
+ puts "Located #{locator.located.length} / #{sorted.length} events (timed: #{timer("locate.all")}"
1113
1107
  end
1114
- puts "Located #{count} / #{sorted.length} events" if($debug)
1115
1108
  end
1116
1109
 
1117
1110
  def to_s
@@ -0,0 +1,172 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'geoptima/locationrange'
4
+
5
+ module Geoptima
6
+
7
+ SPERDAY = 60*60*24
8
+ MSPERDAY = 1000*SPERDAY
9
+
10
+ class LocatorAlgorithm
11
+ def locate(locatable)
12
+ if locatable.next_point
13
+ locatable.location = locatable.next_point
14
+ elsif locatable.previous_point
15
+ locatable.location = locatable.previous_point
16
+ else
17
+ locatable.location = nil
18
+ end
19
+ end
20
+ end
21
+ class BeforeLocatorAlgorithm < LocatorAlgorithm
22
+ def locate(locatable)
23
+ if locatable.previous_point
24
+ locatable.location = locatable.previous_point
25
+ else
26
+ locatable.location = nil
27
+ end
28
+ end
29
+ end
30
+ class AfterLocatorAlgorithm < LocatorAlgorithm
31
+ def locate(locatable)
32
+ if locatable.next_point
33
+ locatable.location = locatable.next_point
34
+ else
35
+ locatable.location = nil
36
+ end
37
+ end
38
+ end
39
+ class ClosestLocatorAlgorithm < LocatorAlgorithm
40
+ def locate(locatable)
41
+ results = [
42
+ [locatable.next_point_gap,locatable.next_point],
43
+ [locatable.previous_point_gap,locatable.previous_point]
44
+ ].reject do |x|
45
+ x[0].nil? && x[1].nil?
46
+ end.sort do |a,b|
47
+ a[0] <=> b[0]
48
+ end[0]
49
+ locatable.location = results && results[1]
50
+ end
51
+ end
52
+ class InterpolationLocatorAlgorithm < ClosestLocatorAlgorithm
53
+ def locate(locatable)
54
+ if locatable.previous_poing && locatable.next_point && locatable.next_point.prev_point
55
+ correlateEvent2Point(point,wavg(point.prev,point.next,point),'interpolated');
56
+ elsif closest = super.locate(locatable)
57
+ correlateEvent2Point(point,closest,'correlated');
58
+ else
59
+ puts "No correlation possible for point: "+point
60
+ end
61
+ end
62
+ end
63
+ module Locatable
64
+ attr_accessor :previous_point, :next_point, :previous_point_gap, :next_point_gap, :location
65
+ def closer_than(gps,window=0.0)
66
+ if $debug && gps && window > 0
67
+ puts "Comparing times:"
68
+ puts "\tGPS: #{gps.time}"
69
+ puts "\tEvent: #{self.time}"
70
+ puts "\tTDiff: #{(self - gps).abs.to_f}"
71
+ puts "\tWindow: #{window}"
72
+ end
73
+ gps && (window <= 0.0 || (self - gps).abs < window)
74
+ end
75
+ def set_next_if(gps,time_window=0.0)
76
+ if closer_than(gps,time_window)
77
+ self.next_point = gps.location
78
+ self.next_point_gap = (self - gps).abs
79
+ end
80
+ end
81
+ def set_previous_if(gps,time_window=0.0)
82
+ if closer_than(gps,time_window)
83
+ self.previous_point = gps.location
84
+ self.previous_point_gap = (self - gps).abs
85
+ end
86
+ end
87
+ end
88
+ class LocatableImpl
89
+ attr_reader :name, :attributes
90
+ attr_accessor :time
91
+ include Locatable
92
+ def initialize(attributes)
93
+ @attributes = Hash[*attributes.map{|k,v| [k.to_s,v]}.flatten]
94
+ @name = @attributes['name']
95
+ @time = @attributes['time']
96
+ end
97
+ def [](key)
98
+ @attributes[key.to_s] || @attributes[key.to_s.gsub(/#{name}\./,'')]
99
+ end
100
+ def []=(key,value)
101
+ @attributes[key.to_s] = value
102
+ end
103
+ def -(other)
104
+ (self.time - other.time) * SPERDAY
105
+ end
106
+ def to_s
107
+ @attributes.inspect
108
+ end
109
+ end
110
+ class Locator
111
+ attr_reader :sorted, :located, :failed, :options
112
+ def initialize(sorted, options={})
113
+ @sorted = sorted
114
+ @options = Hash[*options.map{|k,v| [k.to_s.intern,v]}.flatten]
115
+ @options[:algorithm] ||= 'window'
116
+ @options[:window] ||= 60
117
+ puts "Initialized geo-location on #{@sorted.length} events with options: #{@options.inspect}" if($debug)
118
+ end
119
+ def start
120
+ @start ||= sorted[0] && sorted[0][:time] || DateTime.now
121
+ end
122
+ def algorithm
123
+ @algorithm ||= case @options[:algorithm].to_s
124
+ when /^\-win/
125
+ BeforeLocatorAlgorithm.new
126
+ when /^\+win/
127
+ AfterLocatorAlgorithm.new
128
+ when /closest/
129
+ ClosestLocatorAlgorithm.new
130
+ when /inter/
131
+ InterpolationLocatorAlgorithm.new
132
+ else
133
+ LocatorAlgorithm.new
134
+ end
135
+ end
136
+ def locate
137
+ gps = nil
138
+ @located = []
139
+ @failed = []
140
+ locatables = []
141
+ time_window = @options[:window].to_i
142
+ time_window = 60 if(time_window<1)
143
+ puts "Locating within window[#{time_window}] using algorithm:#{algorithm.class}" if($debug)
144
+ sorted.each do |event|
145
+ event.time ||= start + event[:timestamp].to_f / Geoptima::MSPERDAY
146
+ if event.name === 'gps'
147
+ gps = event
148
+ puts "Setting GPS location point: #{gps.inspect}" if($debug)
149
+ gps.location = Point.new(gps['latitude'].to_f, gps['longitude'].to_f)
150
+ locatables.each do |event|
151
+ event.set_next_if(gps,time_window)
152
+ end
153
+ locatables = []
154
+ else
155
+ event.set_previous_if(gps,time_window)
156
+ locatables << event
157
+ @located << event
158
+ end
159
+ end
160
+ @located = @located.map do |l|
161
+ if self.algorithm.locate(l)
162
+ l
163
+ else
164
+ @failed << l
165
+ nil
166
+ end
167
+ end.compact
168
+ end
169
+ end
170
+ end
171
+
172
+
@@ -1,6 +1,6 @@
1
1
  module Geoptima
2
2
 
3
- VERSION = "0.1.18"
3
+ VERSION = "0.1.19"
4
4
 
5
5
  class Version
6
6
  attr_reader :comparator, :version, :major, :minor, :patch
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: geoptima
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.18
4
+ version: 0.1.19
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,14 +9,14 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2013-01-07 00:00:00.000000000 Z
12
+ date: 2013-05-03 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: multi_json
16
16
  requirement: !ruby/object:Gem::Requirement
17
17
  none: false
18
18
  requirements:
19
- - - ! '>='
19
+ - - ">="
20
20
  - !ruby/object:Gem::Version
21
21
  version: 1.1.0
22
22
  type: :runtime
@@ -24,7 +24,7 @@ dependencies:
24
24
  version_requirements: !ruby/object:Gem::Requirement
25
25
  none: false
26
26
  requirements:
27
- - - ! '>='
27
+ - - ">="
28
28
  - !ruby/object:Gem::Version
29
29
  version: 1.1.0
30
30
  - !ruby/object:Gem::Dependency
@@ -32,7 +32,7 @@ dependencies:
32
32
  requirement: !ruby/object:Gem::Requirement
33
33
  none: false
34
34
  requirements:
35
- - - ! '>='
35
+ - - ">="
36
36
  - !ruby/object:Gem::Version
37
37
  version: 1.6.5
38
38
  type: :runtime
@@ -40,31 +40,43 @@ dependencies:
40
40
  version_requirements: !ruby/object:Gem::Requirement
41
41
  none: false
42
42
  requirements:
43
- - - ! '>='
43
+ - - ">="
44
44
  - !ruby/object:Gem::Version
45
45
  version: 1.6.5
46
- description: ! 'Geoptima is a suite of applications for measuring and locating mobile/cellular
47
- subscriber experience on GPS enabled smartphones.
46
+ description: |2+
48
47
 
49
- It is produced by AmanziTel AB in Helsingborg, Sweden, and supports many phone manufacturers,
50
- with free downloads from the
48
+ Geoptima is a suite of applications for measuring and locating
49
+ mobile/cellular subscriber experience on GPS enabled smartphones. It is
50
+ produced by AmanziTel AB in Helsingborg, Sweden, and supports many phone
51
+ manufacturers, with free downloads from the various app stores, markets or
52
+ marketplaces. This Ruby library is capable of reading the JSON format files
53
+ produced by these phones and reformating them as CSV, GPX and PNG for
54
+ further analysis in Excel. This is a simple and independent way of
55
+ analysing the data, when compared to the full-featured analysis applications
56
+ and servers available from AmanziTel. If you want to analyse a limited
57
+ amount of data in excel, or with Ruby, then this GEM might be for you. If
58
+ you want to analyse large amounts of data, from many subscribers, or over
59
+ long periods of time then rather consider the NetView and Customer IQ
60
+ applications from AmanziTel at www.amanzitel.com.
51
61
 
52
- various app stores, markets or marketplaces. This Ruby library is only capable of
53
- reading the JSON format files priduced by these phones
62
+ Current features available in the library and the show_geoptima command:
63
+ * Import one or many JSON files
64
+ * Organize data by device id (IMEI) into datasets
65
+ * Split by event type
66
+ * Time ordering and time correlation (associate data from one event to another):
67
+ ** Add GPS locations to other events (time window and interpolation algorithms)
68
+ ** Add signal strenth, battery level, etc. to other events
69
+ * Export event tables to CSV format for further processing in excel
70
+ * Make and export GPS traces in GPX and PNG format for simple map reports
54
71
 
55
- and reformating them as CSV for further analysis in Excel. This is a simple and
56
- independent way of analysing the data, when
72
+ The amount of data possible to process is limited by memory, since all data
73
+ is imported in ruby data structures for procssing. If you need to process
74
+ larger amounts of data, you will need a database-driven approach, like that
75
+ provided by AmanziTel's NetView and Customer IQ solutions. This Ruby gem is
76
+ actually used by parts of the data pre-processing chain of 'Customer IQ',
77
+ but it not used by the main database and statistics engine that generates
78
+ the reports.
57
79
 
58
- compared to the full-featured analysis applications and servers available from AmanziTel.
59
- If you want to analyse a limited amount
60
-
61
- of data in excel, or with Ruby, then this GEM might be for you. If you want to analyse
62
- large amounts of data, from many subscribers, or over long periods of time
63
-
64
- then rather consider the NetView and Customer IQ applications from AmanziTel at
65
- www.amanzitel.com.
66
-
67
- '
68
80
  email: craig@amanzi.com
69
81
  executables:
70
82
  - show_geoptima
@@ -90,8 +102,11 @@ files:
90
102
  - lib/geoptima/daterange.rb
91
103
  - lib/geoptima/options.rb
92
104
  - lib/geoptima/timer.rb
105
+ - lib/geoptima/before.ports
93
106
  - lib/geoptima/file_time.rb
94
107
  - lib/geoptima/locationrange.rb
108
+ - lib/geoptima/after.ports
109
+ - lib/geoptima/locator.rb
95
110
  - lib/geoptima.rb
96
111
  - examples/show_geoptima_sos.rb
97
112
  - examples/show_geoptima.rb
@@ -111,30 +126,33 @@ homepage: http://github.com/craigtaverner/geoptima.rb
111
126
  licenses: []
112
127
  post_install_message:
113
128
  rdoc_options:
114
- - --quiet
115
- - --title
129
+ - "--quiet"
130
+ - "--title"
116
131
  - Geoptima.rb
117
- - --line-numbers
118
- - --main
132
+ - "--line-numbers"
133
+ - "--main"
119
134
  - README.rdoc
120
- - --inline-source
135
+ - "--inline-source"
121
136
  require_paths:
122
137
  - lib
123
138
  required_ruby_version: !ruby/object:Gem::Requirement
124
139
  none: false
125
140
  requirements:
126
- - - ! '>='
141
+ - - ">="
127
142
  - !ruby/object:Gem::Version
128
143
  version: 1.8.6
129
144
  required_rubygems_version: !ruby/object:Gem::Requirement
130
145
  none: false
131
146
  requirements:
132
- - - ! '>='
147
+ - - ">="
133
148
  - !ruby/object:Gem::Version
134
149
  version: '0'
150
+ segments:
151
+ - 0
152
+ hash: 909654323
135
153
  requirements: []
136
154
  rubyforge_project: geoptima
137
- rubygems_version: 1.8.24
155
+ rubygems_version: 1.8.25
138
156
  signing_key:
139
157
  specification_version: 3
140
158
  summary: Ruby access to Geoptima JSON files