WP7 Code: Distance Computations with the GeoLocation API

(This is a repost from my old MSDN blog. I haven’t verified the links, etc.)

In my previous post I showed the most interesting code fragments for a location-aware Windows Phone 7 application. The code generates an event stream corresponding to location readings from the phone’s location subsystem. However, there are many applications that instead of lat/long readings need to compute the traveled distance (for example, when driving, biking, running, or hiking). This post shows how to convert the position readings from the Windows Phone location subsystem into distance measurements.

To begin with remember that motion on earth’s surface occurs on a(n approximate) sphere rather than on a plane. Consequently Euclidean geometry no longer does it; instead, the Haversine formula provides the distance between 2 locations. As implementing Haversine in C# has nothing to do with the phone I will reuse some code surfaced by a Web search. The implementation’s use of C# extension methods is in line with what I used to bridge between .NET events and RxLINQ event streams. In addition, they make the code read like English, which is pretty neat. The C# Haversine code follows, with the argument types updated to match those from the WP7 GeoLocation API:

public enum DistanceIn { Miles, Kilometers };

public static class Haversine
{

    public static double Between(this DistanceIn @in, GeoPosition<GeoCoordinate> here, GeoPosition<GeoCoordinate> there)
{
var r = (@in == DistanceIn.Miles) ? 3960 : 6371;
var dLat = (there.Location.Latitude – here.Location.Latitude).ToRadian();
var dLon = (there.Location.Longitude – here.Location.Longitude).ToRadian();
var a = Math.Sin(dLat / 2) * Math.Sin(dLat / 2) +
Math.Cos(here.Location.Latitude.ToRadian()) * Math.Cos(there.Location.Latitude.ToRadian()) *
Math.Sin(dLon / 2) * Math.Sin(dLon / 2);
var c = 2 * Math.Asin(Math.Min(1, Math.Sqrt(a)));
var d = r * c;
return d;
}

    private static double ToRadian(this double val)
{
return (Math.PI / 180) * val;
}
}

Start with the application from my previous blog post and change the XAML (MainPage.xaml) to include a text block and a button in the content panel (new code in green):

<Grid x:Name=”ContentPanel” Grid.Row=”1″ Margin=”12,0,12,0″>
    <TextBlock Height=”30″ HorizontalAlignment=”Left” Margin=”36,69,0,0″ Name=”textBlock1″ Text=”(no reading)” VerticalAlignment=”Top” Width=”392″ />
<Button Content=”Start” Height=”84″ HorizontalAlignment=”Left” Margin=”121,493,0,0″ Name=”button1″ VerticalAlignment=”Top” Width=”227″ />
</Grid>

Next wire the button such that taps (i.e., Click events) start or stop the GeoLocationWatcher. As clicks are asynchronous events RxLINQ provides an elegant solution to deal with them. First add to the Helpers class an extension method that brings Click events into the realm of Rx:

public static IObservable<RoutedEventArgs> GetClickEventStream(this Button button)
{
return Observable.Create<RoutedEventArgs>(observable =>
{
RoutedEventHandler handler = (s, e) =>
{
observable.OnNext(e);
};
button.Click += handler;
return () => { button.Click -= handler; };
});
}

Next remove the gcw.Start() from OnNavigatedTo override and add an RxLINQ query and subscriber to the button click event stream (new code in green):

protected override void OnNavigatedTo(System.Windows.Navigation.NavigationEventArgs e)
{
base.OnNavigatedTo(e);

    if (gcw == null)
gcw = new GeoCoordinateWatcher();

    ShowGeoLocation();
}

// snip

