Information Overload

Published on

We’re surrounded by information, but often we don’t know how to, and often just can’t process this information – a part of Computer Science is to do with the process of taking this information, processing it and making it usable. Take for example the idea of location, we always have a location, however often we can’t process this information into a way that’s usable – this is where we use things like GPS, which gives us our latitude, longitude and altitude to a reasonable accuracy, but longitude and latitude aren’t always useful. Take for example my recent trip to the North Yorks Moors – trying to find Dalby Forest Drive, we knew exactly where we were due to GPS and TomTom (as shown by the blue splodge below), however, we needed to get to the road marked in yellow in order to get to the Bridestones (where the yellow cross is), with the slight problem of the road with the red scribble over it being pedestrian only…

Image for Google Earth

So information overload can happen, where although you have the information you need, you can’t process it effectively, so we either need more information (in the form of a printed map, which would have been of limited use, because the road we were on wasn’t marked on any of the road maps I saw – which runs the risk of further confusing the situation), or we need help to process the information, and in our case, we used TomTom to plan another route to Dalby Forest Drive and used that to get there, albeit about an hour late.

So, I’ve spent the last 2 weeks skiing. My Dad (used to) do quite a bit of running, so he got himself a GPS ‘watch’ (which doesn’t tell the time) that can show you the route you’ve run, average speed, maximum speed, that kind of thing. My Dad’s decided to use it whilst he was skiing to figure out average speeds and stuff like that (for information, the average speed for skiing is between 20-30mph and my Dad managed to hit a max speed of about 64mph, my recorded max was 52). This information is kind of useful on its own, but to make it really useful it’d be good if you can combine it normal mapping and other geographic information software to give you a lot more information – Google Earth is a good candidate for this as it is free and has an openly documented import format. Fortunately, the Garmin Traning Centre software had the option to export an XML file containing sets of coordinates which allows for a fairly easy translation into a Google Earth KML file. So, I played around with C++ and .NET again and used their XML API to do all of this, as well as figuring out the average speed between these points.

When I put the XML file through my program (after much debugging), I got some quite interesting results (red is faster, blue is slower)

Image from Google Earth

