Heads-I-Lose

Check-in [935d1fbeae]
Login

Many hyperlinks are disabled.
Use anonymous login to enable hyperlinks.

Overview
Comment:Handle the reverse route

I don't want to have to query OSRM for th ereverse route - it's
pointless. Instead reverse the route we already have - because I don't
actually need a properly ordered reverse route, just a list of
directions and distances.

In order to do this made sense to re-jig some of the functions a bit:

- Need date and time at top level, not buried in get_weather since
reverse route or normal route is also dependent on time of day
- Don't convert to distances and compass directions in one swoop since
it is easier to reverse the heading angles rather than compass points

Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk | origin/master
Files: files | file ages | folders
SHA3-256: 935d1fbeaec1075327e052775be8ba05e152d0e558695aaa634383c2996d7778
User & Date: base@atomicules.co.uk 2014-12-11 22:37:41
Context
2014-12-12
12:49
Commit in haste: Repent at leisure. Fix reverse journey

Had not actually tried out my changes, or, it seems, used my brain at all
in making them.

- Can't simply just add Pi on, need to keep it within 2*Pi limit
- Also forgot to get compass direction check-in: 3022ce9541 user: base@atomicules.co.uk tags: origin/master, trunk

2014-12-11
22:37
Handle the reverse route

I don't want to have to query OSRM for th ereverse route - it's
pointless. Instead reverse the route we already have - because I don't
actually need a properly ordered reverse route, just a list of
directions and distances.

In order to do this made sense to re-jig some of the functions a bit:

- Need date and time at top level, not buried in get_weather since
reverse route or normal route is also dependent on time of day
- Don't convert to distances and compass directions in one swoop since
it is easier to reverse the heading angles rather than compass points check-in: 935d1fbeae user: base@atomicules.co.uk tags: origin/master, trunk

2014-12-05
23:51
Calculate wind-type percentages and use to determine win/lose

In other words: done for now. Those are pretty much the changes I
wanted to do. Sure they will be much room for improvements to the code,
but it works! check-in: c4d0b2bbec user: base@atomicules.co.uk tags: origin/master, trunk

Changes
Hide Diffs Unified Diffs Ignore Whitespace Patch

Changes to headsilose.erl.

1
2
3
4
5
6
7
8
9
-module(headsilose).
-export([get_locations/0, get_locations/1, get_weather/1, headsilose/1]).
-include_lib("xmerl/include/xmerl.hrl").
-import(weather_types, [weather_type/1]).
-import(polyline, [decode/1]).
-import(osrm, [read_route/0]).

%Supply a direction and location and work out if head wind or not
%For now "know the location id" upfront, but ideally need to search for it at some point or present a choice.

|







1
2
3
4
5
6
7
8
9
-module(headsilose).
-export([get_locations/0, get_locations/1, headsilose/1]).
-include_lib("xmerl/include/xmerl.hrl").
-import(weather_types, [weather_type/1]).
-import(polyline, [decode/1]).
-import(osrm, [read_route/0]).