public void ShowGeoLocation()
{
var statusChanges = from statusChanged in gcw.GetStatusChangedEventStream()
where statusChanged.Status == GeoPositionStatus.Ready
select statusChanged;

    button1.GetClickEventStream().Scan( false
, (isStarted, _) =>
{
if (isStarted)
gcw.Stop();
else
gcw.Start();
return !isStarted;
}).Subscribe(isStarted => button1.Content = isStarted ? “Stop” : “Start” );

The Scan operator allows the query to carry state from one Click event to the other. Each click event starts or stops the GeoLocationWatcher instance depending on the accumulator’s value, and then toggles it. The subscriber updates the button’s content accordingly.

Next the code must ensure that the distance computations takes into account only readings that have different lat/long values. The DistinctUntilChanged RxLINQ operator with a comparator that considers only the Latitude and Longitude values provides an elegant solution to the deduplication problem. Here’s the comparator’s code:

public class PositionComparator : IEqualityComparer<GeoPosition<GeoCoordinate>>
{

    public bool Equals(GeoPosition<GeoCoordinate> x, GeoPosition<GeoCoordinate> y)
{
return (x.Location.Latitude == y.Location.Latitude && x.Location.Longitude == y.Location.Longitude);
}

    // snip
}

And here’s the updated positions query (new code in green):

var positions = (from position in positionChanges
where position.Location.HorizontalAccuracy <= 100
select position).DistinctUntilChanged(new PositionComparator());

Computing distances requires two points. An elegant solution to using the current and previous location events is to combine the location event stream with itself such that every event pair represents the current and previous coordinates. The RxLINQ Zip operator combines the event streams, and the Skip operator provides the shift required for this pairing. Here’s the query that computes the distance in Km (for imperial units replace Kilometers with Miles):

var distances = positions.Zip(positions.Skip(1), (l, r) => DistanceIn.Kilometers.Between(r, l));

Finally, the Scan operator applied to the distances event stream computes the total distance; the accumulator’s initial value is 0.0, and the display shows meters:

var distance = distances.Scan(0.0, (a, e) => a + e);

distance.Subscribe(d => this.textBlock1.Text = string.Format(“Distance so far {0:00.000} m”,d*1000));

In summary, this post has shown:

  • How to convert Windows Phone 7 lat/long readings into distances,
  • How to use RxLINQ queries for UI (button click events), and
  • How to perform calculations on adjacent elements in an event stream via the Zip and Skip operators.
Posted in Uncategorized | Tagged | Leave a comment

WP7 Code: Using the GeoLocation API

(This is a repost from my old MSDN blog. I haven’t verified the links, etc.)

I’m kicking off a series of blog posts focused on writing Windows Phone 7 code with one of the APIs that will probably attract many developers interested in getting their feet wet: GeoLocation. Building this code requires:

Before I begin, a few things to be aware of. First, the samples are not intended to be production code. In other words, don’t use this code in your avionics system. Second, I emphasize Windows Phone code at the expense of other aspects. For example, while data binding may provide an elegant solution to updating GUI elements, I’m leaving its implementation as an exercise to the reader :) Caveat emptor.

Enough prose, let’s write some code. Start by opening a new Windows Phone Application in Visual Studio. This will create the necessary directories and unfold the appropriate templates. Add a TextBlock to the Grid called ContentPanel; the XAML will look similar to the following (new content in green):

<Grid x:Name=”ContentPanel” Grid.Row=”1″ Margin=”12,0,12,0″>
<TextBlock Height=”30″ HorizontalAlignment=”Left” Margin=”0,49,0,0″ Name=”textBlock1″ Text=”TextBlock” VerticalAlignment=”Top” Width=”450″ />
</Grid>

Next add a reference to the assembly holding the GeoLocation API (System.Device), and the appropriate using directive:

using System.Device.Location;

As Windows Phone 7 includes the .NET Reactive Framework (Rx) I will be using it for event-based code. To that end add references to System.Observable and Microsoft.Phone.Reactive, and the appropriate using directive:

using Microsoft.Phone.Reactive;

An instance of GeoLocationWatcher held in an instance variable of the MainPage class provides access to the location information. The OnNavigatedTo and OnNavigatedFrom methods ensure that the location watcher is started when the page opens, and stopped when it is abandoned.