On that, you can see the ski runs, and also it’s fairly interesting how your average speed is fairly constant over numerous runs (the run I’m centered on is a Blue called Tourmaline and the large red line up the middle is the TSD (chair lift) Grand Vans.

If anyone’s interested (I doubt you will be), I can give you a copy of the KML file for Google Earth, and I’ve included the code below (BSD licence)



#include <math.h>
#include <stdio.h>

#ifndef PI
#define PI 3.14159265
#endif

#using <System.dll>
using namespace System;
#using <System.Xml.dll>
using namespace System::Xml;

#define MAX_SPEED 20

int main() {

Double coords3, last3 = {0.0, 0.0, 0.0};
String^ current_element;
Double speed;

DateTime current_time, last_time;
XmlReader^ in_reader;
XmlWriter^ out_writer;

in_reader = XmlReader::Create(“in.xml”);
out_writer = XmlWriter::Create(“out.kml”);

out_writer→WriteStartElement(“kml”);
// out_writer→WriteAttributeString(“xmlns”, “http://earth.google.com/kml/2.0”);
out_writer→WriteStartElement(“Folder”);
out_writer→WriteElementString(“name”, “Garmin2Google Results”);

in_reader→MoveToContent();
while (in_reader→Read()) {
switch (in_reader→NodeType) {
case XmlNodeType::Element:
// If we’re dealing with a new element, store it to decide later what to do with it
current_element = in_reader→Name;
if (current_element == “Run”) {
out_writer→WriteStartElement(“Folder”);
out_writer→WriteElementString(“name”, “Run”);
}
break;
case XmlNodeType::Text:
// If we have some node content, we read it in to the appropriate coordinate
if (current_element == “LatitudeDegrees”) {
coords0 = in_reader→ReadContentAsDouble();
if (last0 == 0) {
last0 = coords0;
}
} else if (current_element == “LongitudeDegrees”) {
coords2 = in_reader→ReadContentAsDouble();
if (last2 == 0) last2 = coords2;
} else if (current_element == “AltitudeMeters”) {
coords1 = in_reader→ReadContentAsDouble();
if (last1 == 0) last1 = coords1;
} else if (current_element == “Time”) {
current_time = in_reader→ReadContentAsDateTime();
if (last_time.Ticks == 0) last_time = DateTime::Parse(current_time.ToString());
}
break;
case XmlNodeType::EndElement:
if (in_reader→Name == “Trackpoint”) {
// speed = distance (which has to be in terms of meters, so we need to normalise the coordinates from degrees into metres and then use Pythagoras theorem to figure out the distance between two points) / time
speed = sqrt(abs((((coords0 + 180) * 111320) – ((last0 + 180) * 111320)) + (coords1 – last1) + (((coords2 + 180) * 111320 * cosf(coords0 / (2 * PI))) – ((last2 + 180) * 111320 * cosf(last0 / (2 * PI))))) / (current_time.Subtract(last_time)).TotalSeconds);
// We only bother doing it if the time between points is less than 60 seconds, otherwise we can assume that the points are erroneous, e.g., the timer was stopped and started again
if ((current_time.Subtract(last_time)).TotalSeconds < 60.0) {
out_writer→WriteStartElement(“Placemark”);
out_writer→WriteStartElement(“Style”);
out_writer→WriteStartElement(“LineStyle”);
if (0.0 < speed / MAX_SPEED <= 0.0625) {
out_writer→WriteElementString(“color”, “ffff0000”);
} else if (0.0625 < speed / MAX_SPEED <= 0.125) {
out_writer→WriteElementString(“color”, “ffee0011”);
} else if (0.125 < speed / MAX_SPEED <= 0.1875) {
out_writer→WriteElementString(“color”, “ffdd0022”);
} else if (0.1875 < speed / MAX_SPEED <= 0.25) {
out_writer→WriteElementString(“color”, “ffcc0033”);
} else if (0.25 < speed / MAX_SPEED <= 0.3125) {
out_writer→WriteElementString(“color”, “ffbb0044”);
} else if (0.3125 < speed / MAX_SPEED <= 0.375) {
out_writer→WriteElementString(“color”, “ffaa0055”);
} else if (0.375 < speed / MAX_SPEED <= 0.4375) {
out_writer→WriteElementString(“color”, “ff990066”);
} else if (0.4375 < speed / MAX_SPEED <= 0.5) {
out_writer→WriteElementString(“color”, “ff880077”);
} else if (0.5 < speed / MAX_SPEED <= 0.5625) {
out_writer→WriteElementString(“color”, “ff770088”);
} else if (0.5625 < speed / MAX_SPEED <= 0.625) {
out_writer→WriteElementString(“color”, “ff660099”);
} else if (0.625 < speed / MAX_SPEED <= 0.6875) {
out_writer→WriteElementString(“color”, “ff5500aa”);
} else if (0.6875 < speed / MAX_SPEED <= 0.75) {
out_writer→WriteElementString(“color”, “ff4400bb”);
} else if (0.75 < speed / MAX_SPEED <= 0.8125) {
out_writer→WriteElementString(“color”, “ff3300cc”);
} else if (0.8125 < speed / MAX_SPEED <= 0.875) {
out_writer→WriteElementString(“color”, “ff2200dd”);
} else if (0.875 < speed / MAX_SPEED <= 0.9375) {
out_writer→WriteElementString(“color”, “ff1100ee”);
} else {
out_writer→WriteElementString(“color”, “ff0000ff”);
}
out_writer→WriteEndElement();
out_writer→WriteEndElement();
out_writer→WriteElementString(“name”, current_time.ToString());
out_writer→WriteStartElement(“LineString”);
out_writer→WriteElementString(“coordinates”, String::Concat(last2.ToString(), “,”, last0.ToString(), “,”, last1.ToString(), " ", coords2.ToString(), “,”, coords0.ToString(), “,”, coords1.ToString()));
out_writer→WriteEndElement();
out_writer→WriteEndElement();
}
last0 = coords0;
last1 = coords1;
last2 = coords2;
last_time = DateTime::Parse(current_time.ToString());
} else if (in_reader→Name == “Run”) {
last0 = 0.0;
last1 = 0.0;
last2 = 0.0;
out_writer→WriteEndElement();
}
break;
}
}
out_writer→Close();
}