%Supply a direction and location and work out if head wind or not
%For now "know the location id" upfront, but ideally need to search for it at some point or present a choice.
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
	%Need to do this recursively
	[ #xmlAttribute{value=Location} ] = xmerl_xpath:string("@name", Node),
	[ #xmlAttribute{value=ID} ] = xmerl_xpath:string("@id", Node),
	io:format(Location++", "++ID++"~n"),
	print_locations(Rest).


get_weather(Location) ->
	inets:start(),
	Key = readapikey(),
	URL = ?BASE_URL ++ ?WXFCS_LOCATIONID ++ Location ++ "?key=" ++ Key ++ "&res=3hourly",
	Date_today = erlang:localtime(),
	{ Date_formatted, Rep } = date_and_rep(Date_today),
	try
		{ ok, {_Status, _Headers, Body }} = httpc:request(get, {URL, []}, [{timeout, timer:seconds(10)}], []),
		{ Xml, _Rest } = xmerl_scan:string(Body),
		[ [ #xmlAttribute{value=Direction} ],
		  [ #xmlAttribute{value=Speed} ],
		  [ #xmlAttribute{value=Gust} ],
		  [ #xmlAttribute{value=Weather} ],







|



<
<







56
57
58
59
60
61
62
63
64
65
66


67
68
69
70
71
72
73
	%Need to do this recursively
	[ #xmlAttribute{value=Location} ] = xmerl_xpath:string("@name", Node),
	[ #xmlAttribute{value=ID} ] = xmerl_xpath:string("@id", Node),
	io:format(Location++", "++ID++"~n"),
	print_locations(Rest).


get_weather(Location, { Date_formatted, Rep }) ->
	inets:start(),
	Key = readapikey(),
	URL = ?BASE_URL ++ ?WXFCS_LOCATIONID ++ Location ++ "?key=" ++ Key ++ "&res=3hourly",


	try
		{ ok, {_Status, _Headers, Body }} = httpc:request(get, {URL, []}, [{timeout, timer:seconds(10)}], []),
		{ Xml, _Rest } = xmerl_scan:string(Body),
		[ [ #xmlAttribute{value=Direction} ],
		  [ #xmlAttribute{value=Speed} ],
		  [ #xmlAttribute{value=Gust} ],
		  [ #xmlAttribute{value=Weather} ],
173
174
175
176
177
178
179
180
181
182
183
184



















185
186
187
188
189
190
191
	Heading_signed = math:atan2(Lon, Lat),
	%Need to convert heading into a 2π value
	Heading = if Heading_signed < 0 ->
				Heading_signed + 2*math:pi();
			true ->
				Heading_signed
			end,
	Compass_direction = get_compass_direction_for(Heading),
	convert_lats_longs_to_distance_heading_(Rest, [{Distance, Compass_direction}]++Distance_headings_list);
convert_lats_longs_to_distance_heading_([], Distance_headings_list) ->
	lists:reverse(Distance_headings_list).





















get_compass_direction_for(Heading) ->
	%In a way this is a waste of time as could just do headwind, etc based on angles, but since already have some code, why not?
	Segment = 2*math:pi()/16,
	Segments = erlang:round(Heading/Segment),
	Compass = ["N", "NNE", "NE", "ENE", "E", "ESE", "SE", "SSE", "S", "SSW", "SW", "WSW", "W", "WNW", "NW", "NNW"],
	lists:nth(Segments, Compass).







<
|



>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>







171
172
173
174
175
176
177

178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
	Heading_signed = math:atan2(Lon, Lat),
	%Need to convert heading into a 2π value
	Heading = if Heading_signed < 0 ->
				Heading_signed + 2*math:pi();
			true ->
				Heading_signed
			end,

	convert_lats_longs_to_distance_heading_(Rest, [{Distance, Heading}]++Distance_headings_list);
convert_lats_longs_to_distance_heading_([], Distance_headings_list) ->
	lists:reverse(Distance_headings_list).


journey(Distance_headings_list) ->
	lists:map(
		fun({Distance, Heading}) ->
			Compass_direction = get_compass_direction_for(Heading),
			{Distance, Compass_direction}
		end,
		Distance_headings_list).


reverse_journey(Distance_headings_list) ->
	%Don't actually need a correctly ordered reverse route, as long as we have directions and distances.
	lists:map(
		fun({Distance, Compass_direction}) ->
			Reverse_direction = Compass_direction + math:pi(),
			{Distance, Reverse_direction}
		end,
		Distance_headings_list).


get_compass_direction_for(Heading) ->
	%In a way this is a waste of time as could just do headwind, etc based on angles, but since already have some code, why not?
	Segment = 2*math:pi()/16,
	Segments = erlang:round(Heading/Segment),
	Compass = ["N", "NNE", "NE", "ENE", "E", "ESE", "SE", "SSE", "S", "SSW", "SW", "WSW", "W", "WNW", "NW", "NNW"],
	lists:nth(Segments, Compass).
204
205
206
207
208
209
210


211
212
213
214
215
216
217
218






219
220
221
222
223
224
225
226
227
228
229
230
231
232
	Tailwind ->
		tailwind
	end.
%Something like that?
	

headsilose(Location) ->


	{Direction, Speed, Gust, Weather, Temperature} = get_weather(Location),
	Weather_type = weather_types:weather_type(erlang:list_to_integer(Weather)),
	[Headwinds, Sidewinds, Tailwinds] = build_list_of_wind_directions(Direction),
	%Ok so now map this list over (like previous function) the headings list to get list of head, side, tail and distances?

	{_Checksum, Polyline} = osrm:read_route(),
	Polyline_decoded = polyline:decode(Polyline),
	Distances_and_compass_list = convert_lats_longs_to_distance_heading(Polyline_decoded),






	%If now have a set of co-ords need to figure out distances and directions
	Distances_and_wind_type_list = lists:map(
		fun({Distance, Compass}) ->
			Wind_type = head_side_or_tail_wind(Compass, [Headwinds, Sidewinds, Tailwinds]),
			{Distance, Wind_type}
		end,
		Distances_and_compass_list),
	[Headwind_distances, Sidewind_distances, Tailwind_distances] = lists:map(
		fun(Wind_type_filter) ->
			lists:filter(
				fun({_Distance, Wind_type}) ->
					Wind_type == Wind_type_filter
				end,
				Distances_and_wind_type_list)







>
>
|


<
<


|
>
>
>
>
>
>






|







220
221
222
223
224
225
226
227
228
229
230
231


232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
	Tailwind ->
		tailwind
	end.
%Something like that?
	

headsilose(Location) ->
	Date_today = erlang:localtime(),
	{ Date_formatted, Rep } = date_and_rep(Date_today),
	{Direction, Speed, Gust, Weather, Temperature} = get_weather(Location,  { Date_formatted, Rep }),
	Weather_type = weather_types:weather_type(erlang:list_to_integer(Weather)),
	[Headwinds, Sidewinds, Tailwinds] = build_list_of_wind_directions(Direction),


	{_Checksum, Polyline} = osrm:read_route(),
	Polyline_decoded = polyline:decode(Polyline),
	Distances_and_headings_list = convert_lats_longs_to_distance_heading(Polyline_decoded),
	%A better representation than 360 or 1080 would be better now this is used here as well.
	Journey = if Rep =:= "360" ->
		journey(Distances_and_headings_list);
	Rep =:= "1080" ->
		reverse_journey(Distances_and_headings_list)
	end,
	%If now have a set of co-ords need to figure out distances and directions
	Distances_and_wind_type_list = lists:map(
		fun({Distance, Compass}) ->
			Wind_type = head_side_or_tail_wind(Compass, [Headwinds, Sidewinds, Tailwinds]),
			{Distance, Wind_type}
		end,
		Journey),
	[Headwind_distances, Sidewind_distances, Tailwind_distances] = lists:map(
		fun(Wind_type_filter) ->
			lists:filter(
				fun({_Distance, Wind_type}) ->
					Wind_type == Wind_type_filter
				end,
				Distances_and_wind_type_list)