8efe665a5f9bb93ef9e7c0d644952a0c870703f4
1 # -*- coding: utf-8 -*-
5 Munter Time Calculation
7 Wylark Mountaineering LLC
9 A rudimentary program which implements the Munter time calculation.
15 from . import __progname__
as progname
16 from . import __version__
as version
18 class InvalidUnitsException(Exception):
19 """Exception class for when invalid units are specified"""
22 'uphill': {'rate': 4, 'direction': '↑'},
23 'flat': {'rate': 6, 'direction': '→'}, # or downhill on foot
24 'downhill': {'rate': 10, 'direction': '↓'},
25 'bushwhacking': {'rate': 2, 'direction': '↹'},
34 UNIT_CHOICES
= ['metric', 'imperial']
35 TRAVEL_MODE_CHOICES
= RATES
.keys()
36 FITNESS_CHOICES
= FITNESSES
.keys()
38 def time_calc(distance
, elevation
, fitness
='average', rate
='uphill',
41 the heart of the program, the Munter time calculation implementation
45 if units
not in UNIT_CHOICES
:
46 raise InvalidUnitsException
50 if units
== 'imperial':
52 distance
= (distance
* 1.609) # mi to km
53 elevation
= (elevation
* .305) # ft to m
55 unit_count
= distance
+ (elevation
/ 100.0)
57 retval
['time'] = (distance
+ (elevation
/ 100.0)) / RATES
[rate
]['rate']
58 retval
['time'] = retval
['time'] * FITNESSES
[fitness
]
60 retval
['unit_count'] = unit_count
61 retval
['direction'] = RATES
[rate
]['direction']
62 retval
['pace'] = RATES
[rate
]['rate']
66 def print_ugly_estimate(est
):
67 """plain-jane string containing result"""
68 hours
= int(est
['time'])
69 minutes
= int((est
['time'] - hours
) * 60)
70 print("{human_time}".format(
71 human_time
="{hours} hours {minutes} minutes".format(
72 hours
=hours
, minutes
=minutes
)))
74 def print_pretty_estimate(est
):
75 """more elaborate, console-based 'GUI' displaying result"""
76 hours
= int(est
['time'])
77 minutes
= int((est
['time'] - hours
) * 60)
79 # NOTE: Below, the line with the unicode up arrow uses an alignment
80 # value of 31. In the future, consider using e.g. wcwidth
81 # library so that this is more elegant.
82 print("\n\t╒═══════════════════════════════╕")
83 print("\t╎▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒╎╮")
84 print("\t╎▒{:^29}▒╎│".format(''))
85 print("\t╎▒{pace_readable:^31}▒╎│".format(
86 pace_readable
="{units} {direction} @ {pace}".format(
87 units
=round(est
['unit_count']),
88 direction
=est
['direction'],
90 print("\t╎▒{human_time:^29}▒╎│".format(
91 human_time
="{hours} hours {minutes} minutes".format(
94 print("\t╎▒{:^29}▒╎│".format(''))
95 print("\t╎▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒╎│")
96 print("\t╘═══════════════════════════════╛│")
97 print("\t └───────────────────────────────┘\n")
100 """return ArgumentParser for this program"""
101 parser
= argparse
.ArgumentParser(description
='Implementation of '
102 'the Munter time calculation')
104 # No required args anymore, since -g overrides any requirement
105 parser
.add_argument('--distance',
110 help='Distance (in km, by default)')
112 parser
.add_argument('--elevation',
117 help='Elevation change (in m, by default)')
119 parser
.add_argument('--travel-mode',
123 choices
=TRAVEL_MODE_CHOICES
, required
=False,
124 help='Travel mode (uphill, by default)')
126 parser
.add_argument('--fitness',
130 choices
=FITNESS_CHOICES
, required
=False,
131 help='Fitness modifier (average, by default)')
133 parser
.add_argument('--units',
138 choices
=UNIT_CHOICES
,
139 help='Units of input values')
141 parser
.add_argument('--pretty',
146 help='Make output pretty')
148 parser
.add_argument('--gui',
153 help='Launch GUI mode (overrides --pretty)')
155 parser
.add_argument('--version',
160 help='Print version and exit')
165 """main routine: sort through args, decide what to do"""
166 parser
= get_parser()
167 opts
= parser
.parse_args()
169 distance
= opts
.distance
170 elevation
= opts
.elevation
171 fitness
= opts
.fitness
173 travel_mode
= opts
.travel_mode
176 get_version
= opts
.version
179 print("%s - v%s" % (progname
, version
))
182 time_estimate
= time_calc(distance
=distance
, elevation
=elevation
,
183 fitness
=fitness
, rate
=travel_mode
,
191 print_pretty_estimate(time_estimate
)
193 print_ugly_estimate(time_estimate
)
197 if __name__
== "__main__":