public partial class MainPage : PhoneApplicationPage
{
GeoCoordinateWatcher gcw;

// Constructor
public MainPage()
{
InitializeComponent();
}

protected override void OnNavigatedTo(System.Windows.Navigation.NavigationEventArgs e)
{
base.OnNavigatedTo(e);

if (gcw == null)
gcw = new GeoCoordinateWatcher();

gcw.Start();

ShowGeoLocation();
}

protected override void OnNavigatedFrom(System.Windows.Navigation.NavigationEventArgs e)
{
base.OnNavigatedFrom(e);

if (gcw != null)
gcw.Stop();
}

// snip

The ShowGeoLocation method contains code that updates the UI (i.e., text box) with the location information. Before covering that code let’s go over a couple of helper methods that convert the .NET events raised by the GeoLocationWatcher class into Rx event streams. The first event of interest is StatusChanged. It signals when the location subsystem is ready and thus able to provide location information. The second event is PositionChanged, which signals whenever the position of the device, as determined by the location subsystem, changes. The following extension methods provide the corresponding event streams:

public static class Helpers
{
public static IObservable<GeoPositionStatusChangedEventArgs> GetStatusChangedEventStream(this GeoCoordinateWatcher watcher)
{
return Observable.Create<GeoPositionStatusChangedEventArgs>(observer =>
{
EventHandler<GeoPositionStatusChangedEventArgs> handler = (s, e) =>
{
observer.OnNext(e);
};
watcher.StatusChanged += handler;
return () => { watcher.StatusChanged -= handler; };
}
);
}

public static IObservable<GeoPositionChangedEventArgs<GeoCoordinate>> GetPositionChangedEventStream(this GeoCoordinateWatcher watcher)
{
return Observable.Create<GeoPositionChangedEventArgs<GeoCoordinate>>(observable =>
{
EventHandler<GeoPositionChangedEventArgs<GeoCoordinate>> handler = (s, e) =>
{
observable.OnNext(e);
};
watcher.PositionChanged += handler;
return () => { watcher.PositionChanged -= handler; };
}
);
}
}

If you’re building an application that needs to determine the position just once (e.g., what’s around me based on where I’m at) then the following sequence of queries does just that, updating the contents of the text box with the location information:

public void ShowGeoLocation()
{
var statusChanges = from statusChanged in gcw.GetStatusChangedEventStream()
where statusChanged.Status == GeoPositionStatus.Ready
select statusChanged;

var positionChanges = from s in statusChanges
from position in gcw.GetPositionChangedEventStream()
select position.Position;

var positions = from position in positionChanges
where position.Location.HorizontalAccuracy <= 100
select position;

positions.Take(1).Subscribe(firstLocationFix =>
{
textBlock1.Text = string.Format(“{0},{1}”
, firstLocationFix.Location.Latitude
, firstLocationFix.Location.Longitude
);
}
);

}

The first query (statusChanges) represents an event stream comprised of status changed events signaling that the location subsystem is ready. The second query (positionChanges) is a join between statusChanges and position changed events; this ensures that the latter is gated by the former. Finally, the third query (positions) filters the position changes based on the horizontal accuracy of each reading. The accuracy depends on how the location subsystem determines the location, and the code above discard readings below 100m accuracy. The last statement updates the UI with the first reading satisfying the (composed by now) queries:

