Fuzzy Distance

Around this time last year I was playing around with fuzzy dates - that is, formatting a machine date (like the UNIX timestamp) as a human-friendly string (like, 'last week'). At the time I was working on my lifestream site and wanted to display elapsed time in a convenient manner. Now that I'm working with distances and geographic proximity I started to wonder if there was a way to use that same logical basis for fuzzy distance. Is there a consistent pattern to shorthand length to make it more readable?

Wondering how other websites were handling distance information I hopped over to a few mapping applications. In the back of my mind I knew that these examples would be a bit different than my use case, as most online maps are focused on roads (and sometimes sidewalks), but I was curious how they would display different ranges and breakpoints.

  1. Google Maps

  2. less than a tenth of a mile n feet

  3. less than a mile .n miles

  4. less than a hundred miles nn.n miles

  5. hundred miles or more nnn miles

  6. Bing Maps

  7. less than a tenth of a mile n feet

  8. less than a mile .n miles

  9. over a mile nn.n miles

This research was fairly surprising. Both Bing and Google really only have one breakpoint, at a tenth of mile, where they would switch to feet instead. Everything else was in numeric miles (either rounded up, in the case of Google at over a hundred miles, or to the closest tenth of a mile). They never worked with yards or other units, nor did they attempt to do some rounding with larger numbers (1,920 miles seems more readable than 1,921.8).

Also, there was no difference between walking, biking, or driving, with either service. Personally, I wouldn't mind changing the units based on transportation method, as someone who is walking or running may be more interested in feet or yards over tenths of a mile.

Based on this I decided to follow a few similar thoughts. I would try to be exact, as it kinda makes sense that someone would want more exact distance over time (the phrase 'yesterday' or 'a few hours ago' is more present in web applications than 'a mile or two'). Since I'm going to be using fuzzy distance for nearby waterfalls there's a decent chance that the distance could be walk-able, so I'd want to lean towards displaying information in yards or feet a bit.

So, the code. One other parameter - all of my distances are stored in meters. Because that makes sense. So I need to convert from meters to imperial before the final output. Also, all of my distances will be filtered through this logic, so I'll need to override the fuzziness. I can explain that a bit more after the code.

  1. function convertToImperial($distance, $unit_preference = false)

  2. {

  3. $distance *= 39.37; // convert meters to inches

  4. if ($unit_preference == '') {

  5. if ($distance > (12 * 3 * 1760 * 5)) {

  6. $unit_preference = 'full miles';

  7. } else if ($distance > (12 * 3 * 1760 * .5)) {

  8. $unit_preference = 'tenth miles';

  9. } else if ($distance > (12 * 3 * 150)) {

  10. $unit_preference = 'yards';

  11. } else if ($distance > (12 * 10)) {

  12. $unit_preference = 'feet';

  13. } else {

  14. $unit_preference = 'inches';

  15. }

  16. }

  17. switch ($unit_preference ) {

  18. case 'full miles' :

  19. return number_format(round($distance / (12 * 3 * 1760))) . ' miles';

  20. break;

  21. case 'tenth miles' :

  22. return round($distance / (12 * 3 * 1760), 1) . ' miles';

  23. break;

  24. case 'yards' :

  25. return number_format(round($distance / (12 * 3))) . ' yards';

  26. break;

  27. case 'feet' :

  28. return number_format(round($distance / 12)) . "'";

  29. break;

  30. case 'inches' :

  31. $feet = floor($distance / 12);

  32. $inches = $number - $feet * 12;

  33. $inches = round($inches);

  34. if ($inches == 12) {

  35. $feet++;

  36. $inches = 0;

  37. }

  38. $distance_string = '';

  39. $distance_string.= number_format($feet) . "'";

  40. if (isset($inches) && $inches > 0) {

  41. $distance_string .= " {$inches}\"";

  42. }

  43. return $distance_string;

  44. break;

  45. }

  46. }

The reason why I wanted to override the chosen unit is for elevation. I need to convert all measurements into imperial units - including elevation - and displaying elevation in yards didn't seem too smart. Plus, the override could be helpful for displaying tall waterfall heights in feet, or forcing driving direction estimates to always be in miles, etc.

Final notes: this code works, and is okay, but it really should be broken down and abstracted out quite a bit. The final output formats would make great sprintf patterns in class constants, the conversion of inches -> other units should not be duplicated, and the logic to convert/round/format should be handled by one concise method. This chunk works as a good proof for now, and depending on how it functions over time, I'll probably break it down further and make a nicely structured class.