{"id":2651,"date":"2015-12-03T21:58:17","date_gmt":"2015-12-03T12:58:17","guid":{"rendered":"https:\/\/regex.info\/blog\/2015-12-03\/2651"},"modified":"2015-12-03T21:58:17","modified_gmt":"2015-12-03T12:58:17","slug":"the-scourge-or-beauty-of-snap-to-road-with-iphone-location-tracking-apps","status":"publish","type":"post","link":"https:\/\/regex.info\/blog\/2015-12-03\/2651","title":{"rendered":"The Scourge (or Beauty) of &#8220;Snap To Road&#8221; with iPhone Location-Tracking Apps"},"content":{"rendered":"\n\n<p>I've discovered an issue with how an iPhone give location information to apps, an issue that can have <span class='nobr'>a\ndramatic<\/span> impact on the accuracy of location data. <span class='nobr'>The impact<\/span> is either really good or really bad,\ndepending on what the app (and you) want to use the location information for.<\/p>\n\n<p>The issue is that the iPhone can get into <span class='nobr'>a mode<\/span> where instead of providing apps with your location\ndirectly from its normal location-tracking methods (GPS\/GLONASS, WiFi and cell-tower signal strength), it <span\nclass='QO'>&#8220;<\/span>snaps<span class='QC'>&#8221;<\/span> the location to the center of the nearest road it knows about. <span\nclass='nobr'>I call this<\/span> <span class='QO'>&#8220;<\/span>snap to road<span class='QC'>&#8221;<\/span>; internally at Apple,\n<span class='nobr'>I hear it<\/span>'s called <span class='QO'>&#8220;<\/span>map matching<span class='QC'>&#8221;<\/span>.<\/p>\n\n<p>I can imagine that this feature is really useful for apps providing turn-by-turn driving directions.<\/p>\n\n<p>It's not so wonderful for how <span class='nobr'>I use<\/span> location-aware apps: for tracking <a\nhref='\/cycling-heatmap\/'>my cycling activity<\/a>, and for geoencoding photos, both of which are harmed by this\nroad-snap effect.<\/p>\n\n<p>Unfortunately, an app developer (and hence an app user) can not control which kind of data the app gets. I've submitted the bug\nto Apple (<span class='QO'>&#8220;<\/span><a href='https:\/\/openradar.appspot.com\/radar?id=6056041628303360'><i>CoreLocation:\nlocation snap-to-road can't be controlled by the developer<\/i><\/a><span class='QC'>&#8221;<\/span>).<\/p>\n\n<p>If you are a user of apps, or <span class='nobr'>a developer,<\/span> you can do some things to mitigate the issue, so that's\nwhat this blog post is about.<\/p>\n\n<p>First, here's an illustration of the effect in action: the two colors of the track in the image below are parts of the same\ncontinuous track. <span class='nobr'>The part colored<\/span> red is the first half, an upside-down <span\nclass='QO'>&#8220;<\/span>L<span class='QC'>&#8221;<\/span> loop, done without the road-snap effect. <span class='nobr'>You can\nsee<\/span> that it more or less tracks the outside edge of the road for the whole loop.<\/p>\n\n<div class='ic tight'><img loading=\"lazy\" decoding=\"async\" src=\"\/apple-bug-23737784\/example4.png\" width=\"690\" height=\"462\" id=\"iexample4\"\/>\n<br\/><span class='caption'>Tale of One Tracklog<\/span> <br\/>colored into two halves, the red without road snapping, the blue with\n<meta itemprop='about' content=\"Tale of One Tracklog colored into two halves, the red without road snapping, the blue\nwith\"\/><\/div>\n\n<p>Then, I did something on the phone that turned on the road-snapping effect, and drove the exact same loop again. This part of\nthe track is colored blue. <span class='nobr'>The blue line<\/span> perfectly matches the centers of the roads, and though you\ncan't tell from looking, it's actually the same loop with both <span class='QO'>&#8220;<\/span>out<span class='QC'>&#8221;<\/span>\nand <span class='QO'>&#8220;<\/span>back<span class='QC'>&#8221;<\/span> segments.... they just overwrite each other on their\nperfectly-straight road-center lines.<\/p>\n\n<p>If I were using this track to geoencode photos, <span class='nobr'>I would<\/span> certainly want to differentiate photos taken\non one side of the road from the other, but this <span class='QO'>&#8220;<\/span>snap to road<span class='QC'>&#8221;<\/span>\nfeature destroys the true data, and <span class='nobr'>I lose<\/span> that ability.<\/p>\n\n<p>Here's another example, from <a href='\/cycling-heatmap\/#15\/35.00393,135.69280\/2015112008'>this cycling\ntrip<\/a>. Here, the location track reported to the app is shown in blue. <span class='nobr'>I added<\/span> the red line to\nindicate where <span class='nobr'>I actually<\/span> rode the bicycle:<\/p>\n\n<div class='tight ic'><img loading=\"lazy\" decoding=\"async\" src=\"\/apple-bug-23737784\/example3.png\" width=\"490\" height=\"590\" id=\"iexample3\"\/>\n<br\/><span class='caption'><span class='nobr'>I Wasn't<\/span> Zig-Zagging<\/span> <meta itemprop='about' content=\"I Wasn't\nZig-Zagging\"\/><\/div>\n\n<p>The elevation between a road-side path and the road can be quite different, so besides giving the incorrect history, it can\ncontribute to incorrect ride-climb data.<\/p>\n\n<p>This road-snapping feature can also create artificial speed and distance numbers, which contributes to inflated distance and\nspeed calculations for fitness apps. <span class='nobr'>In the image<\/span> above, as the road curves away from my actual path,\nthe distance it's saying I'm covering is longer than the straight-line path I'm actually taking. Longer distance covered in the\nsame amount of time means that both the speed and distance are reported incorrectly.<\/p>\n\n<p>As a cyclist, the only thing worse than mistakes that shortchange my achievements are mistakes that inflate them.<\/p>\n\n<p>Then in the middle you can see the track suddenly jig to the left. <span class='nobr'>The road it<\/span> was snapping my\nlocation to has now drifted too far away, so it decides to snap me onto <span class='nobr'>a closer<\/span> road that I'm also not\non. That jump sees me suddenly accelerate to 87 kph for the one second required to make the adjustment, then return to the ~30kph\nspeed <span class='nobr'>I was<\/span> actually traveling at.<\/p>\n\n<p>Then there's some weirdness that happens as you near intersections... sometimes the road-snapping stuff can't decide which road\nyou're on, and so it throws you around. <span class='nobr'>You can see<\/span> it near the top of the screenshot with one data\npoint jutting out to the right. <span class='nobr'>I was on<\/span> the riverside path, down an embankment from the road, but as my\nlocation came close to the intersection above, it snapped me momentarily from one road to another, making it seem that <span\nclass='nobr'>I accelerated<\/span> to ~130kph (80mph) on my bicycle for two seconds then immediately returned to <span\nclass='nobr'>a more<\/span> human pace.<\/p>\n\n<p>Another common manifestation of this problem is seen when stopping at <span class='nobr'>a traffic<\/span> light, as illustrated here:<\/p>\n\n<div class='ic tight'><img loading=\"lazy\" decoding=\"async\" src=\"\/apple-bug-23737784\/intersection.png\" width=\"690\" height=\"621\"\nid=\"iintersection\"\/>\n<br\/><span class='caption'>Stopping at an Intersection<\/span>\n<br\/>Travel is north to south on the image-right side of the road.\n<br\/>Red line is the actual path traveled.\n<meta itemprop='about' content=\"Stopping at an Intersection Travel is north to south on the image-right side of the road. Red line is the actual path traveled.\"\/><\/div>\n\n<p>As I traveled from the north, <span class='nobr'>I had<\/span> to stop at the intersection (on the north-east side of the\nintersection; this is Japan, where traffic flows on the left) to wait for the light. While standing still, one expects <span\nclass='nobr'>a location<\/span> drift from <span class='nobr'>a consumer<\/span>-grade GPS\/GLONASS unit, but the snap-to-road <span\nclass='QO'>&#8220;<\/span>feature<span class='QC'>&#8221;<\/span> can turn it into spiky ordered disorder.<\/p>\n\n<div class='wide ic'><img loading=\"lazy\" decoding=\"async\" src=\"\/apple-bug-23737784\/example5.png\" width=\"690\" height=\"569\"\nid=\"iexample5\"\/>\n<br\/><span class='caption'>Stopping at an Intersection #2<\/span>\n<br\/>Actual travel is north to south on the image-right side of the road.\n<meta itemprop='about' content=\"Stopping at an Intersection #2 Actual travel is north to south on the image-right side of the road.\"\/><\/div>\n\n<div class='ic'><img loading=\"lazy\" decoding=\"async\" src=\"\/apple-bug-23737784\/example2.png\" width=\"690\" height=\"692\"\nid=\"iexample2\"\/>\n<br\/><span class='caption'>Stopping In Front of <span class='nobr'>a Friend's<\/span> House<\/span>\n<br\/>The spike in the top half is manufactured by the road-snap <span class='QO'>&#8220;<\/span>feature<span class='QC'>&#8221;<\/span>\n<meta itemprop='about' content=\"Stopping In Front of a Friend's House The spike in the top half is manufactured by the road-snap &amp;#8220; feature &amp;#8221;\"\/><\/div>\n\n<p>There's another wrinkle to the road-snapping issue: it seems to happen only when traveling above <span class='nobr'>a\ncertain<\/span> speed threshold, <strike>around 20~30kph (12~19mph)<\/strike>\n<b>[Update:<\/b> as reported in <a href='\/blog\/2016-01-19\/2666'>this followup post<\/a>, it\nturns on at 20kph<b>]<\/b>.<\/p>\n\n<p>This can be inferred in <span class='QO'>&#8220;<\/span>Stopping at an\nIntersection<span class='QC'>&#8221;<\/span> example above. <span class='nobr'>As I traveled<\/span> at speed from north to south,\nthe location was snapped to the center of the road until <span class='nobr'>I reached<\/span> the intersection and had to stop.\n<span class='nobr'>I didn't<\/span> accelerate quickly enough from the intersection to suffer the road snapping, so that part of\nthe track shows the actual path traveled.<\/p>\n\n<p>Yet, how does this explain the craziness while stopped at the intersection, or while stopped in front of <span class='nobr'>a building<\/span> in the\nexample immediately above? If you're not moving, you should be below the speed threshold. <span class='nobr'>My guess<\/span> is that the non-precise variability found in consumer-grade GPS\/GLONASS units (<a\nhref='\/blog\/2015-05-09\/2568#i2015_05_06_stationary1'>as illustrated here<\/a>, and especially when the unit\ndoesn't have <span class='nobr'>a good<\/span> satellite fix, <a href='\/blog\/2012-01-15\/1922#itrack_20110112_view08'>as illustrated\nhere<\/a>) creates data points that meander around your actual location, and if one meanders far enough away,\nit can appear to an unsophisticated algorithm as if the actually-stationary phone has suddenly moved far enough away (which means fast-enough away) to invoke the\nroad-snapping thing, and in its desperate attempt to match that point to the center of some road, we see these spikes that\nmake the <span class='QO'>&#8220;<\/span>non-precise variability<span class='QC'>&#8221;<\/span> so much worse.<\/p>\n\n<p>A cyclist would suffer this problem the most, as it's easy to exceed the threshold. Runners likely won't suffer\nit directly so much, except for the <span class='QO'>&#8220;<\/span>non-precise variability<span class='QC'>&#8221;<\/span> that can strike when paused.<\/p>\n\n<p>So, what causes this problem to be turned on in the first place?<\/p>\n\n<p id='activity-type'>When an app tells the iPhone that it wants location information, it has four choices\nto indicate what type of app it is. Apple's <a href='https:\/\/developer.apple.com\/library\/mac\/documentation\/CoreLocation\/Reference\/CLLocationManager_Class\/#\/\/apple_ref\/c\/tdef\/CLActivityType'>developer documentation on this<\/a> is woefully lacking details on the ramifications of the choice, but one can read something into the four names:<\/p>\n\n<ul>\n<li><span title='CLActivityTypeAutomotiveNavigation'><span style='color:#888'>CLActivityType<\/span><b>AutomotiveNavigation<\/b><\/span><\/li>\n<li><span title='CLActivityTypeFitness'             ><span style='color:#888'>CLActivityType<\/span><b>Fitness<\/b><\/span><\/li>\n<li><span title='CLActivityTypeOtherNavigation'     ><span style='color:#888'>CLActivityType<\/span><b>OtherNavigation<\/b><\/span><\/li>\n<li><span title='CLActivityTypeOther'               ><span style='color:#888'>CLActivityType<\/span><b>Other<\/b><\/span><\/li>\n<\/ul>\n\n<p>It turns out that this <span class='QO'>&#8220;<\/span>road snap<span class='QC'>&#8221;<\/span> feature is enabled <i>except<\/i> when using <span class='QO'>&#8220;<\/span>Other Navigation<span class='QC'>&#8221;<\/span>,\nwhich the docs say is intended for non-automotive navigation, e.g. planes, trains, boats, snowmobiles, etc.<\/p>\n\n<p>On the surface this makes no sense, because one would think that road snapping would apply to\n<i>only<\/i> <span class='QO'>&#8220;<\/span>Automotive Navigation<span class='QC'>&#8221;<\/span>, and certainly explicitly <i>not<\/i> apply to <span class='QO'>&#8220;<\/span>Fitness<span class='QC'>&#8221;<\/span> (predominately\nwalking, running, and cycling) or <span class='QO'>&#8220;<\/span>Other<span class='QC'>&#8221;<\/span>, where one can't make any assumptions on the use of location information.<\/p>\n\n<p style='color: #F88'>When one digs in, it makes even less sense. <span class='nobr'>It turns<\/span> out that if <i>any<\/i> app requests something other than\n<span class='QO'>&#8220;<\/span>Other Navigation<span class='QC'>&#8221;<\/span>, <i>all<\/i> apps get the road-snapped data.<\/p>\n\n<p>This means that if you don't want this <span class='QO'>&#8220;<\/span>road snap<span class='QC'>&#8221;<\/span> feature, you must run only apps that use <span class='QO'>&#8220;<\/span>Other Navigation<span class='QC'>&#8221;<\/span>.<\/p>\n\n<p>Unfortunately, it seems that fitness tracking apps unsurprisingly tend to use the <span class='QO'>&#8220;<\/span>Fitness<span class='QC'>&#8221;<\/span> activity type when registering for\nlocation information, so they suffer this problem. I've tested <b>Strava<\/b>, <b>Wahoo Fitness<\/b>, and <b>Runmeter<\/b> (aka\nCyclemeter and Walkmeter), and all invoke road snapping. <span class='nobr'>To be fair<\/span>, some users may consider this <span class='nobr'>a feature,<\/span> or consider it <span class='nobr'>a\nfeature<\/span> at times and less desirable other times. <span class='nobr'>It'd be nice<\/span> if an app gave the user explicit control over this, but none of them\ndo.<\/p>\n\n<p>The only app I've found that does not invoke road snapping is\n<strike>Galileo Offline Maps<\/strike> (Name changed Feb 2019 to <a href='https:\/\/gurumaps.app\/'>Guru Maps<\/a>), an\napp I've been recommending for years for its ability to use high-quality maps while completely offline. <span class='nobr'>In testing<\/span> this issue over\nthe last month, the developer has made special builds of his app available to me, so I'd like to think him for help in pinning\nthis issue down.<\/p>\n\n<p>I'm a geek about my data (<a href='\/blog\/2015-02-09\/2521#i066896'>as made obvious here<\/a>) so <span class='nobr'>I used<\/span>\nto keep tracks of my cycling with multiple apps. <span class='nobr'>I felt I<\/span> got the best location track from Guru Maps,\nbut Runmeter included temperature data and Wahoo Fitness included bicycle speed and cadence. <span class='nobr'>And on top<\/span> of that <span class='nobr'>I used<\/span>\n<a href='https:\/\/itunes.apple.com\/us\/app\/geotagr-versatile-photo-geotagging\/id294194869?mt=8'>GeoTagr<\/a> as <span class='nobr'>a backup<\/span>\nbecause other apps tended to spontaneously stop recording my track.<\/p>\n\n<p>But now I can't use any of them because, as mentioned above, the use of <i>any<\/i> app with road snapping infects even\nnon-snapped apps like Guru Maps. <span class='nobr'>I can't<\/span> even open up <b>Google Maps<\/b>, because it too (this time unsurprisingly),\ngets the road snapping. <span class='nobr'>So to keep<\/span> <span class='nobr'>a pure<\/span> tracklog, <span class='nobr'>I can run<\/span> only Guru and no others.<\/p>\n\n<p>The bug has been submitted to Apple. <span class='nobr'>The bug number<\/span> is #23737784, implying that there are 23.7 million other bugs\nsubmitted before me, so <span class='nobr'>I don't<\/span> hold much hope for <span class='nobr'>a response,<\/span> but it'd be very nice if<\/p>\n\n<ol>\n<li>Apple documented for developers the exact ramifications of the various CoreLocation activity types.<\/li>\n<li>Apple made the road-snapping feature something an app could explicitly turn on and off.<\/li>\n<li>Apple removed the ability for random other apps to influence the data you get.<\/li>\n<\/ol>\n\n<p>I won't hold my breath, but until it's resolved I'll stick with Guru Maps. <span class='nobr'>It's a bummer<\/span>, but I've\nremoved the Wahoo Fitness cadence\/speed unit from <a href='\/blog\/2015-10-04\/2628'>my bike<\/a>\nbecause <span class='nobr'>I haven't<\/span> found an app that can read its data without destroying my cycling track.<\/p>\n\n<p>UPDATE: I've added some details in \"<a href='\/blog\/2016-01-19\/2666' class='pt'>More Details on the Insidious iOS Snap-to-Road \u201cFeature\u201d<\/a>\".<\/p>\n\n","protected":false},"excerpt":{"rendered":"<p>I've discovered an issue with how an iPhone give location information to apps, an issue that can have a dramatic impact on the accuracy of location data. The impact is either really good or really bad, depending on what the app (and you) want to use the location information for.<\/p> <p>The issue is that the iPhone can get into a mode where instead of providing apps with your location directly from its normal location-tracking methods (GPS\/GLONASS, WiFi and cell-tower signal strength), it \"snaps\" the location to the center of the nearest road it knows about. I call this \"snap to [...]","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[30,1,4],"tags":[],"_links":{"self":[{"href":"https:\/\/regex.info\/blog\/wp-json\/wp\/v2\/posts\/2651"}],"collection":[{"href":"https:\/\/regex.info\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/regex.info\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/regex.info\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/regex.info\/blog\/wp-json\/wp\/v2\/comments?post=2651"}],"version-history":[{"count":0,"href":"https:\/\/regex.info\/blog\/wp-json\/wp\/v2\/posts\/2651\/revisions"}],"wp:attachment":[{"href":"https:\/\/regex.info\/blog\/wp-json\/wp\/v2\/media?parent=2651"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/regex.info\/blog\/wp-json\/wp\/v2\/categories?post=2651"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/regex.info\/blog\/wp-json\/wp\/v2\/tags?post=2651"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}