  • Filtering of StatusChanged events by Status property
  • Joining between filtered StatusChanged events and LocationChanged events
  • Filtering of resulting LocationChanged events by HorizontalAccuracy property

What if you’re building an application that needs the series of location events (e.g., turn-by-turn navigation) rather than just one location? The Rx queries shown above remain unchanged. The only change involves how the event stream is consumed. The Take method is gone, and Action argument updates the text box contents. Here’s the ShowGeoLocation code, with the updated statement in green:

public void ShowGeoLocation()
{
var statusChanges = from statusChanged in gcw.GetStatusChangedEventStream()
where statusChanged.Status == GeoPositionStatus.Ready
select statusChanged;

var positionChanges = from s in statusChanges
from position in gcw.GetPositionChangedEventStream()
select position.Position;

var positions = from position in positionChanges
where position.Location.HorizontalAccuracy <= 100
select position;

    positions.Subscribe(position =>
{
textBlock1.Text = string.Format( “{0},{1}”
, position.Location.Latitude
, position.Location.Longitude
);
}
);

}

Even though the displayed latitude and longitude values may not change, the read values might change. To illustrate that the final update to this code adds a sequence number to the display. It also displays the horizontal accuracy. The code implements the sequence with the Scan operator (which applies an accumulator over the events) and an anonymous class encapsulating the sequence number. Here’s the ShowGeoLocation code, with the updated statement in green:

public void ShowGeoLocation()
{
var statusChanges = from statusChanged in gcw.GetStatusChangedEventStream()
where statusChanged.Status == GeoPositionStatus.Ready
select statusChanged;

var positionChanges = from s in statusChanges
from position in gcw.GetPositionChangedEventStream()
select position.Position;

var positions = from position in positionChanges
where position.Location.HorizontalAccuracy <= 1000
select position;

   positions.Scan(new { i = 0
, p = default(GeoPosition<GeoCoordinate>)
},
(a,e) => new { i = a.i + 1
, p = e }
).Subscribe(e =>
{
textBlock1.Text = string.Format( “{0}:{1},{2}@{3}”
, e.i
, e.p.Location.Latitude
, e.p.Location.Longitude
, e.p.Location.HorizontalAccuracy
);
}
);

}

In summary, this post has shown:

  • How to get started with the Windows Phone GeoLocation API,
  • How to convert the StatusChanged and PositionChanged events into Rx event streams, and
  • How to write LINQ queries against them.
Posted in Uncategorized | Tagged | 1 Comment

Pad check

Testing from the iPad app.
just testing

Posted in Uncategorized | Leave a comment

Back to regular programming

After a long period of silence micro-workflow.com is coming back to regular programming! There have been many changes since the last update: OS, software, platform, and so on. The world is a different, more exciting place now… Stay tuned; as I’m weaning from Facebook I expect more updates and tidbits here Smile

Posted in Uncategorized | Leave a comment

Asleep at the Wheel

This quick rant is about Amazon.com. Before proceeding further let me assure you that I’m a big fan, having been an Amazon.com customer for over a decade. I’ve also successfully tested their A-to-Z coverage, with my shopping history including phones, camera lenses, lawnmowers (yes, several), as well as books. Yes, they’re great!

In an older post I pointed out that Amazon’s recommendation technology didn’t allow one to specify whenever they’re purchasing gifts for others. Consequently any such purchase used to throw it off, adding noise to otherwise useful recommendations. That got fixed since then, though it took longer than I thought.

These days I’m longing for another obvious yet missing feature: the ability to sort/filter by location. I purchase used books/music/videos quite frequently, and the default sort by price (increasing in the following screenshot) no longer does it for me:

image

All online stores offer the above experience; nowadays it is the norm. If my shopping experience is any indication, an improved experience is within close reach, involving information that is already available, yet for the moment is blindly pushed from the seller database(s) onto the glass.

Personally I prefer local (or close-by) sellers vs equally (or even slightly lower) priced, but far-away ones. For the items that I buy used the shipping charges tend to be the same. Consequently, in the above example, assuming the item’s cost doesn’t vary wildly, I’d pick a seller from WA over one in CA, over one in TX, over one in MN, over one in NY. To begin with, the delivery time will be shorter. Then, assuming you care about your carbon footprint, the shorter distance translates into a lower environmental impact. However, although Amazon (or other commerce sites for that matter–this experience reflects today’s common practices) has this information readily available, it doesn’t allow me to pivot by location. Consequently I have to do it through visual inspection. Let’s see how long it takes until the location pivot becomes an integral part of the shopping experience!

Posted in Uncategorized | Leave a comment

Live Labs Web Sandbox in Your Pocket

A few weeks ago we launched Live Labs Web Sandbox, a preview for a technology that secures Web 2.0. The sandbox runs entirely in the browser, without requiring any browser add-ons or plugins. Consequently we worked hard to make it cross-browser, as the image from my post from 10/23 illustrates.

However the browser no longer belongs to the realm of desktop or laptop computers. Browsers run on mobile phones and offer capabilities on par with their traditional counterparts. We ran the Web Sandbox on the T-Mobile G1 phone, as well as on the iPhone (screenshot below). The samples from the sandbox site execute as they should. When running the overhead benchmarks the QoS layer kicks in a little earlier than on traditional platforms, reflecting the speed differential between the underlying runtimes.

Live Labs Web Sandbox on iPhone

Posted in work | Leave a comment

In the NYT Tech Section

 

The New York Times already has a story about Live Labs Sandbox, a project we’ve released just a few days ago. I am happy to see one of Live Labs‘ projects I’ve been driving from the embryonic stages receiving this kind of attention! For a closer look drop by our PDC 2008 session in L.A. or join the discussion about Web 2.0 security in the community forums available on websandbox.livelabs.com.

Posted in work | Leave a comment

Live Labs Social Streams

In the post Political Streams Online (work blog) I mentioned that I left my fingerprints on Social Streams, the platform underneath Political Streams. For those who followed my work for a while the connections are probably obvious. For those who’d like to get oriented here are a few starting points:

