gooby 1.0.0 → 1.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.
- data/README +144 -180
- data/bin/example_usage.txt +55 -0
- data/bin/gooby_been_there.rb +35 -0
- data/bin/gooby_config.rb +16 -0
- data/bin/gooby_gen_gmap.rb +16 -0
- data/bin/gooby_parser.rb +19 -0
- data/bin/gooby_splitter.rb +18 -0
- data/bin/gooby_version.rb +16 -0
- data/bin/run_all.sh +23 -0
- data/bin/run_been_there.sh +16 -0
- data/bin/run_db_gen.sh +11 -0
- data/bin/run_db_load.sh +11 -0
- data/bin/run_gen_gmaps.sh +20 -0
- data/bin/run_parse.sh +43 -0
- data/bin/run_parse_named.sh +19 -0
- data/bin/run_split.sh +23 -0
- data/config/gooby_config.yaml +137 -0
- data/data/20050305_corporate_cup_hm.csv +251 -251
- data/data/20050430_nashville_marathon.csv +1208 -1208
- data/data/20060115_phoenix_marathon.csv +1280 -1280
- data/data/davidson_11m_20070101.csv +251 -0
- data/data/davidson_11m_20070101.xml +2020 -0
- data/data/davidson_5K_20070505.csv +286 -0
- data/data/davidson_5K_20070505.xml +2875 -0
- data/lib/gooby.rb +889 -361
- data/samples/20050305_corporate_cup_hm.html +270 -270
- data/samples/20050430_nashville_marathon.html +1240 -1240
- data/samples/20060115_phoenix_marathon.html +1312 -1312
- data/samples/been_there.txt +744 -0
- data/samples/davidson_11m_20070101.html +432 -0
- data/samples/davidson_5K_20070505.html +395 -0
- data/sql/gooby.ddl +56 -0
- data/sql/gooby_load.dml +35 -0
- metadata +30 -32
- data/bin/20050305_corporate_cup_hm_to_csv.rb +0 -9
- data/bin/20050430_nashville_marathon_to_csv.rb +0 -9
- data/bin/20060115_phoenix_marathon_to_csv.rb +0 -9
- data/bin/activity_2007_03_10_13_02_32.xml_to_csv.rb +0 -9
- data/bin/example_usage.rb +0 -46
- data/bin/example_usage.sh +0 -52
- data/bin/gen_gap_phx.rb +0 -10
- data/bin/gen_gmap_cc_2005.rb +0 -10
- data/bin/gen_gmap_cc_2007.rb +0 -10
- data/bin/gen_gmap_nashville.rb +0 -10
- data/bin/gen_gmap_phx.rb +0 -10
- data/bin/phx_to_csv.rb +0 -47
- data/bin/split_forerunner_logbook_2007.rb +0 -10
- data/bin/split_training_center_2007.rb +0 -8
- data/data/2007_03_10.tcx +0 -28445
- data/data/activity_2007_03_10_13_02_32.csv +0 -1168
- data/data/activity_2007_03_10_13_02_32.xml +0 -11695
- data/data/forerunner_2007.xml +0 -31872
- data/data/geo_data.txt +0 -171
- data/pkg/code_header.txt +0 -21
- data/pkg/pkg.rb +0 -238
- data/pkg/test_header.txt +0 -19
- data/samples/20070310_corporate_cup_hm.html +0 -1367
- data/samples/gps_point_capture.html +0 -54
- data/samples/phoenix_marathon.html +0 -1596
- data/tests/ts_gooby.rb +0 -1109
- data/tests/ts_gooby_min.rb +0 -550
data/lib/gooby.rb
CHANGED
@@ -6,36 +6,41 @@ This file contains the classes and modules for the Gooby project.
|
|
6
6
|
See file 'tests/ts_gooby.rb' for the regression test suite.
|
7
7
|
|
8
8
|
Index of Modules and Classes in this file:
|
9
|
-
line type Module or Class name
|
10
|
-
---- ------ ---------------------------
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
9
|
+
line type Module or Class name
|
10
|
+
---- ------ ---------------------------
|
11
|
+
57 module Gooby
|
12
|
+
64 module GoobyKernel
|
13
|
+
191 module TestHelper
|
14
|
+
209 class GoobyObject
|
15
|
+
222 class CounterHash
|
16
|
+
305 class DelimLine
|
17
|
+
340 class DtTm
|
18
|
+
417 class Duration
|
19
|
+
496 class ForerunnerXmlParser
|
20
|
+
665 class ForerunnerXmlSplitter
|
21
|
+
775 class TrainingCenterXmlParser
|
22
|
+
962 class TrainingCenterXmlSplitter
|
23
|
+
1067 class GeoData
|
24
|
+
1250 class GoogleMapGenerator
|
25
|
+
1625 class History
|
26
|
+
1656 class Lap
|
27
|
+
1671 class Line
|
28
|
+
1749 class Configuration
|
29
|
+
1848 class Point
|
30
|
+
1987 class CsvPoint
|
31
|
+
2042 class CvsRun
|
32
|
+
2060 class CsvReader
|
33
|
+
2121 class Trackpoint
|
34
|
+
2319 class Run
|
35
|
+
2521 class SimpleXmlParser
|
36
|
+
2561 class Track
|
37
|
+
2593 class Course
|
38
|
+
2713 class CodeScanner
|
39
|
+
3003 class GoobyCommand
|
36
40
|
|
37
41
|
Gooby - Copyright 2007 by Chris Joakim.
|
38
42
|
Gooby is available under GNU General Public License (GPL) license.
|
43
|
+
|
39
44
|
=end
|
40
45
|
|
41
46
|
require 'date'
|
@@ -43,6 +48,7 @@ require 'find'
|
|
43
48
|
require 'rbconfig'
|
44
49
|
require 'rexml/document'
|
45
50
|
require 'rexml/streamlistener'
|
51
|
+
require 'singleton'
|
46
52
|
require 'time'
|
47
53
|
require 'yaml'
|
48
54
|
|
@@ -57,19 +63,19 @@ module Gooby
|
|
57
63
|
|
58
64
|
module GoobyKernel
|
59
65
|
|
60
|
-
# Return a String version number, like '1.
|
66
|
+
# Return a String version number, like '1.1.0'.
|
61
67
|
|
62
68
|
def project_name
|
63
69
|
'Gooby'
|
64
70
|
end
|
65
71
|
|
66
72
|
def project_version_number
|
67
|
-
'1.
|
73
|
+
'1.1.0'
|
68
74
|
end
|
69
75
|
|
70
76
|
# Return a String date, like '2007/03/21'.
|
71
77
|
def project_date
|
72
|
-
'2007/
|
78
|
+
'2007/06/10'
|
73
79
|
end
|
74
80
|
|
75
81
|
# Return a String containing the project author name.
|
@@ -372,10 +378,10 @@ module Gooby
|
|
372
378
|
@time.strftime("%Y-%m-%d")
|
373
379
|
end
|
374
380
|
|
375
|
-
def yyyy_mm_dd_hh_mm_ss
|
376
|
-
@time.strftime("%Y-%m-%d
|
381
|
+
def yyyy_mm_dd_hh_mm_ss(delim=' ')
|
382
|
+
@time.strftime("%Y-%m-%d#{delim}%H:%M:%S")
|
377
383
|
end
|
378
|
-
|
384
|
+
|
379
385
|
def hh_mm_ss
|
380
386
|
@time.strftime("%H:%M:%S")
|
381
387
|
end
|
@@ -386,7 +392,7 @@ module Gooby
|
|
386
392
|
t = @time - (anotherDtTm.to_i)
|
387
393
|
t.strftime("%H:%M:%S")
|
388
394
|
else
|
389
|
-
'
|
395
|
+
'00:00:00'
|
390
396
|
end
|
391
397
|
end
|
392
398
|
|
@@ -527,6 +533,7 @@ module Gooby
|
|
527
533
|
@run_count = @run_count + 1
|
528
534
|
@lap_count = 0
|
529
535
|
@track_count = 0
|
536
|
+
@trackpoint_count = 0
|
530
537
|
@curr_run = Run.new(@run_count)
|
531
538
|
@history.add_run(@curr_run)
|
532
539
|
@cv_hash['Notes'] = ''
|
@@ -542,7 +549,6 @@ module Gooby
|
|
542
549
|
if is_tag?('Track', tagname)
|
543
550
|
@track_count = @track_count + 1
|
544
551
|
@curr_track = Track.new(@track_count)
|
545
|
-
@trackpoint_count = 0
|
546
552
|
return
|
547
553
|
end
|
548
554
|
end
|
@@ -555,20 +561,20 @@ module Gooby
|
|
555
561
|
if is_tag?('Position', tagname)
|
556
562
|
lat = @cv_hash['Latitude']
|
557
563
|
long = @cv_hash['Longitude']
|
558
|
-
@curr_begin_position =
|
559
|
-
@@curr_end_position
|
564
|
+
@curr_begin_position = Point.new(lat.strip, long.strip)
|
565
|
+
@@curr_end_position = Point.new(lat.strip, long.strip)
|
560
566
|
end
|
561
567
|
|
562
568
|
if is_tag?('BeginPosition', tagname)
|
563
569
|
lat = @cv_hash['Latitude']
|
564
570
|
long = @cv_hash['Longitude']
|
565
|
-
@curr_begin_position =
|
571
|
+
@curr_begin_position = Point.new(lat.strip, long.strip)
|
566
572
|
end
|
567
573
|
|
568
574
|
if is_tag?('EndPosition', tagname)
|
569
575
|
lat = @cv_hash['Latitude']
|
570
576
|
long = @cv_hash['Longitude']
|
571
|
-
@@curr_end_position =
|
577
|
+
@@curr_end_position = Point.new(lat.strip, long.strip)
|
572
578
|
end
|
573
579
|
|
574
580
|
if is_tag?('Trackpoint', tagname)
|
@@ -576,7 +582,7 @@ module Gooby
|
|
576
582
|
lat = @cv_hash['Latitude']
|
577
583
|
long = @cv_hash['Longitude']
|
578
584
|
alt = @cv_hash['Altitude']
|
579
|
-
time = @cv_hash['Time']
|
585
|
+
time = @cv_hash['Time']
|
580
586
|
tp = Trackpoint.new(@trackpoint_count, lat, long, alt, time)
|
581
587
|
@curr_track.add_trackpoint(tp)
|
582
588
|
end
|
@@ -629,10 +635,8 @@ module Gooby
|
|
629
635
|
end
|
630
636
|
|
631
637
|
# Iterate all parsed Run objects and print each with put_tkpt_csv.
|
632
|
-
def put_all_run_tkpt_csv(
|
633
|
-
@history.runs.each { |run|
|
634
|
-
run.put_tkpt_csv(with_header_comment)
|
635
|
-
}
|
638
|
+
def put_all_run_tkpt_csv()
|
639
|
+
@history.runs.each { |run| run.put_tkpt_csv() }
|
636
640
|
end
|
637
641
|
|
638
642
|
private
|
@@ -760,7 +764,7 @@ module Gooby
|
|
760
764
|
# =============================================================================
|
761
765
|
|
762
766
|
=begin rdoc
|
763
|
-
Instances of this class are used to parse a Garmin TrainingCenter XML file
|
767
|
+
Instances of this class are used to parse a Garmin TrainingCenter XML(TCX) file
|
764
768
|
in a SAX-like manner. Instances of the model classes - History, Run, Track,
|
765
769
|
Trackpoint, etc. are created in this parsing process.
|
766
770
|
|
@@ -779,19 +783,21 @@ module Gooby
|
|
779
783
|
attr_reader :history, :cvHash, :tagCount
|
780
784
|
|
781
785
|
def initialize
|
782
|
-
@cv_hash
|
783
|
-
@tag_count
|
784
|
-
@run_count
|
785
|
-
@lap_count
|
786
|
-
@track_count
|
787
|
-
@trackpoint_count
|
788
|
-
@curr_text
|
789
|
-
@history
|
790
|
-
@curr_run
|
791
|
-
@curr_lap
|
792
|
-
@curr_track
|
793
|
-
@curr_begin_position
|
794
|
-
@@curr_end_position
|
786
|
+
@cv_hash = Hash.new("")
|
787
|
+
@tag_count = 0
|
788
|
+
@run_count = 0
|
789
|
+
@lap_count = 0
|
790
|
+
@track_count = 0
|
791
|
+
@trackpoint_count = 0
|
792
|
+
@curr_text = "";
|
793
|
+
@history = History.new
|
794
|
+
@curr_run = nil
|
795
|
+
@curr_lap = nil
|
796
|
+
@curr_track = nil
|
797
|
+
@curr_begin_position = nil
|
798
|
+
@@curr_end_position = nil
|
799
|
+
@first_lap_start_time = nil
|
800
|
+
@curr_lap_start_time = ''
|
795
801
|
end
|
796
802
|
|
797
803
|
public
|
@@ -810,6 +816,7 @@ module Gooby
|
|
810
816
|
@run_count = @run_count + 1
|
811
817
|
@lap_count = 0
|
812
818
|
@track_count = 0
|
819
|
+
@trackpoint_count = 0
|
813
820
|
@curr_run = Run.new(@run_count)
|
814
821
|
@history.add_run(@curr_run)
|
815
822
|
@cv_hash['Notes'] = ''
|
@@ -817,16 +824,26 @@ module Gooby
|
|
817
824
|
end
|
818
825
|
|
819
826
|
if is_tag?('Lap', tagname)
|
820
|
-
@lap_count =
|
827
|
+
@lap_count = @lap_count + 1
|
821
828
|
@curr_lap = Lap.new(@lap_count)
|
822
|
-
|
829
|
+
|
830
|
+
attrs.each { |attr|
|
831
|
+
name = attr[0]
|
832
|
+
val = attr[1]
|
833
|
+
if (name && (name == 'StartTime'))
|
834
|
+
if (@first_lap_start_time == nil)
|
835
|
+
@first_lap_start_time = "#{val}"
|
836
|
+
end
|
837
|
+
@curr_lap_start_time = "#{val}"
|
838
|
+
end
|
839
|
+
}
|
840
|
+
# TODO - capture value of 'StartTime' attribute.
|
823
841
|
return
|
824
842
|
end
|
825
843
|
|
826
844
|
if is_tag?('Track', tagname)
|
827
845
|
@track_count = @track_count + 1
|
828
846
|
@curr_track = Track.new(@track_count)
|
829
|
-
@trackpoint_count = 0
|
830
847
|
return
|
831
848
|
end
|
832
849
|
|
@@ -840,20 +857,20 @@ module Gooby
|
|
840
857
|
if is_tag?('Position', tagname)
|
841
858
|
lat = @cv_hash['LatitudeDegrees']
|
842
859
|
long = @cv_hash['LongitudeDegrees']
|
843
|
-
@curr_begin_position =
|
844
|
-
@@curr_end_position
|
860
|
+
@curr_begin_position = Point.new(lat.strip, long.strip)
|
861
|
+
@@curr_end_position = Point.new(lat.strip, long.strip)
|
845
862
|
end
|
846
863
|
|
847
864
|
if is_tag?('BeginPosition', tagname)
|
848
865
|
lat = @cv_hash['LatitudeDegrees']
|
849
866
|
long = @cv_hash['LongitudeDegrees']
|
850
|
-
@curr_begin_position =
|
867
|
+
@curr_begin_position = Point.new(lat.strip, long.strip)
|
851
868
|
end
|
852
869
|
|
853
870
|
if is_tag?('EndPosition', tagname)
|
854
871
|
lat = @cv_hash['LatitudeDegrees']
|
855
872
|
long = @cv_hash['LongitudeDegrees']
|
856
|
-
@@curr_end_position =
|
873
|
+
@@curr_end_position = Point.new(lat.strip, long.strip)
|
857
874
|
end
|
858
875
|
|
859
876
|
if is_tag?('Trackpoint', tagname)
|
@@ -861,8 +878,14 @@ module Gooby
|
|
861
878
|
lat = @cv_hash['LatitudeDegrees']
|
862
879
|
long = @cv_hash['LongitudeDegrees']
|
863
880
|
alt = @cv_hash['AltitudeMeters']
|
864
|
-
time = @cv_hash['Time']
|
865
|
-
|
881
|
+
time = @cv_hash['Time']
|
882
|
+
|
883
|
+
hash = Hash.new('')
|
884
|
+
hash['lap_number'] = "#{@lap_count}"
|
885
|
+
hash['first_lap_start_time'] = "#{@first_lap_start_time}"
|
886
|
+
hash['curr_lap_start_time'] = "#{@curr_lap_start_time}"
|
887
|
+
|
888
|
+
tp = Trackpoint.new(@trackpoint_count, lat, long, alt, time, hash)
|
866
889
|
@curr_track.add_trackpoint(tp)
|
867
890
|
end
|
868
891
|
|
@@ -872,14 +895,7 @@ module Gooby
|
|
872
895
|
end
|
873
896
|
end
|
874
897
|
|
875
|
-
if is_tag?('Lap', tagname)
|
876
|
-
# TotalTimeSeconds DistanceMeters
|
877
|
-
# TODO - rework tnd of Lap for tcx
|
878
|
-
# @curr_lap.startTime = @cv_hash['StartTime']
|
879
|
-
# @curr_lap.duration = Duration.new(@cv_hash['Duration'])
|
880
|
-
# @curr_lap.length = @cv_hash['Length']
|
881
|
-
# @curr_lap.begin_position = @curr_begin_position
|
882
|
-
# @curr_lap.end_position = @@curr_end_position
|
898
|
+
if is_tag?('Lap', tagname)
|
883
899
|
@curr_run.add_lap(@curr_lap)
|
884
900
|
end
|
885
901
|
|
@@ -916,10 +932,8 @@ module Gooby
|
|
916
932
|
end
|
917
933
|
|
918
934
|
# Iterate all parsed Run objects and print each with put_tkpt_csv.
|
919
|
-
def put_all_run_tkpt_csv(
|
920
|
-
@history.runs.each { |run|
|
921
|
-
run.put_tkpt_csv(with_header_comment)
|
922
|
-
}
|
935
|
+
def put_all_run_tkpt_csv()
|
936
|
+
@history.runs.each { |run| run.put_tkpt_csv() }
|
923
937
|
end
|
924
938
|
|
925
939
|
private
|
@@ -1243,7 +1257,10 @@ module Gooby
|
|
1243
1257
|
# 1 | 2006-01-15T18:31:10Z | 1279 | 33.42601 | -111.92927 | 347.654 | 26.3514930151813
|
1244
1258
|
# 1 | 2004-11-13T13:05:20Z | 2 | 37.54318 | -77.43636 | -58.022 | 0.00297286231747969
|
1245
1259
|
|
1246
|
-
|
1260
|
+
# primary_key|run_id|date|time|tkpt_num|latitude|longitude|altitude_ft|run_distance|run_elapsed|lap_tkpt_number|lap_distance|lap_elapsed
|
1261
|
+
# 2005-03-05T13:00:29Z.2|2005-03-05T13:00:29Z|2005-03-05|13:00:49|2|35.22054|-80.84506|738.4161312|0.046918021941152|00:00:20|2|0.046918021941152|00:00:20
|
1262
|
+
|
1263
|
+
def initialize(csv_file, dttm_idx=1, num_idx=4, lat_idx=5, lng_idx=6, alt_idx=7, cdist_idx=8)
|
1247
1264
|
@csv_file = csv_file
|
1248
1265
|
@dttm_idx = dttm_idx
|
1249
1266
|
@num_idx = num_idx
|
@@ -1251,30 +1268,31 @@ module Gooby
|
|
1251
1268
|
@lng_idx = lng_idx
|
1252
1269
|
@alt_idx = alt_idx
|
1253
1270
|
@cdist_idx = cdist_idx
|
1254
|
-
|
1255
|
-
# Override default csv value indices if specified in the
|
1256
|
-
@
|
1257
|
-
@dttm_idx = @
|
1258
|
-
@num_idx = @
|
1259
|
-
@lat_idx = @
|
1260
|
-
@lng_idx = @
|
1261
|
-
@alt_idx = @
|
1262
|
-
@title = @
|
1271
|
+
|
1272
|
+
# Override default csv value indices if specified in the configuration yaml file.
|
1273
|
+
@configuration = Gooby::Configuration.get_config
|
1274
|
+
@dttm_idx = @configuration.get('csv_dttm_idx') if @configuration.get('csv_dttm_idx')
|
1275
|
+
@num_idx = @configuration.get('csv_num_idx') if @configuration.get('csv_num_idx')
|
1276
|
+
@lat_idx = @configuration.get('csv_lat_idx') if @configuration.get('csv_lat_idx')
|
1277
|
+
@lng_idx = @configuration.get('csv_lng_idx') if @configuration.get('csv_lng_idx')
|
1278
|
+
@alt_idx = @configuration.get('csv_alt_idx') if @configuration.get('csv_alt_idx')
|
1279
|
+
@title = @configuration.get("#{@csv_file}")
|
1263
1280
|
|
1264
1281
|
@content_hash = Hash.new('')
|
1265
1282
|
@run = Gooby::Run.new(1)
|
1266
1283
|
@track = Gooby::Track.new(1)
|
1267
1284
|
@run.add_track(@track)
|
1268
1285
|
@tkpts = Array.new
|
1269
|
-
@icon_url_base = @
|
1270
|
-
|
1271
|
-
|
1272
|
-
|
1273
|
-
|
1274
|
-
|
1275
|
-
|
1276
|
-
|
1277
|
-
|
1286
|
+
@icon_url_base = @configuration.get('gmap_icon_url_base')
|
1287
|
+
|
1288
|
+
list = Array.new
|
1289
|
+
list << @csv_file
|
1290
|
+
@cvs_reader = Gooby::CsvReader.new(list)
|
1291
|
+
@cvs_points = @cvs_reader.read
|
1292
|
+
@cvs_points.each { |cvs_point|
|
1293
|
+
tkpt = cvs_point.as_trackpoint
|
1294
|
+
if tkpt
|
1295
|
+
@track.add_trackpoint(tkpt)
|
1278
1296
|
end
|
1279
1297
|
}
|
1280
1298
|
@run.finish
|
@@ -1283,15 +1301,15 @@ module Gooby
|
|
1283
1301
|
=begin
|
1284
1302
|
Returns a Hash with specific generated content at the following keys:
|
1285
1303
|
=end
|
1286
|
-
def generate(
|
1287
|
-
if (
|
1288
|
-
@
|
1304
|
+
def generate(configuration)
|
1305
|
+
if (configuration == nil)
|
1306
|
+
@configuration = Gooby::Configuration.get_config
|
1289
1307
|
else
|
1290
|
-
@
|
1308
|
+
@configuration = configuration
|
1291
1309
|
end
|
1292
1310
|
@content_hash['when_generated'] = Time.now
|
1293
1311
|
@content_hash['title'] = @title
|
1294
|
-
@icon_url_base = @
|
1312
|
+
@icon_url_base = @configuration.get('gmap_icon_url_base')
|
1295
1313
|
filter_trackpoints
|
1296
1314
|
compute_center_point
|
1297
1315
|
generate_key_js
|
@@ -1307,8 +1325,8 @@ Returns a Hash with specific generated content at the following keys:
|
|
1307
1325
|
|
1308
1326
|
def filter_trackpoints
|
1309
1327
|
count, @tkpts = 0, Array.new
|
1310
|
-
firstTkpt = @
|
1311
|
-
lastTkpt = @
|
1328
|
+
firstTkpt = @configuration.get('gmap_first_tkpt_number')
|
1329
|
+
lastTkpt = @configuration.get('gmap_last_tkpt_number')
|
1312
1330
|
@run.tracks.each { |trk|
|
1313
1331
|
trk.trackpoints.each { |tkpt|
|
1314
1332
|
count = count + 1
|
@@ -1322,7 +1340,7 @@ Returns a Hash with specific generated content at the following keys:
|
|
1322
1340
|
=begin
|
1323
1341
|
Returns a Hash with specific generated content at the following keys:
|
1324
1342
|
=end
|
1325
|
-
def generate_page(
|
1343
|
+
def generate_page(configuration)
|
1326
1344
|
|
1327
1345
|
# puts "generate_page #{@csv_file} #{@csv_lines.size}"
|
1328
1346
|
content_hash = generate(nil)
|
@@ -1381,18 +1399,19 @@ HERE
|
|
1381
1399
|
end
|
1382
1400
|
|
1383
1401
|
def generate_key_js
|
1384
|
-
key = @
|
1402
|
+
key = @configuration.get('gmap_key')
|
1385
1403
|
key.strip!
|
1386
|
-
|
1404
|
+
# <script src="http://maps.google.com/maps?file=api&v=2&key=<%= @gmap_key -%>" type="text/javascript"></script>
|
1405
|
+
s = "<script src='http://maps.google.com/maps?file=api&v=2&key="
|
1387
1406
|
s << key
|
1388
|
-
s << '
|
1407
|
+
s << "' type='text/javascript'></script>"
|
1389
1408
|
@content_hash['key_js'] = s
|
1390
1409
|
end
|
1391
1410
|
|
1392
1411
|
def generate_map_div
|
1393
|
-
width = @
|
1394
|
-
height = @
|
1395
|
-
id = @
|
1412
|
+
width = @configuration.get('gmap_width')
|
1413
|
+
height = @configuration.get('gmap_height')
|
1414
|
+
id = @configuration.get('gmap_map_element_id')
|
1396
1415
|
s = '<div id="'
|
1397
1416
|
s << id
|
1398
1417
|
s << '" style="width: '
|
@@ -1411,13 +1430,13 @@ HERE
|
|
1411
1430
|
end
|
1412
1431
|
|
1413
1432
|
def generate_main_js_start
|
1414
|
-
id = @
|
1415
|
-
size = @
|
1416
|
-
type = @
|
1417
|
-
zoom = @
|
1418
|
-
title = @
|
1433
|
+
id = @configuration.get('gmap_map_element_id')
|
1434
|
+
size = @configuration.get('gmap_size_control')
|
1435
|
+
type = @configuration.get('gmap_type')
|
1436
|
+
zoom = @configuration.get('gmap_zoom_level')
|
1437
|
+
title = @configuration.get("#{@csv_file}")
|
1419
1438
|
title = '' if title == nil
|
1420
|
-
zoom_tab = @
|
1439
|
+
zoom_tab = @configuration.get('gmap_zoom_tab')
|
1421
1440
|
if size
|
1422
1441
|
if size == 'smallmap'
|
1423
1442
|
size = 'GSmallMapControl'
|
@@ -1474,8 +1493,8 @@ HERE
|
|
1474
1493
|
|
1475
1494
|
def generate_main_js_route_overlay
|
1476
1495
|
tkpt_count = @tkpts.size.to_f
|
1477
|
-
app_max = @
|
1478
|
-
gen_comments = @
|
1496
|
+
app_max = @configuration.get('gmap_approx_max_points').to_f
|
1497
|
+
gen_comments = @configuration.get('gmap_gen_comments')
|
1479
1498
|
ratio = tkpt_count / app_max
|
1480
1499
|
@start_dttm = nil
|
1481
1500
|
if ratio > 1.0
|
@@ -1489,7 +1508,8 @@ HERE
|
|
1489
1508
|
curr_idx = curr_idx + 1
|
1490
1509
|
if curr_idx == 0
|
1491
1510
|
@start_dttm = tkpt.dttm
|
1492
|
-
@start_pos = tkpt.
|
1511
|
+
@start_pos = tkpt.point
|
1512
|
+
|
1493
1513
|
time = Time.parse(@start_dttm.dateTime().to_s)
|
1494
1514
|
end
|
1495
1515
|
if ((curr_idx == next_idx) || (curr_idx == last_idx) || (tkpt.is_split()))
|
@@ -1717,28 +1737,42 @@ HERE
|
|
1717
1737
|
end
|
1718
1738
|
|
1719
1739
|
# =============================================================================
|
1740
|
+
=begin
|
1720
1741
|
|
1721
|
-
|
1722
|
-
|
1723
|
-
|
1742
|
+
This is a singleton class whose values are loaded from a YAML file when your
|
1743
|
+
GoobyCommand class is created. The default filename is 'gooby_config.yaml"'.
|
1744
|
+
|
1745
|
+
The YAML file contains configuration parameters, such as your Google Map key,
|
1746
|
+
map HTML options, points of interest, and courses.
|
1747
|
+
|
1748
|
+
=end
|
1749
|
+
class Configuration < GoobyObject
|
1750
|
+
|
1751
|
+
@@singleton_instance = nil
|
1752
|
+
|
1753
|
+
attr_reader :yaml_filename, :configuration
|
1724
1754
|
|
1725
|
-
|
1726
|
-
|
1727
|
-
|
1755
|
+
private_class_method :new
|
1756
|
+
|
1757
|
+
def Configuration.init(yaml_filename='gooby_config.yaml')
|
1758
|
+
return @@singleton_instance if @@singleton_instance
|
1759
|
+
@@singleton_instance = new(yaml_filename)
|
1728
1760
|
end
|
1729
|
-
|
1730
|
-
|
1731
|
-
|
1732
|
-
|
1733
|
-
|
1734
|
-
|
1761
|
+
|
1762
|
+
def self.get_config
|
1763
|
+
@@singleton_instance
|
1764
|
+
end
|
1765
|
+
|
1766
|
+
def initialize(yaml_filename)
|
1767
|
+
@yaml_filename = yaml_filename
|
1768
|
+
File.open("#{@yaml_filename}") { |fn| @configuration = YAML::load(fn) }
|
1735
1769
|
end
|
1736
1770
|
|
1737
1771
|
def get(name)
|
1738
1772
|
if name == nil
|
1739
1773
|
return ''
|
1740
1774
|
end
|
1741
|
-
s = @
|
1775
|
+
s = @configuration["#{name}"]
|
1742
1776
|
|
1743
1777
|
# Provide "sensible defaults".
|
1744
1778
|
if s == nil
|
@@ -1774,44 +1808,102 @@ HERE
|
|
1774
1808
|
end
|
1775
1809
|
s
|
1776
1810
|
end
|
1811
|
+
|
1812
|
+
def print_all
|
1813
|
+
@configuration.keys.sort.each { |key| puts "#{key}: #{@configuration["#{key}"]}" }
|
1814
|
+
end
|
1815
|
+
|
1816
|
+
def print_all_poi
|
1817
|
+
@configuration.keys.sort.each { |key|
|
1818
|
+
if (key.match(/poi[\.]/))
|
1819
|
+
val = @configuration["#{key}"]
|
1820
|
+
poi = Point.new(val)
|
1821
|
+
puts poi.to_s
|
1822
|
+
end
|
1823
|
+
}
|
1824
|
+
end
|
1825
|
+
|
1826
|
+
def get_poi(number)
|
1827
|
+
val = @configuration["poi.#{number}"]
|
1828
|
+
(val) ? Point.new(val) : nil
|
1829
|
+
end
|
1830
|
+
|
1831
|
+
def get_course(number)
|
1832
|
+
val = @configuration["course.#{number}"]
|
1833
|
+
(val) ? Course.new(val) : nil
|
1834
|
+
end
|
1777
1835
|
|
1778
1836
|
def size
|
1779
|
-
@
|
1837
|
+
@configuration.size
|
1780
1838
|
end
|
1781
1839
|
|
1782
1840
|
# Return a String containing yaml filename and entry count.
|
1783
1841
|
def to_s
|
1784
|
-
return "
|
1842
|
+
return "# Configuration: filename: #{@yaml_filename} entries: #{@configuration.size}"
|
1785
1843
|
end
|
1786
1844
|
end
|
1787
1845
|
|
1788
1846
|
# =============================================================================
|
1789
|
-
|
1790
|
-
=begin rdoc
|
1791
|
-
Instances of this class represent a <Position> aggregate object from a
|
1792
|
-
Forerunner XML file. Each contains a latitude and longitude.
|
1793
|
-
Instances within a Trackpoint will also contain an altitude.
|
1794
|
-
=end
|
1795
1847
|
|
1796
|
-
class
|
1848
|
+
class Point < GoobyObject
|
1797
1849
|
|
1798
|
-
attr_accessor :latitude, :longitude, :altitude, :note
|
1850
|
+
attr_accessor :number, :latitude, :longitude, :altitude, :note
|
1799
1851
|
|
1800
|
-
def initialize(
|
1801
|
-
@latitude
|
1802
|
-
|
1803
|
-
|
1804
|
-
|
1852
|
+
def initialize(*args)
|
1853
|
+
@number, @latitude, @longitude, @altitude, @note = '', '', '', '', ''
|
1854
|
+
if args
|
1855
|
+
if args.size == 1
|
1856
|
+
initialize_from_string(args[0]) # yaml
|
1857
|
+
else
|
1858
|
+
initialize_from_array(args)
|
1859
|
+
end
|
1860
|
+
end
|
1805
1861
|
end
|
1806
|
-
|
1862
|
+
|
1863
|
+
def csv_delim
|
1864
|
+
'|'
|
1865
|
+
end
|
1866
|
+
|
1867
|
+
def initialize_from_array(args)
|
1868
|
+
@latitude = args[0] if args.size > 0
|
1869
|
+
@longitude = args[1] if args.size > 1
|
1870
|
+
@altitude = args[2] if args.size > 2
|
1871
|
+
@note = args[3] if args.size > 3
|
1872
|
+
end
|
1873
|
+
|
1874
|
+
def initialize_from_string(yaml_value_string)
|
1875
|
+
tokens = yaml_value_string.split
|
1876
|
+
if (tokens.size > 2)
|
1877
|
+
@latitude = tokens[0]
|
1878
|
+
@longitude = tokens[1]
|
1879
|
+
@note = ''
|
1880
|
+
count = 0
|
1881
|
+
tokens.each { |tok|
|
1882
|
+
count = count + 1
|
1883
|
+
if (count > 2)
|
1884
|
+
@note << tok
|
1885
|
+
@note << ' '
|
1886
|
+
end
|
1887
|
+
}
|
1888
|
+
end
|
1889
|
+
end
|
1890
|
+
|
1807
1891
|
public
|
1808
1892
|
|
1809
1893
|
def to_s
|
1810
1894
|
return "lat: #{@latitude} lng: #{@longitude} alt: #{@altitude} note: #{@note}"
|
1811
1895
|
end
|
1896
|
+
|
1897
|
+
def to_formatted_string
|
1898
|
+
s = "lat: #{@latitude.to_s.ljust(20)}"
|
1899
|
+
s << " lng: #{@longitude.to_s.ljust(20)}"
|
1900
|
+
s << " poi.#{@number.to_s.ljust(12)}" if @number
|
1901
|
+
s << " #{@note}" if @note
|
1902
|
+
s
|
1903
|
+
end
|
1812
1904
|
|
1813
1905
|
def to_csv
|
1814
|
-
return "#{@latitude}
|
1906
|
+
return "#{@latitude}#{csv_delim}#{@longitude}#{csv_delim}#{@altitude}"
|
1815
1907
|
end
|
1816
1908
|
|
1817
1909
|
def latitude_as_float
|
@@ -1825,7 +1917,394 @@ HERE
|
|
1825
1917
|
def altitude_as_float
|
1826
1918
|
@altitude ? @altitude.to_f : invalid_altitude
|
1827
1919
|
end
|
1920
|
+
|
1921
|
+
def degrees_diff(another_point)
|
1922
|
+
if (another_point)
|
1923
|
+
puts "this: #{to_s}" if false
|
1924
|
+
puts "other: #{another_point.to_s}" if false
|
1925
|
+
puts "lats: #{latitude_as_float} #{another_point.latitude_as_float}" if false
|
1926
|
+
puts "lngs: #{longitude_as_float} #{another_point.longitude_as_float}" if false
|
1927
|
+
lat_diff = latitude_as_float - another_point.latitude_as_float
|
1928
|
+
lng_diff = longitude_as_float - another_point.longitude_as_float
|
1929
|
+
diff = lat_diff.abs + lng_diff.abs
|
1930
|
+
puts "diff: #{diff} #{lat_diff} #{lng_diff}" if false
|
1931
|
+
diff
|
1932
|
+
else
|
1933
|
+
360
|
1934
|
+
end
|
1935
|
+
end
|
1936
|
+
|
1937
|
+
def proximity(another_point, units)
|
1938
|
+
if (another_point)
|
1939
|
+
arg1 = latitude_as_float
|
1940
|
+
arg2 = another_point.latitude_as_float
|
1941
|
+
arg3 = latitude_as_float
|
1942
|
+
arg4 = another_point.latitude_as_float
|
1943
|
+
theta = longitude_as_float - another_point.longitude_as_float
|
1944
|
+
res1 = Math.sin(deg2rad(arg1))
|
1945
|
+
res2 = Math.sin(deg2rad(arg2))
|
1946
|
+
res3 = Math.cos(deg2rad(arg3))
|
1947
|
+
res4 = Math.cos(deg2rad(arg4))
|
1948
|
+
res5 = Math.cos(deg2rad(theta.to_f))
|
1949
|
+
dist = ((res1 * res2) + (res3 * res4 * res5)).to_f
|
1950
|
+
|
1951
|
+
if (!dist.nan?)
|
1952
|
+
dist = Math.acos(dist.to_f)
|
1953
|
+
if (!dist.nan?)
|
1954
|
+
dist = rad2deg(dist)
|
1955
|
+
if (!dist.nan?)
|
1956
|
+
dist = dist * 60 * 1.1515;
|
1957
|
+
if (!dist.nan?)
|
1958
|
+
if units == "K"
|
1959
|
+
dist = dist * 1.609344;
|
1960
|
+
end
|
1961
|
+
if units == "N"
|
1962
|
+
dist = dist * 0.8684;
|
1963
|
+
end
|
1964
|
+
end
|
1965
|
+
end
|
1966
|
+
end
|
1967
|
+
return dist.to_f
|
1968
|
+
else
|
1969
|
+
return 0
|
1970
|
+
end
|
1971
|
+
else
|
1972
|
+
return 0
|
1973
|
+
end
|
1974
|
+
end
|
1975
|
+
|
1976
|
+
def deg2rad(degrees)
|
1977
|
+
(((0 + degrees) * Math::PI) / 180)
|
1978
|
+
end
|
1979
|
+
|
1980
|
+
def rad2deg(radians)
|
1981
|
+
(((0 + radians) * 180) / Math::PI)
|
1982
|
+
end
|
1983
|
+
end
|
1984
|
+
|
1985
|
+
# =============================================================================
|
1986
|
+
|
1987
|
+
class CsvPoint < Point
|
1988
|
+
|
1989
|
+
attr_reader :rawdata, :tokens
|
1990
|
+
attr_reader :id, :run_id, :date, :time, :tkpt_num, :distance, :elapsed
|
1991
|
+
attr_reader :lap_number, :lap_distance, :lap_elapsed
|
1992
|
+
attr_accessor :course_distance, :course_elapsed, :degrees_diff
|
1993
|
+
|
1994
|
+
def initialize(csv_line)
|
1995
|
+
@rawdata = "#{csv_line}"
|
1996
|
+
@tokens = @rawdata.split(csv_delim)
|
1997
|
+
if (tokens.size > 12)
|
1998
|
+
@id = tokens[0] # <-- consists of @run_id.@tkpt_num for uniqueness and use as a DB table primary key.
|
1999
|
+
@run_id = tokens[1]
|
2000
|
+
@date = tokens[2]
|
2001
|
+
@time = tokens[3]
|
2002
|
+
@tkpt_num = tokens[4].strip.to_i
|
2003
|
+
@latitude = tokens[5].to_f
|
2004
|
+
@longitude = tokens[6].to_f
|
2005
|
+
@altitude = tokens[7].strip.to_f
|
2006
|
+
@distance = tokens[8].strip.to_f
|
2007
|
+
@elapsed = tokens[9]
|
2008
|
+
@lap_number = tokens[10].strip.to_i
|
2009
|
+
@lap_distance = tokens[11].strip.to_f
|
2010
|
+
@lap_elapsed = tokens[12]
|
2011
|
+
end
|
2012
|
+
end
|
2013
|
+
|
2014
|
+
def as_trackpoint
|
2015
|
+
tkpt = Trackpoint.new(@tkpt_num, @latitude, @longitude, @altitude, "#{date}T#{time}Z")
|
2016
|
+
tkpt.lap_number = @lap_number
|
2017
|
+
tkpt.lap_distance = @lap_distance
|
2018
|
+
tkpt.lap_elapsed = @lap_elapsed
|
2019
|
+
tkpt
|
2020
|
+
end
|
2021
|
+
|
2022
|
+
def to_s
|
2023
|
+
return "lat: #{@latitude} lng: #{@longitude} alt: #{@altitude} note: #{@note}"
|
2024
|
+
end
|
2025
|
+
|
2026
|
+
def to_formatted_string
|
2027
|
+
s = "lat: #{@latitude.to_s.ljust(20)}"
|
2028
|
+
s << " lng: #{@longitude.to_s.ljust(20)}"
|
2029
|
+
s << " time: #{@time}"
|
2030
|
+
pad = ''.ljust(70)
|
2031
|
+
s << "\n#{pad} course elapsed: #{@course_elapsed}"
|
2032
|
+
s << "\n#{pad} distance: #{@distance}"
|
2033
|
+
s << "\n#{pad} course distance: #{@course_distance}"
|
2034
|
+
s << "\n#{pad} altitude: #{@altitude}"
|
2035
|
+
s << "\n#{pad} degrees diff: #{@degrees_diff}"
|
2036
|
+
s
|
2037
|
+
end
|
2038
|
+
end
|
2039
|
+
|
2040
|
+
# =============================================================================
|
2041
|
+
|
2042
|
+
class CvsRun < GoobyObject
|
2043
|
+
|
2044
|
+
attr_reader :id, :points
|
2045
|
+
|
2046
|
+
def initialize(id)
|
2047
|
+
@id = "#{id}"
|
2048
|
+
@points = Array.new
|
2049
|
+
end
|
2050
|
+
|
2051
|
+
def add_point(point)
|
2052
|
+
if point
|
2053
|
+
@points << point
|
2054
|
+
end
|
2055
|
+
end
|
1828
2056
|
end
|
2057
|
+
|
2058
|
+
# =============================================================================
|
2059
|
+
|
2060
|
+
class CsvReader < GoobyObject
|
2061
|
+
|
2062
|
+
attr_reader :files, :cvs_points
|
2063
|
+
|
2064
|
+
def initialize(array_of_filenames=nil)
|
2065
|
+
@files = Array.new
|
2066
|
+
@cvs_points = Array.new
|
2067
|
+
if array_of_filenames
|
2068
|
+
array_of_filenames.each { |filename| add_file(filename) }
|
2069
|
+
end
|
2070
|
+
end
|
2071
|
+
|
2072
|
+
def add_file(filename)
|
2073
|
+
if (filename)
|
2074
|
+
if (File.exist?(filename))
|
2075
|
+
@files << filename
|
2076
|
+
end
|
2077
|
+
end
|
2078
|
+
end
|
2079
|
+
|
2080
|
+
def read
|
2081
|
+
@files.each { |filename|
|
2082
|
+
lines = read_lines(filename, true)
|
2083
|
+
lines.each { |line|
|
2084
|
+
if (line.match('^#'))
|
2085
|
+
if (line.match('^#cols: '))
|
2086
|
+
col_names_header = line[7, line.size]
|
2087
|
+
@col_names = col_names_header.split('|')
|
2088
|
+
end
|
2089
|
+
else
|
2090
|
+
if (line.size > 50)
|
2091
|
+
@cvs_points << Gooby::CsvPoint.new(line)
|
2092
|
+
end
|
2093
|
+
end
|
2094
|
+
}
|
2095
|
+
}
|
2096
|
+
@cvs_points
|
2097
|
+
end
|
2098
|
+
|
2099
|
+
def display_formatted_record(record_index=2)
|
2100
|
+
tokens = @cvs_points[record_index].rawdata.split('|')
|
2101
|
+
puts "\nCsvReader.display_formatted_record hdr_cols=#{@col_names.size} data_cols=#{tokens.size}"
|
2102
|
+
size = 0
|
2103
|
+
@col_names.each { |col_name|
|
2104
|
+
size = size + 1
|
2105
|
+
if size <= tokens.size
|
2106
|
+
value = tokens[size - 1]
|
2107
|
+
puts "#{col_name.strip.ljust(20)} #{(size - 1).to_s.ljust(3)} #{value}"
|
2108
|
+
end
|
2109
|
+
}
|
2110
|
+
end
|
2111
|
+
|
2112
|
+
def to_s
|
2113
|
+
s = "CsvReader - file count: #{files.size} total points: #{cvs_points.size}"
|
2114
|
+
@files.each { |file| s << "\n file: #{file} "}
|
2115
|
+
s
|
2116
|
+
end
|
2117
|
+
end
|
2118
|
+
|
2119
|
+
# =============================================================================
|
2120
|
+
|
2121
|
+
class Trackpoint < Point
|
2122
|
+
|
2123
|
+
attr_accessor :first, :last, :number, :run_number, :dttm, :prev_tkpt, :lap_number, :lap_seq, :lap_distance, :lap_elapsed
|
2124
|
+
attr_accessor :cumulative_distance, :cumulative_pace, :incremental_distance, :split, :prev_split
|
2125
|
+
attr_accessor :first, :last, :run_id, :run_number
|
2126
|
+
attr_accessor :run_start_dttm
|
2127
|
+
|
2128
|
+
def initialize(num, lat, lng, alt, time_string, auxInfoHash=Hash.new(''))
|
2129
|
+
@number = num
|
2130
|
+
@run_number = 0
|
2131
|
+
@auxInfoHash = auxInfoHash
|
2132
|
+
@lap_seq = 1
|
2133
|
+
@lap_distance = 0
|
2134
|
+
lap_num = @auxInfoHash['lap_number']
|
2135
|
+
if (lap_num && lap_num.size > 0)
|
2136
|
+
@lap_number = lap_num.to_i
|
2137
|
+
else
|
2138
|
+
@lap_number = 0
|
2139
|
+
end
|
2140
|
+
# initialize superclass variables:
|
2141
|
+
@latitude = lat.to_s
|
2142
|
+
@longitude = lng.to_s
|
2143
|
+
feet = alt.to_f * 3.2736 # Convert from meters (in the Garmin xml) to feet.
|
2144
|
+
@altitude = feet.to_s
|
2145
|
+
@note = note.to_s
|
2146
|
+
@dttm = DtTm.new(time_string)
|
2147
|
+
@first = false
|
2148
|
+
@last = false
|
2149
|
+
@prev_tkpt = nil
|
2150
|
+
@cumulative_distance, @incremental_distance, @split = 0.0, 0.0, 0.0
|
2151
|
+
@cumulative_pace = ""
|
2152
|
+
end
|
2153
|
+
|
2154
|
+
public
|
2155
|
+
|
2156
|
+
def point
|
2157
|
+
Point.new(@latitude, @longitude, @altitude, @note)
|
2158
|
+
end
|
2159
|
+
|
2160
|
+
def position
|
2161
|
+
Point.new(@latitude, @longitude, @altitude, @note)
|
2162
|
+
end
|
2163
|
+
|
2164
|
+
def to_s
|
2165
|
+
"Tkpt: #{@number} #{super.to_s} date: #{@dttm.to_s} cdist: #{@cumulative_distance}"
|
2166
|
+
end
|
2167
|
+
|
2168
|
+
def to_csv(prev_tkpt=nil)
|
2169
|
+
first_lap_start_time_s = @auxInfoHash['first_lap_start_time']
|
2170
|
+
curr_lap_start_time_s = @auxInfoHash['curr_lap_start_time']
|
2171
|
+
lap_elapsed = ''
|
2172
|
+
total_elapsed = ''
|
2173
|
+
|
2174
|
+
if ((first_lap_start_time_s.size > 0) && (curr_lap_start_time_s.size > 0)) # garmin205 & 305
|
2175
|
+
first_lap_start_time = DtTm.new(first_lap_start_time_s)
|
2176
|
+
first_lap_start_time = @run_start_dttm
|
2177
|
+
curr_lap_start_time = DtTm.new(curr_lap_start_time_s)
|
2178
|
+
lap_elapsed = @dttm.hhmmss_diff(curr_lap_start_time)
|
2179
|
+
total_elapsed = @dttm.hhmmss_diff(first_lap_start_time)
|
2180
|
+
else # garmin 201
|
2181
|
+
total_elapsed = @dttm.hhmmss_diff(@run_start_dttm)
|
2182
|
+
lap_elapsed = total_elapsed
|
2183
|
+
end
|
2184
|
+
|
2185
|
+
delim = csv_delim
|
2186
|
+
csv = "#{@run_id}.#{@number}" # <-- primary key
|
2187
|
+
csv << "#{delim}#{@run_id}"
|
2188
|
+
csv << "#{delim}#{@dttm.yyyy_mm_dd_hh_mm_ss('|')}"
|
2189
|
+
csv << "#{delim}#{@number}"
|
2190
|
+
csv << "#{delim}#{position.to_csv}"
|
2191
|
+
csv << "#{delim}#{@cumulative_distance}"
|
2192
|
+
csv << "#{delim}#{total_elapsed}"
|
2193
|
+
csv << "#{delim}#{@lap_seq}"
|
2194
|
+
csv << "#{delim}#{@lap_distance}"
|
2195
|
+
csv << "#{delim}#{lap_elapsed}"
|
2196
|
+
csv
|
2197
|
+
end
|
2198
|
+
|
2199
|
+
def self.csv_header
|
2200
|
+
"#cols: primary_key|run_id|date|time|tkpt_num|latitude|longitude|altitude_ft|run_distance|run_elapsed|lap_tkpt_number|lap_distance|lap_elapsed"
|
2201
|
+
end
|
2202
|
+
|
2203
|
+
def to_geo_s
|
2204
|
+
ss = position.to_csv
|
2205
|
+
"Tkpt: #{@number} | #{ss} | #{@descr}"
|
2206
|
+
end
|
2207
|
+
|
2208
|
+
def compute_distance_and_pace(curr_index, start_dttm, prev_cumulative_dist, prev_trackpoint, units)
|
2209
|
+
@prev_tkpt = prev_trackpoint
|
2210
|
+
@cumulative_distance = prev_cumulative_dist.to_f
|
2211
|
+
@run_start_dttm = start_dttm
|
2212
|
+
|
2213
|
+
if @prev_tkpt
|
2214
|
+
@incremental_distance = proximity(@prev_tkpt, units)
|
2215
|
+
if (!@incremental_distance.nan?)
|
2216
|
+
@cumulative_distance = @cumulative_distance + @incremental_distance.to_f
|
2217
|
+
if (@lap_number == prev_trackpoint.lap_number)
|
2218
|
+
@lap_seq = prev_trackpoint.lap_seq + 1
|
2219
|
+
@lap_distance = prev_trackpoint.lap_distance + @incremental_distance
|
2220
|
+
else
|
2221
|
+
@lap_seq = 1
|
2222
|
+
@lap_distance = @incremental_distance
|
2223
|
+
end
|
2224
|
+
end
|
2225
|
+
compute_cumulative_pace(start_dttm)
|
2226
|
+
@cumulative_distance
|
2227
|
+
else
|
2228
|
+
@lap_seq = 1
|
2229
|
+
0
|
2230
|
+
end
|
2231
|
+
end
|
2232
|
+
|
2233
|
+
def compute_cumulative_pace(start_dttm)
|
2234
|
+
if @cumulative_distance > 0
|
2235
|
+
secsDiff = @dttm.seconds_diff(start_dttm)
|
2236
|
+
secsMile = ((secsDiff.to_f) / (@cumulative_distance.to_f))
|
2237
|
+
minsMile = (secsMile / 60)
|
2238
|
+
wholeMins = minsMile.floor
|
2239
|
+
secsBal = secsMile - (wholeMins * 60)
|
2240
|
+
s1 = "#{secsDiff} #{secsMile} #{minsMile} #{wholeMins} #{secsBal} #{@cumulative_distance} | "
|
2241
|
+
s2 = sprintf("%d:%2.1f", minsMile, secsBal)
|
2242
|
+
@cumulative_pace = "#{s2}"
|
2243
|
+
else
|
2244
|
+
@cumulative_pace = ""
|
2245
|
+
end
|
2246
|
+
end
|
2247
|
+
|
2248
|
+
def set_split(n, tkpt)
|
2249
|
+
@split, @prev_split = n, tkpt
|
2250
|
+
end
|
2251
|
+
|
2252
|
+
def is_split()
|
2253
|
+
(@split >= 1)
|
2254
|
+
end
|
2255
|
+
|
2256
|
+
def split_info(dtTm)
|
2257
|
+
if is_split
|
2258
|
+
hhmmss = ''
|
2259
|
+
if @prev_split
|
2260
|
+
return "#{@split} #{@dttm.hhmmss_diff(@prev_split.dttm())}"
|
2261
|
+
else
|
2262
|
+
return "#{@split} #{@dttm.hhmmss_diff(dtTm)}"
|
2263
|
+
end
|
2264
|
+
else
|
2265
|
+
""
|
2266
|
+
end
|
2267
|
+
end
|
2268
|
+
|
2269
|
+
public
|
2270
|
+
|
2271
|
+
def as_glatlng(comment_out, gen_comments, tkpt_count, curr_idx, start_dttm)
|
2272
|
+
comment_out ? comment = '// ' : comment = ''
|
2273
|
+
if gen_comments
|
2274
|
+
secs_diff = @dttm.seconds_diff(start_dttm)
|
2275
|
+
fmt_time = @dttm.hhmmss_diff(start_dttm)
|
2276
|
+
"\n #{comment}points.push(new GLatLng(#{latitude_as_float},#{longitude_as_float})); " +
|
2277
|
+
"// (#{curr_idx + 1} of #{tkpt_count}) #{@dttm.to_s} #{secs_diff} #{fmt_time} #{@cumulative_distance} #{split_info(start_dttm)} #{project_embedded_comment} "
|
2278
|
+
else
|
2279
|
+
"\n #{comment}points.push(new GLatLng(#{latitude_as_float},#{longitude_as_float})); // #{project_embedded_comment} "
|
2280
|
+
end
|
2281
|
+
end
|
2282
|
+
|
2283
|
+
def as_info_window_html(checkpoint, start_dttm)
|
2284
|
+
s = "\"<table align='left'>"
|
2285
|
+
if checkpoint
|
2286
|
+
secs_diff = @dttm.seconds_diff(start_dttm)
|
2287
|
+
fmt_time = @dttm.hhmmss_diff(start_dttm)
|
2288
|
+
|
2289
|
+
if checkpoint == 'Start'
|
2290
|
+
s << "<tr><td colspan='2'><b>Start!</b></td></tr>"
|
2291
|
+
elsif checkpoint == 'Finish'
|
2292
|
+
s << "<tr><td colspan='2'><b>Finish!</b></td></tr>"
|
2293
|
+
else
|
2294
|
+
s << "<tr><td colspan='2'><b>Checkpoint #{checkpoint}</b></td></tr>"
|
2295
|
+
end
|
2296
|
+
s << "<tr><td>Distance: </td><td>#{@cumulative_distance}</td></tr>"
|
2297
|
+
s << "<tr><td>Time of Day: </td><td>#{@dttm.to_s} </td></tr>"
|
2298
|
+
s << "<tr><td>Elapsed Time: </td><td>#{fmt_time} </td></tr>"
|
2299
|
+
s << "<tr><td>Average Pace: </td><td>#{@cumulative_pace} </td></tr>"
|
2300
|
+
s << "<tr><td>Lat/Lng: </td><td>#{latitude_as_float} , #{longitude_as_float} </td></tr>"
|
2301
|
+
#s << "<tr><td>Altitude: </td><td>#{altitude_as_float}m </td></tr>"
|
2302
|
+
s
|
2303
|
+
end
|
2304
|
+
s << "</table>\""
|
2305
|
+
s
|
2306
|
+
end
|
2307
|
+
end
|
1829
2308
|
|
1830
2309
|
# =============================================================================
|
1831
2310
|
|
@@ -1839,19 +2318,20 @@ HERE
|
|
1839
2318
|
|
1840
2319
|
class Run < GoobyObject
|
1841
2320
|
|
1842
|
-
attr_accessor :number, :descr, :notes, :tracks, :tkpts, :laps, :distance
|
2321
|
+
attr_accessor :number, :run_id, :descr, :notes, :tracks, :tkpts, :laps, :distance
|
1843
2322
|
|
1844
2323
|
def initialize(number=0, descr='')
|
1845
2324
|
@number = number
|
2325
|
+
@run_id = nil
|
1846
2326
|
@descr = descr
|
1847
2327
|
@notes = ''
|
1848
2328
|
@tracks = Array.new
|
1849
2329
|
@tkpts = Array.new
|
1850
2330
|
@laps = Array.new
|
1851
2331
|
@distance = 0
|
1852
|
-
@
|
2332
|
+
@configuration = Hash.new
|
1853
2333
|
@logProgress = true
|
1854
|
-
@finished
|
2334
|
+
@finished = false
|
1855
2335
|
end
|
1856
2336
|
|
1857
2337
|
public
|
@@ -1860,7 +2340,7 @@ HERE
|
|
1860
2340
|
def finish()
|
1861
2341
|
@logProgress = false
|
1862
2342
|
unless @finished
|
1863
|
-
@tracks.each { |trk|
|
2343
|
+
@tracks.each { |trk|
|
1864
2344
|
trk.trackpoints().each { |tkpt|
|
1865
2345
|
tkpt.run_number = @number
|
1866
2346
|
@tkpts.push(tkpt)
|
@@ -1868,6 +2348,7 @@ HERE
|
|
1868
2348
|
}
|
1869
2349
|
compute_distance_and_pace
|
1870
2350
|
compute_splits
|
2351
|
+
set_run_ids
|
1871
2352
|
@finished = true
|
1872
2353
|
end
|
1873
2354
|
end
|
@@ -1920,7 +2401,7 @@ HERE
|
|
1920
2401
|
return last.hhmmss_diff(first)
|
1921
2402
|
end
|
1922
2403
|
end
|
1923
|
-
return "
|
2404
|
+
return "00:00:00"
|
1924
2405
|
end
|
1925
2406
|
|
1926
2407
|
def start_yyyy_mm_dd
|
@@ -1965,12 +2446,14 @@ HERE
|
|
1965
2446
|
puts "#{@number}|#{}|#{start_yyyy_mm_dd()}|#{start_hh_mm_ss()}|#{end_hh_mm_ss}|#{duration()}|#{@distance}|#{@tracks.size}|#{trackpoint_count()}|#{lap_count}|#{@notes.strip}"
|
1966
2447
|
end
|
1967
2448
|
|
1968
|
-
def put_tkpt_csv(
|
2449
|
+
def put_tkpt_csv()
|
1969
2450
|
finish() unless @finished
|
1970
|
-
|
1971
|
-
|
1972
|
-
|
1973
|
-
|
2451
|
+
@tkpts.each { | tkpt |
|
2452
|
+
if (@prev_tkpt == nil)
|
2453
|
+
@prev_tkpt = tkpt
|
2454
|
+
end
|
2455
|
+
puts tkpt.to_csv(@prev_tkpt)
|
2456
|
+
}
|
1974
2457
|
end
|
1975
2458
|
|
1976
2459
|
def put_laps
|
@@ -1988,19 +2471,19 @@ HERE
|
|
1988
2471
|
curr_index = curr_index + 1
|
1989
2472
|
if curr_index == 0
|
1990
2473
|
start_dttm = tkpt.dttm()
|
1991
|
-
prev_tkpt = tkpt
|
2474
|
+
prev_tkpt = tkpt
|
1992
2475
|
else
|
1993
2476
|
cumulative_dist = tkpt.compute_distance_and_pace(curr_index, start_dttm, cumulative_dist, prev_tkpt, 'M')
|
1994
2477
|
prev_tkpt = tkpt
|
1995
2478
|
end
|
1996
2479
|
}
|
1997
|
-
@distance = cumulative_dist
|
2480
|
+
@distance = cumulative_dist
|
1998
2481
|
end
|
1999
2482
|
|
2000
|
-
def compute_splits
|
2483
|
+
def compute_splits
|
2001
2484
|
nextSplitDist = 1.00
|
2002
2485
|
prev_splitTkpt = nil
|
2003
|
-
loop1Count
|
2486
|
+
loop1Count = 0;
|
2004
2487
|
@tkpts.each { |tkpt|
|
2005
2488
|
loop1Count = loop1Count + 1
|
2006
2489
|
if tkpt.cumulative_distance() >= nextSplitDist
|
@@ -2017,6 +2500,15 @@ HERE
|
|
2017
2500
|
tkpt.last = true if count == loop1Count
|
2018
2501
|
}
|
2019
2502
|
end
|
2503
|
+
|
2504
|
+
def set_run_ids
|
2505
|
+
@tkpts.each { |tkpt|
|
2506
|
+
if (@run_id == nil)
|
2507
|
+
@run_id = tkpt.dttm.rawdata
|
2508
|
+
end
|
2509
|
+
tkpt.run_id = @run_id
|
2510
|
+
}
|
2511
|
+
end
|
2020
2512
|
end
|
2021
2513
|
|
2022
2514
|
# =============================================================================
|
@@ -2092,201 +2584,117 @@ HERE
|
|
2092
2584
|
|
2093
2585
|
def dump
|
2094
2586
|
puts "Track: '#{@descr}' tkpts: #{size}"
|
2095
|
-
@trackpoints.each { |tkpt| puts tkpt.to_csv }
|
2587
|
+
@trackpoints.each { |tkpt| puts tkpt.to_csv }
|
2096
2588
|
end
|
2097
2589
|
end
|
2098
|
-
|
2099
|
-
# =============================================================================
|
2100
|
-
|
2101
|
-
=begin rdoc
|
2102
|
-
Instances of this class represent a <Trackpoint> aggregate from a Forerunner
|
2103
|
-
XML file. Additionally, there is distance, pace, and Google Map generation
|
2104
|
-
logic in this class.
|
2105
|
-
|
2106
|
-
<Trackpoint>
|
2107
|
-
<Position>
|
2108
|
-
<Latitude>35.49577</Latitude>
|
2109
|
-
<Longitude>-80.83281</Longitude>
|
2110
|
-
<Altitude>232.296</Altitude>
|
2111
|
-
</Position>
|
2112
|
-
<Time>2007-01-06T15:27:51Z</Time>
|
2113
|
-
</Trackpoint>
|
2114
|
-
=end
|
2115
|
-
|
2116
|
-
class Trackpoint < Position
|
2117
|
-
|
2118
|
-
attr_reader :first, :last, :number, :run_number, :dttm, :prev_tkpt, :descr
|
2119
|
-
attr_reader :cumulative_distance, :cumulative_pace, :incremental_distance, :split, :prev_split
|
2120
|
-
attr_writer :first, :last, :run_number
|
2121
2590
|
|
2122
|
-
|
2123
|
-
|
2124
|
-
|
2125
|
-
|
2126
|
-
|
2127
|
-
|
2128
|
-
|
2129
|
-
|
2130
|
-
|
2131
|
-
|
2132
|
-
|
2133
|
-
|
2134
|
-
|
2135
|
-
|
2136
|
-
|
2137
|
-
|
2138
|
-
|
2139
|
-
|
2140
|
-
|
2141
|
-
|
2142
|
-
|
2143
|
-
|
2144
|
-
|
2145
|
-
|
2146
|
-
|
2147
|
-
|
2148
|
-
end
|
2149
|
-
|
2150
|
-
def to_csv
|
2151
|
-
ss = position.to_csv
|
2152
|
-
"#{@run_number} | #{@dttm.to_s} | #{@number} | #{ss} | #{@cumulative_distance} "
|
2153
|
-
end
|
2154
|
-
|
2155
|
-
def to_geo_s
|
2156
|
-
ss = position.to_csv
|
2157
|
-
"Tkpt: #{@number} | #{ss} | #{@descr}"
|
2158
|
-
end
|
2159
|
-
|
2160
|
-
def compute_distance_and_pace(curr_index, start_dttm, prev_cumulative_dist, prev_trackpoint, units)
|
2161
|
-
@prev_tkpt = prev_trackpoint
|
2162
|
-
@cumulative_distance = prev_cumulative_dist.to_f
|
2163
|
-
|
2164
|
-
if @prev_tkpt
|
2165
|
-
arg1 = latitude().to_f
|
2166
|
-
arg2 = @prev_tkpt.latitude().to_f
|
2167
|
-
arg3 = latitude().to_f
|
2168
|
-
arg4 = @prev_tkpt.latitude().to_f
|
2169
|
-
theta = longitude().to_f - @prev_tkpt.longitude().to_f
|
2170
|
-
|
2171
|
-
res1 = Math.sin(deg2rad(arg1))
|
2172
|
-
res2 = Math.sin(deg2rad(arg2))
|
2173
|
-
res3 = Math.cos(deg2rad(arg3))
|
2174
|
-
res4 = Math.cos(deg2rad(arg4))
|
2175
|
-
res5 = Math.cos(deg2rad(theta.to_f))
|
2176
|
-
|
2177
|
-
incremental_distance = ((res1 * res2) + (res3 * res4 * res5)).to_f
|
2178
|
-
|
2179
|
-
if (!incremental_distance.nan?)
|
2180
|
-
incremental_distance = Math.acos(incremental_distance.to_f)
|
2181
|
-
if (!incremental_distance.nan?)
|
2182
|
-
incremental_distance = rad2deg(incremental_distance)
|
2183
|
-
if (!incremental_distance.nan?)
|
2184
|
-
incremental_distance = incremental_distance * 60 * 1.1515;
|
2185
|
-
if (!incremental_distance.nan?)
|
2186
|
-
if units == "K"
|
2187
|
-
incremental_distance = incremental_distance * 1.609344;
|
2188
|
-
end
|
2189
|
-
if units == "N"
|
2190
|
-
incremental_distance = incremental_distance * 0.8684;
|
2191
|
-
end
|
2192
|
-
@cumulative_distance = @cumulative_distance + incremental_distance.to_f
|
2591
|
+
# =============================================================================
|
2592
|
+
|
2593
|
+
class Course < GoobyObject
|
2594
|
+
|
2595
|
+
attr_accessor :name, :distance, :point_numbers, :points
|
2596
|
+
|
2597
|
+
def initialize(yaml_csv)
|
2598
|
+
@name, @distance = '', 0.0
|
2599
|
+
@point_numbers, @points, @bad_points = Array.new, Array.new, Array.new
|
2600
|
+
@points_hash, @matched_points = Hash.new, Hash.new
|
2601
|
+
tokens = yaml_csv.split(',')
|
2602
|
+
@name = tokens[0] if tokens.size > 0
|
2603
|
+
@distance = tokens[1].to_f if tokens.size > 1
|
2604
|
+
if tokens.size > 2
|
2605
|
+
index = 0
|
2606
|
+
tokens.each { |tok|
|
2607
|
+
index = index + 1
|
2608
|
+
if (index > 2)
|
2609
|
+
poi = Configuration.get_config.get_poi(tok)
|
2610
|
+
if (poi)
|
2611
|
+
poi.number = "#{tok}"
|
2612
|
+
@point_numbers << "#{tok}"
|
2613
|
+
@points << poi
|
2614
|
+
@points_hash["#{tok}"] = poi
|
2615
|
+
else
|
2616
|
+
@bad_points << tok
|
2193
2617
|
end
|
2194
2618
|
end
|
2195
|
-
|
2196
|
-
end
|
2197
|
-
compute_cumulative_pace(start_dttm)
|
2198
|
-
@cumulative_distance
|
2199
|
-
else
|
2200
|
-
0
|
2201
|
-
end
|
2202
|
-
end
|
2203
|
-
|
2204
|
-
def compute_cumulative_pace(start_dttm)
|
2205
|
-
if @cumulative_distance > 0
|
2206
|
-
secsDiff = @dttm.seconds_diff(start_dttm)
|
2207
|
-
secsMile = ((secsDiff.to_f) / (@cumulative_distance.to_f))
|
2208
|
-
minsMile = (secsMile / 60)
|
2209
|
-
wholeMins = minsMile.floor
|
2210
|
-
secsBal = secsMile - (wholeMins * 60)
|
2211
|
-
s1 = "#{secsDiff} #{secsMile} #{minsMile} #{wholeMins} #{secsBal} #{@cumulative_distance} | "
|
2212
|
-
s2 = sprintf("%d:%2.1f", minsMile, secsBal)
|
2213
|
-
@cumulative_pace = "#{s2}"
|
2214
|
-
else
|
2215
|
-
@cumulative_pace = ""
|
2619
|
+
}
|
2620
|
+
end
|
2216
2621
|
end
|
2217
|
-
|
2218
|
-
|
2219
|
-
|
2220
|
-
|
2221
|
-
|
2222
|
-
|
2223
|
-
|
2224
|
-
|
2225
|
-
|
2226
|
-
|
2227
|
-
|
2228
|
-
|
2229
|
-
|
2230
|
-
|
2231
|
-
|
2232
|
-
|
2233
|
-
|
2234
|
-
|
2235
|
-
|
2236
|
-
|
2622
|
+
|
2623
|
+
def has_errors
|
2624
|
+
(@bad_points.size > 0) ? true : false
|
2625
|
+
end
|
2626
|
+
|
2627
|
+
def matched(number, point)
|
2628
|
+
@matched_points["#{number}"] = point if point
|
2629
|
+
end
|
2630
|
+
|
2631
|
+
def matched?
|
2632
|
+
(@matched_points.size == @point_numbers.size) ? true : false
|
2633
|
+
end
|
2634
|
+
|
2635
|
+
def display_matches
|
2636
|
+
puts ''
|
2637
|
+
calculate_matches
|
2638
|
+
@point_numbers.each { |num|
|
2639
|
+
point = @points_hash["#{num}"]
|
2640
|
+
mpoint = @matched_points["#{num}"]
|
2641
|
+
puts ''
|
2642
|
+
puts " Course Point: #{point.to_formatted_string}" if point
|
2643
|
+
puts " Matched Point: #{mpoint.to_formatted_string}" if mpoint
|
2644
|
+
}
|
2645
|
+
puts ''
|
2237
2646
|
end
|
2238
|
-
end
|
2239
|
-
|
2240
|
-
private
|
2241
|
-
|
2242
|
-
def deg2rad(degrees)
|
2243
|
-
(((0 + degrees) * Math::PI) / 180)
|
2244
|
-
end
|
2245
|
-
|
2246
|
-
def rad2deg(radians)
|
2247
|
-
(((0 + radians) * 180) / Math::PI)
|
2248
|
-
end
|
2249
2647
|
|
2250
|
-
|
2251
|
-
|
2252
|
-
def as_glatlng(comment_out, gen_comments, tkpt_count, curr_idx, start_dttm)
|
2253
|
-
comment_out ? comment = '// ' : comment = ''
|
2254
|
-
if gen_comments
|
2255
|
-
secs_diff = @dttm.seconds_diff(start_dttm)
|
2256
|
-
fmt_time = @dttm.hhmmss_diff(start_dttm)
|
2257
|
-
"\n #{comment}points.push(new GLatLng(#{latitude_as_float},#{longitude_as_float})); " +
|
2258
|
-
"// (#{curr_idx + 1} of #{tkpt_count}) #{@dttm.to_s} #{secs_diff} #{fmt_time} #{@cumulative_distance} #{split_info(start_dttm)} #{project_embedded_comment} "
|
2259
|
-
else
|
2260
|
-
"\n #{comment}points.push(new GLatLng(#{latitude_as_float},#{longitude_as_float})); // #{project_embedded_comment} "
|
2261
|
-
end
|
2262
|
-
end
|
2263
|
-
|
2264
|
-
def as_info_window_html(checkpoint, start_dttm)
|
2265
|
-
s = "\"<table align='left'>"
|
2266
|
-
if checkpoint
|
2267
|
-
secs_diff = @dttm.seconds_diff(start_dttm)
|
2268
|
-
fmt_time = @dttm.hhmmss_diff(start_dttm)
|
2269
|
-
|
2270
|
-
if checkpoint == 'Start'
|
2271
|
-
s << "<tr><td colspan='2'><b>Start!</b></td></tr>"
|
2272
|
-
elsif checkpoint == 'Finish'
|
2273
|
-
s << "<tr><td colspan='2'><b>Finish!</b></td></tr>"
|
2274
|
-
else
|
2275
|
-
s << "<tr><td colspan='2'><b>Checkpoint #{checkpoint}</b></td></tr>"
|
2276
|
-
end
|
2277
|
-
s << "<tr><td>Distance: </td><td>#{@cumulative_distance}</td></tr>"
|
2278
|
-
s << "<tr><td>Time of Day: </td><td>#{@dttm.to_s} </td></tr>"
|
2279
|
-
s << "<tr><td>Elapsed Time: </td><td>#{fmt_time} </td></tr>"
|
2280
|
-
s << "<tr><td>Average Pace: </td><td>#{@cumulative_pace} </td></tr>"
|
2281
|
-
s << "<tr><td>Lat/Lng: </td><td>#{latitude_as_float} , #{longitude_as_float} </td></tr>"
|
2282
|
-
s << "<tr><td>Altitude: </td><td>#{altitude_as_float}m </td></tr>"
|
2283
|
-
s
|
2648
|
+
def reset
|
2649
|
+
@matched_points = Hash.new
|
2284
2650
|
end
|
2285
|
-
|
2286
|
-
|
2651
|
+
|
2652
|
+
def to_s
|
2653
|
+
"#{@name} #{@distance} points: #{@points.size} errors: #{has_errors}"
|
2654
|
+
end
|
2655
|
+
|
2656
|
+
def dump
|
2657
|
+
puts "Course: #{@name}"
|
2658
|
+
puts "Distance: #{@distance}"
|
2659
|
+
points.each { |pt| puts pt } #{@points.size} errors: #{has_errors}"
|
2660
|
+
end
|
2661
|
+
|
2662
|
+
private
|
2663
|
+
|
2664
|
+
def calculate_matches
|
2665
|
+
# first, identify the high and low distance points and their indices.
|
2666
|
+
idx, low_dist, low_dist_idx, low_time, high_dist, high_dist_idx = -1, 999999.0, 0, '', -1.0, 0
|
2667
|
+
@point_numbers.each { |num|
|
2668
|
+
idx = idx + 1
|
2669
|
+
mpoint = @matched_points["#{num}"]
|
2670
|
+
if mpoint && mpoint.distance < low_dist
|
2671
|
+
low_dist = mpoint.distance
|
2672
|
+
low_dist_idx = idx
|
2673
|
+
low_time = mpoint.elapsed
|
2674
|
+
end
|
2675
|
+
if mpoint && mpoint.distance > high_dist
|
2676
|
+
high_dist = mpoint.distance
|
2677
|
+
high_dist_idx = idx
|
2678
|
+
end
|
2679
|
+
}
|
2680
|
+
low_dttm = DtTm.new("2007-06-09T#{low_time}Z")
|
2681
|
+
|
2682
|
+
# reorder the entries in @point_numbers if necessary - 'low-to-high distance'.
|
2683
|
+
if (high_dist_idx < low_dist_idx)
|
2684
|
+
@point_numbers.reverse!
|
2685
|
+
end
|
2686
|
+
|
2687
|
+
@point_numbers.each { |num|
|
2688
|
+
mpoint = @matched_points["#{num}"]
|
2689
|
+
if mpoint
|
2690
|
+
mpoint.course_distance = mpoint.distance - low_dist
|
2691
|
+
dttm = DtTm.new("2007-06-09T#{mpoint.elapsed}Z")
|
2692
|
+
mpoint.course_elapsed = dttm.hhmmss_diff(low_dttm)
|
2693
|
+
end
|
2694
|
+
}
|
2695
|
+
end
|
2287
2696
|
end
|
2288
|
-
|
2289
|
-
|
2697
|
+
|
2290
2698
|
# =============================================================================
|
2291
2699
|
|
2292
2700
|
=begin rdoc
|
@@ -2361,7 +2769,7 @@ HERE
|
|
2361
2769
|
type = tokens[0].ljust(6)
|
2362
2770
|
name = tokens[1]
|
2363
2771
|
count = tokens[2].rjust(6)
|
2364
|
-
puts " #{count} #{type} #{name}"
|
2772
|
+
puts " #{count} #{type} #{name}"
|
2365
2773
|
}
|
2366
2774
|
end
|
2367
2775
|
|
@@ -2409,8 +2817,6 @@ HERE
|
|
2409
2817
|
count = @tokens_hash.value(name)
|
2410
2818
|
puts "method: #{name} (#{count})"
|
2411
2819
|
}
|
2412
|
-
# puts @tokens_hash.to_s
|
2413
|
-
# puts @tokens_hash.size
|
2414
2820
|
end
|
2415
2821
|
|
2416
2822
|
def parse_code_lines
|
@@ -2596,13 +3002,40 @@ HERE
|
|
2596
3002
|
|
2597
3003
|
class GoobyCommand < GoobyObject
|
2598
3004
|
|
2599
|
-
|
3005
|
+
attr_reader :configuration
|
3006
|
+
|
3007
|
+
def initialize(gooby_yaml_filename=nil)
|
3008
|
+
@configuration = Gooby::Configuration.init(gooby_yaml_filename)
|
2600
3009
|
end
|
2601
3010
|
|
2602
|
-
def
|
2603
|
-
|
3011
|
+
def display_version
|
3012
|
+
s = "# #{project_name} #{project_version_number} #{project_date}. #{project_copyright}."
|
3013
|
+
puts s
|
2604
3014
|
end
|
2605
3015
|
|
3016
|
+
def split_garmin_export_file(argv)
|
3017
|
+
if (argv == nil)
|
3018
|
+
puts "ERROR: no ARGV args passed."
|
3019
|
+
elsif (argv.size < 3)
|
3020
|
+
puts ""
|
3021
|
+
puts "Invalid program args; three args required - format, input filename, output directory"
|
3022
|
+
puts " the first arg, format, should be one of: garmin201, garmin205, garmin305, etc."
|
3023
|
+
puts " the second arg is the input filename - which is a garmin export file"
|
3024
|
+
puts " the third arg is the output directory where the split files are written to\n\n"
|
3025
|
+
puts "Please correct the program arguments and try again. \n\n"
|
3026
|
+
else
|
3027
|
+
format = argv[0].downcase
|
3028
|
+
filename = argv[1]
|
3029
|
+
out_dir = argv[2]
|
3030
|
+
|
3031
|
+
if (format == 'garmin201')
|
3032
|
+
split_garmin_forerunner_logbook_xml(filename, out_dir)
|
3033
|
+
else
|
3034
|
+
split_garmin_training_center_xml(filename, out_dir)
|
3035
|
+
end
|
3036
|
+
end
|
3037
|
+
end
|
3038
|
+
|
2606
3039
|
def split_garmin_forerunner_logbook_xml(xml_filename, out_dir)
|
2607
3040
|
splitter = Gooby::ForerunnerXmlSplitter.new(xml_filename, out_dir)
|
2608
3041
|
splitter.split
|
@@ -2612,22 +3045,117 @@ HERE
|
|
2612
3045
|
splitter = Gooby::TrainingCenterXmlSplitter.new(tcx_filename, out_dir)
|
2613
3046
|
splitter.split
|
2614
3047
|
end
|
3048
|
+
|
3049
|
+
def parse_garmin_xml_file(argv)
|
3050
|
+
if (argv == nil)
|
3051
|
+
puts "ERROR: no ARGV args passed."
|
3052
|
+
elsif (argv.size < 2)
|
3053
|
+
puts ""
|
3054
|
+
puts "Invalid program args; two args required - format, input (xml) filename, output directory"
|
3055
|
+
puts " the first arg, format, should be one of: garmin201, garmin205, garmin305, etc."
|
3056
|
+
puts " the second arg, input xml filename, was produced by the Gooby 'splitter.rb' program."
|
3057
|
+
puts "Please correct the program arguments and try again. \n\n"
|
3058
|
+
else
|
3059
|
+
format = argv[0].downcase
|
3060
|
+
filename = argv[1]
|
3061
|
+
puts Trackpoint.csv_header
|
3062
|
+
if (format == 'garmin201')
|
3063
|
+
parse_garmin_forerunner_logbook_xml(filename)
|
3064
|
+
else
|
3065
|
+
parse_garmin_training_center_xml(filename)
|
3066
|
+
end
|
3067
|
+
end
|
3068
|
+
end
|
2615
3069
|
|
2616
3070
|
def parse_garmin_forerunner_logbook_xml(xml_filename)
|
2617
3071
|
handler = Gooby::ForerunnerXmlParser.new
|
2618
3072
|
Document.parse_stream((File.new xml_filename), handler)
|
2619
|
-
handler.put_all_run_tkpt_csv(
|
3073
|
+
handler.put_all_run_tkpt_csv()
|
2620
3074
|
end
|
2621
3075
|
|
2622
3076
|
def parse_garmin_training_center_xml(tcx_filename)
|
2623
3077
|
handler = Gooby::TrainingCenterXmlParser.new
|
2624
3078
|
Document.parse_stream((File.new tcx_filename), handler)
|
2625
|
-
handler.put_all_run_tkpt_csv(
|
3079
|
+
handler.put_all_run_tkpt_csv()
|
3080
|
+
end
|
3081
|
+
|
3082
|
+
def read_csv_files(array_of_filenames, record_index=0)
|
3083
|
+
@cvs_reader = Gooby::CsvReader.new(array_of_filenames)
|
3084
|
+
@cvs_points = @cvs_reader.read
|
3085
|
+
puts @cvs_reader.to_s
|
3086
|
+
if (record_index > 0)
|
3087
|
+
@cvs_reader.display_formatted_record(record_index)
|
3088
|
+
end
|
3089
|
+
@cvs_points
|
2626
3090
|
end
|
2627
3091
|
|
2628
|
-
def
|
2629
|
-
|
2630
|
-
|
3092
|
+
def been_there(course_id, proximity=0.0070, uom='deg')
|
3093
|
+
unless @cvs_points
|
3094
|
+
puts "You must first invoke method 'read_csv_files' with a list of parsed CSV filenames."
|
3095
|
+
return
|
3096
|
+
end
|
3097
|
+
course = configuration.get_course("#{course_id}")
|
3098
|
+
unless course
|
3099
|
+
puts "Unable to find course id '#{course_id}' in the gooby config yaml file."
|
3100
|
+
return
|
3101
|
+
end
|
3102
|
+
puts ''
|
3103
|
+
# collect the cvs_points into run arrays
|
3104
|
+
@curr_run_id = 'x'
|
3105
|
+
@cvs_runs = Array.new
|
3106
|
+
@cvs_points.each { |cvs_point|
|
3107
|
+
if (cvs_point.run_id == @curr_run_id)
|
3108
|
+
@curr_run.add_point(cvs_point)
|
3109
|
+
else
|
3110
|
+
@curr_run_id = cvs_point.run_id
|
3111
|
+
@curr_run = Gooby::CvsRun.new(@curr_run_id)
|
3112
|
+
@curr_run.add_point(cvs_point)
|
3113
|
+
@cvs_runs << @curr_run
|
3114
|
+
end
|
3115
|
+
}
|
3116
|
+
|
3117
|
+
# iterate the runs - looking for a match vs the course
|
3118
|
+
@cvs_runs.each { |cvs_run|
|
3119
|
+
puts "Scanning run id '#{cvs_run.id}', point count= #{cvs_run.points.size}" if false
|
3120
|
+
run_points = cvs_run.points
|
3121
|
+
course.reset
|
3122
|
+
course.points.each { |course_point|
|
3123
|
+
closest_diff = 999
|
3124
|
+
closest_point = nil
|
3125
|
+
run_points.each { |run_point|
|
3126
|
+
diff = course_point.degrees_diff(run_point)
|
3127
|
+
if ((diff < proximity) && (diff < closest_diff))
|
3128
|
+
closest_diff = diff
|
3129
|
+
closest_point = run_point
|
3130
|
+
closest_point.degrees_diff = diff
|
3131
|
+
course.matched(course_point.number, run_point)
|
3132
|
+
end
|
3133
|
+
}
|
3134
|
+
}
|
3135
|
+
if course.matched?
|
3136
|
+
puts "Course '#{course.name}' matched vs run id '#{cvs_run.id}'"
|
3137
|
+
course.display_matches
|
3138
|
+
else
|
3139
|
+
puts "course not matched" if false
|
3140
|
+
end
|
3141
|
+
}
|
3142
|
+
end
|
3143
|
+
|
3144
|
+
def generate_google_map(argv)
|
3145
|
+
if (argv == nil)
|
3146
|
+
puts "ERROR: no ARGV args passed."
|
3147
|
+
elsif (argv.size < 1)
|
3148
|
+
puts ""
|
3149
|
+
puts "Invalid program args; one required - input csv filename"
|
3150
|
+
puts " the first arg, csv filename, was produced by the Gooby 'parser.rb' program."
|
3151
|
+
puts "Please correct the program arguments and try again. \n\n"
|
3152
|
+
else
|
3153
|
+
csv_filename = argv[0]
|
3154
|
+
configuration = Gooby::Configuration.get_config
|
3155
|
+
generator = Gooby::GoogleMapGenerator.new(csv_filename)
|
3156
|
+
generator.generate_page(configuration)
|
3157
|
+
end
|
3158
|
+
|
2631
3159
|
end
|
2632
3160
|
end
|
2633
3161
|
end # end of module
|