  • Streams fit right into data flow architectures. A Data Flow Pattern Language covers sources, filters, and sinks, as well as how they interact with each other.
  • Aggregating data from heterogeneous sources is an integration problem. Integration Patterns discusses many proven techniques for tackling those problems.

Enjoy!

Posted in patterns, work | Leave a comment

Cloud Computing and LINQ

Due to scheduling conflicts I will miss the forthcoming workshop on Cloud Computing and Its Applications (CCA08), scheduled to kick off in a couple of days in Chicago. Erik Meijer will be there to present our LINQ-to-Datacenter paper–thanks Erik!. Here’s the abstract:

A plethora of Cloud/fabric frameworks/substrates have emerged within the industry: S3/EC2, Bigtable/Sawzall, Hadoop/PigLatin. Typically these substrates have low-level, idiosyncratic interfaces with data- and query- models heavily influenced by legacy SQL.

The many choices translate into high pain of adoption by developers because of the high risk of making the wrong bet. The SQL-like query model translates into high pain of adoption because it doesn’t appeal to developers who embraced object-oriented languages like C# or Java. The SQL-like data model is suboptimal for MapReduce computations because it is not fully compositional. This conservative approach is puzzling because recent language and tool innovations such as Language Integrated Query (LINQ) address precisely the problem of compositional programming with data in modern object-oriented languages.

The proponents of the current substrates have no incentive to come up with a general and developer-friendly abstraction that hides the idiosyncrasies of their proprietary solutions and graduates from the SQL model to a modern, object-oriented and compositional style.

We propose extending the LINQ programming model to massively-parallel, data-driven computations. LINQ provides a seamless transition path from computing on top of traditional stores like relational databases or XML to computing on the Cloud. It offers an object-oriented, compositional model that hides the idiosyncrasies of the underlying substrates. We anticipate that just as the community already built custom LINQ providers for sources such as Amazon, Flickr, or SharePoint, this model will trigger a similar convergence in the space of Cloud-based storage and computation substrates.

Posted in cloud, work | 1 Comment

Building Distributed Applications with Recompilers

(Cross-posted from my work blog)

My article Volta: Developing Distributed Applications by Recompiling (co-authored with Brian Beckman and Benjamin Livshits) is now available in the Software Development Tools issue of IEEE Software (September/October 2008).

Here’s the abstract:

Mainstream languages and tools are tailored for sequential, non-distributed applications, with support for distributed computing provided only in library APIs. Such programming environments force developers to make decisions about “where-code-runs” early in the application lifecycle, structuring the entire application around partitioning decisions. Performance measurement may reveal that the original partitioning was wrong, but redistributing the application is expensive because redistributing is restructuring. We built a new kind of tool suite that recompiles executables into distributed form based on declarative user annotations, inserting most of the necessary remoting and synchronization boilerplate code, and facilitating post-hoc instrumentation to drive quantitative redistribution. Since the tools operate on the intermediate language CIL, they are compatible with a wide variety of .NET programming languages and eventual execution environments, even those that do not support .NET CIL directly, such as JavaScript.

Enjoy!

Posted in work | Leave a comment