Windows Support Number

  • Subscribe to our RSS feed.
  • Twitter
  • StumbleUpon
  • Reddit
  • Facebook
  • Digg

Monday, 28 November 2011

Observations on web service design for mobile devices

Posted on 09:53 by Unknown
This post was prompted by my use of back end third party services for the FINDaPAD app and my recent set of posts about push pins and Bing Maps control. I want to explore the affect the design of the back end services can have on a mobile app UX & UI design.

For FINDaPAD we make use of two sets of third party services, Nestoria & UK Crime API. Nestoria is a property search service for the UK and other countries whilst UK Crime API provides crime information for England & Wales, we use the second to generate crime stats for a local area when viewing a property in FINDaPAD.

Even though Nestoria claim on their website 'The API is very much a work in progress.' I believe this be a well thought out API from a consumers perspective, it has a compact data schema (JSON or XML) and it enforces a pagination convention on the consumer which has a bigger benefit for mobile app development than for full blown desktop for the simple reason of CPU performance and power consumption. We use two APIs from Nestoria, one for property details and the other for average property prices - one HTTP GET request for one set of results. It has well defined pagination API which limits the maximum page size to 50.

Shown below is the performance cost of making a HTTP GET request against Nestoria on a tethered WP7 device - it takes approximately 3.7 seconds to request the first 50 properties, decode the JSON and map into a domain model. The relationship between the number of properties downloaded and the time taken to download is relatively linear and predictable and this fact is import when designing how your UI reacts when downloading data - whether it sits there with a progress bar or allows the user to perform other actions.



The UK Police API is a less mature API having been around for about a year, it allows you to query for data by several different criteria.

In FINDaPAD we have to use two separate API calls to get the information we want - two HTTP GET requests for one set of results. First we have to make a HTTP GET request with our geo-location to get the police force & neighbourhood values and then a second HTTP GET request with the result from the first to get the crime stats for the current geo-location. Now this isn't a problem per-se for FINDaPAD because we request the crime stats asynchronously whilst we are trickling the property data from Nestoria to the UI so the user experience is a seem less transition from the details of property to the crime stats for the local area. Ideally this would have been done as a single web request not only from a performance point of view but from a cost - if you're paying for your data plan on your mobile device then you would have incurred a greater cost.

In my 'How many pins...' I was using a UK Police API to return all the crimes in a particular area, this was based on the idea of supplying a geo-location and it would return all the crimes occurring within a 1 mile radius for the last calendar month. This API call works great when tested from a desktop app or the WP7 emulator because both have plenty of processor power, memory and network connectivity. But when running on a device it can be an issue because the returned data set has an unlimited size and the cost in time to transmit this down the wire, decode etc is unknown - fundamentally the API does not support pagination. This is best demonstrated by the following set of screen shots, searches for crimes in totally different locations, one a remote rural area and the other an urban inner city area:




The first screen shot shows the cost to get all the crimes in a rural area (where there are no crimes) and the second in the urban inner city you can see how the elapsed time has increased, if the total crimes in the urban area increases I don't have anyway of calculating how long it would take to request and process going results and ultimately this could lead the user to abandon the app (and give it a bad rating!).

So you might ask - Okay how would you do it then?


If I was going to keep the API endpoint the same - all crimes in a 1 mile radius. I would add pagination support so that I could trickle the data to UI as each request is fulfilled. If I was going to change the API I would like the ability to specify a bounding rectangle so I could request only the visible crimes, this would also require pagination as the number of crimes could be even greater than the 1630 show above. Though there could be a downside to the second approach as this would make client caching more problematic.

Don't be under the impression I think the UK Police API is bad or wrongly implemented, I believe this APIs will mature over time as greater understand of how the data is being used.

Remember not all publicly consumable web services are well suited for use with mobile devices.

Read More
Posted in web services mobile devices data | No comments

Wednesday, 23 November 2011

How many pins can Bing Maps handle in a WP7 app - part 3

Posted on 12:51 by Unknown
I've finally got round to finishing this 3 part series about manipulating push pins on the Bing Maps control in WP7 - the final part took longer than expected!

In the first part I showed what happens to memory usage and UI performance when you have to many pins to show and how virtualizing the pins can reduce and improve both of these. In the second part I showed how you could optimise the HTTP calls to the back end services and how scrolling around the map control can be used to start and stop the requesting of more data.

In this part what I want to show is how you can group & cluster pins and effectively remove the idea of using a pins completely but still convey the geo-location data to the user. I'll be using techniques described in the polygons posts I wrote previously to help with the grouping & clustering of pins.

For this post like the previous posts I'm going to be using the UK Police API for street level crime, see here. This API gives a lot of data when used in an urban area like London and I'll using a location based in London to show how grouping and clustering can improve the UI experience.

At the end of part 2 we still had the same UI as part 1 but it was optimised for HTTP communication to the back end services - the first screen shot shows the map with no push pins and second shows the UI at the end of the second post:


As you can see the second screenshot indicates there was 313 crimes in the visible bounding rectangle - what you can't gain from interpreting the data with pins is there are multiple crimes for the same location. Plus when there are a lot crimes we start to loose site of the map control it's self and this defeats the point of using the map control in the first place. I've also highlighted the memory usage and at the end of part 2 the memory usage was around 48 Mb which to be honest is rather high for such a simple task.

What I did to get round these issues was to use a square polygon to represent a defined area of the visible map - very similar to the way I did this in the 'tessellating polygons' posts. I then calculated if a crime occurred within this defined area and if it did the crime was added to class representing the defined area ( class called 'CrimeShape'). The first screen shot below shows the same location zoomed out with no tessellation, the second shows the squares at this resolution. As you can see we can now show more crime data, well over 1000, but at this resolution it's still hard to gain a meaningful understanding. The third screen shot is the same place at a higher resolution:


So now we've a reduced number of pins and an increased amount of crime data. What's interesting about the third screen shot is it appears there is a crime hot spot centred around the traffic junction (intersection) - 269 crimes. The memory usage is also much better, even on the second screen shot we're now peaking memory at half the previous implementation peak value.

Drilling down further into the data by increasing the resolution of the map control (via the Zoom property) and gradually reducing the square area size I get the following set of screen shots:


What you see from the fifth screen shot above is the actually crimes are not occurring at the traffic junction (intersection) they are occurring just above to the left. Determining this kind of detail wouldn't have been possible if I'd just shown pins or used a low map resolution and a course grained area granularity.

Now I think this is a great way to use the polygons on top of the map control but the use of squares doesn't quite look or feel right - they are too regular. What is required is a more irregular pattern - how about hexagons or triangles!


I really like the hexagons, it reminds me of honeycomb...

Before I get into the code and how it is structured I want to show how this data can be interpreted to generate heat map instead of using pins all together:


I get a similar affect using hexagon shapes:


Looking at the code to generate the heat map first this was achieved by binding the crime counts for an area to the Fill property of the MapPolygon class. This is more difficult than it appears and the reason being the Fill property is not a dependency property so you can't bind to it. To get round this I derived from the MapPolygon class and made Fill a dependency property:

public sealed class MapPolygonExtended : MapPolygon
{
public static readonly DependencyProperty FillProperty = DependencyProperty.RegisterAttached("Fill",
typeof(Brush),
typeof(MapPolygonExtended),
new PropertyMetadata(new PropertyChangedCallback(FillChangedCallback)));

public Brush Fill
{
get { return base.Fill; }
set { base.Fill = value; }
}

private static void FillChangedCallback(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var dlb = (MapPolygonExtended)d;
dlb.Fill = (Brush)e.NewValue;
}
}

Then using this class I'm able to bind a property from the ViewModel to the Fill property:


As you can see from the XAML above I'm using a converter to convert the CrimeCount property from the CrimeShape Model to a solid brush colour. This is where the thresholds are defined for the polygon fill colour:

public sealed class CrimeCountConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
var count = (int)value;

if (count < 3)
{
return new SolidColorBrush(Colors.Green);
}

if (count < 10)
{
return new SolidColorBrush(Colors.Orange);
}

return new SolidColorBrush(Colors.Red);
}

public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}

The CrimeShape Model aggregates the Polygon Model and is bound via the MapViewModel class. These are standard bindable Model & ViewModel classes. I'm not going to show the complete code for these classes, what is shown below is how the top level service is used to generate & group the crime data for rendering onto the map control. Whether the crime data is shown using a heat map or aggregated push pin is not defined in the ViewModel this is defined as shown above in the XAML.

private void BuildCrimeMap()
{
if (ukCrimeMapSubscriber != null)
{
log.Write("MapViewModel: Shutting down existing crime map subscriber...");
ukCrimeMapSubscriber.Dispose();
ukCrimeMapSubscriber = null;
}

log.Write("MapViewModel: Building crime map...");

if (shapeSelected)
{
crimeShapes.Clear();
}
else
{
var nonVisible = crimeShapes.Where(cs => !boundingRectangle.Intersects(cs.TileBoundingRectangle));
nonVisible.ForEach(cs => crimeShapes.Remove(cs));
}

Busy = true;
shapeSelected = false;

Func<LocationRect, double, IObservable<CrimeShape>> func = (r, s) => Observable.Empty<CrimeShape>();
if (selectedShape.Name.ToLower().Contains("square"))
{
func = (r, s) => ukCrimeMapService.TessellateSquares(boundingRectangle, selectedShape.Size);
}
else if (selectedShape.Name.ToLower().Contains("hexagon"))
{
func = (r, s) => ukCrimeMapService.TessellateHexagons(boundingRectangle, selectedShape.Size);
}
else if (selectedShape.Name.ToLower().Contains("triangle"))
{
func = (r, s) => ukCrimeMapService.TessellateTriangles(boundingRectangle, selectedShape.Size);
}

ukCrimeMapSubscriber = func(boundingRectangle, selectedShape.Size)
.ObserveOnDispatcher()
.Subscribe(crimeShape =>
{
if (crimeShapes.Any(cs => cs.Polygon == crimeShape.Polygon))
{
return;
}

crimeShapes.Add(crimeShape);
},
exception => { },
() =>
{
Busy = false;
log.Write("MapViewModel: Crime shapes count = " + crimeShapes.Count);
});
}

As you can see I'm using Rx (Reactive Extensions) again to deal with asynchronous nature of the tessellating function, not only is the method asynchronous it will return a stream of CrimeShape class instances, the number of theses is determined from the input parameters to the tessellating method. I really like the compact nature of the call to the Rx method - from the ViewModel perspective it is only 10 lines of code!

The service definition is shown below, as you can see I've tried to keep this simple and very clean:

public interface IUkCrimeMapService
{
IObservable<CrimeShape> TessellateSquares(LocationRect boundingRectangle, double size);
IObservable<CrimeShape> TessellateTriangles(LocationRect boundingRectangle, double size);
IObservable<CrimeShape> TessellateHexagons(LocationRect boundingRectangle, double size);
}

This service interface is implemented by the UkCrimeMapService class. The responiblity of this class is two-fold:

Firstly the orchestration of calls to two other services that actually do the work of generating (tessellating) the polygons - ICreatePolygons, and the work to retrieve the crime data from the UK Police back end services - IUKCrimeService.

Secondly the assignment of polygons and crime data to correct CrimeShape class instance.

public sealed class UkCrimeMapService : IUkCrimeMapService
{
private readonly ICreatePolygons polygonService;
private readonly IUkCrimeService crimeService;
private readonly ICacheProvider cacheProvider;
private readonly ILog log;
private readonly TimeSpan cacheTimeout;

public UkCrimeMapService(ICreatePolygons polygonService, IUkCrimeService crimeService, ICacheProvider cacheProvider, ISettings settings, ILog log)
{
this.polygonService = polygonService;
this.crimeService = crimeService;
this.cacheProvider = cacheProvider;
this.log = log;

cacheTimeout = TimeSpan.FromMilliseconds(settings.CacheTimeout);
}
}

The polygon generating service interface, ICreatePolygons, is defined as follows, I've removed several other mehtods to show only the relevant methods for this post. As you can see this has a similiar structure to the previous service interface:

public interface ICreatePolygons
{
IObservable<Polygon> TessellateVisibleSquares(LocationRect visibleRectangle, double size);
IObservable<Polygon> TessellateVisibleHexagons(LocationRect visibleRectangle, double size);
IObservable<Polygon> TessellateVisibleTriangles(LocationRect visibleRectangle, double size);
}

The crime service also has a simply definition, the criterion takes a geo-location for the area you want retrieve crime data for, the data is returned in a one mile radius of the location:

public interface IUkCrimeService
{
IObservable<StreetLevelCrimeResult> SearchStreetLevelCrime(StreetLevelCrimeCriterion criterion);
}

The way the call to the UkCrimeMapService orchestrates the calls to these services is as follows:
  1. The polygons service is called to tessellate polygons for the required bounding rectangle asynchronously,
  2. As each polygon is received a CrimeShape class instance is created and published, 
  3. The number of calls required to retrieve all crimes for the polygon area is calculated,
  4. This list and polygon are then pushed onto a queue to be processed by a background worker,
  5. The background worker starts processing the queue and retrieve the crime data from the UK crime service,
  6. Once all the data is returned the Rx observer is signalled as being complete and the background worker shut down.
We use caching where applicable in the services to avoid repetitively creating the same polygons or requesting the same crime data from the UK Police API.

Steps 1, 2, 3 & 4 are represented by the following two methods:

private IObservable<CrimeShape> TessellatingImpl(LocationRect boundingRectangle, double size, Func<LocationRect, double, IObservable<Polygon>> tessellatingFunc, string polygonName)
{
var crimeWorker = new CrimeWorker();
var localWorker = crimeWorker;

return Observable.Create<CrimeShape>(obs =>
{
localWorker.SetObserver(obs);
localWorker.Worker.DoWork += DoCrimeWork;
localWorker.Worker.WorkerSupportsCancellation = true;
localWorker.Worker.RunWorkerAsync(localWorker);

Scheduler.ThreadPool.Schedule(mapThrottle, o =>
{
localWorker.TessellatingDisposable = tessellatingFunc(boundingRectangle, size)
.SubscribeOn(Scheduler.ThreadPool)
.ObserveOn(Scheduler.ThreadPool)
.Subscribe(polygon => ProcessResponse(polygon, polygonName, localWorker),
FailedTessellatingPolygons,
() => CompletedTessellatingPolygons(localWorker));

mapThrottle = TimeSpan.FromMilliseconds(MapSubsequentThrottle);
});

return localWorker.Disposable;
}).Finally(() =>
{
log.Write("UkCrimeMapService: Shutting down background worker...");
crimeWorker.Dispose();
log.Write("UkCrimeMapService: Background worker shutdown...");
});
}

private void ProcessResponse(Polygon polygon, string polygonName, CrimeWorker crimeWorker)
{
var cacheKey = new CrimePolygonTuple(polygon);
var crimeShape = cacheProvider.Get<CrimePolygonTuple, CrimeShape>(cacheKey);
var criteria = Enumerable.Empty<StreetLevelCrimeCriterion>();
if (crimeShape == null)
{
crimeShape = new CrimeShape(polygon, polygonName, polygon.Size);
cacheProvider.Add(cacheKey, crimeShape, cacheTimeout);

criteria = CalculateCrimeCriteria(crimeShape.TileBoundingRectangle);
}
else if (!crimeShape.IsComplete)
{
criteria = CalculateCrimeCriteria(crimeShape.TileBoundingRectangle);
}

if (crimeWorker.IsDisposed)
{
return;
}

criteria.ForEach(c => crimeWorker.PushQueue(new CrimeCriterionTuple { CrimeShape = crimeShape, Criterion = c }));

var observer = crimeWorker.Observer;
if (observer != null)
{
crimeWorker.Observer.OnNext(crimeShape);
}
}

Could this code be used in a real world WP7 app?


The simple answer is NO!

The reason for this is not the quality of the code per-se but the fact it's using services that aren't well designed for this use. The code has all the required exception handlers, it also avoid doing work on the UI thread (Dispatcher) as much as possible and it manages the life time of the background worker correctly. What I mean by 'services that aren't well designed for this use' can be best demonstrated by the following three screen shots. The first shows the application running through the WP7 emulator and as we all know the emulator is a really bad place to measure app performance:


As you can see from the highlighted output window in visual studio the total time to create the polygons, retrieve the data from the UK police API backend services and render the heat map is less than 8 seconds!

You start thinking this is looking really promising and then you try it on a device. I tried this on my new Nokia Lumia 800:


The elapsed time has risen to 14 seconds, now you're probably thinking this isn't to bad either but what you have to remember is the device is tethered to a machine so the network type is ethernet and importantly I'm only request crime data for a small area.

When you start to look at a larger area it will increase the elapsed time greatly:


The screen shot above represents an area approximate to 3x2 miles and the time taken is over 6 minutes!

The majority of the time is consumed in retrieving the crime data, deserializing to JSON and mapping into model classes ready for use. If the UK Crime API was more mature then maybe there would be a better and more simpler way to retrieve this data - I'm going to talk about back end service design in a future post.

I've made the code available for download via SkyDrive, if you want to run the demo you'll need to register for an account with the UK Police API here.

The code makes extensive use of the WP7Contrib for help with accessing the backend HTTP services, caching of data in memory and the binding of Model classes to the UI.





Read More
Posted in WP7 Bing Maps Development UK Crime Clustering | No comments

Monday, 21 November 2011

Setting up RavenDB in IIS 7.5

Posted on 08:38 by Unknown
I started exploring RavenDB today and the first part was to get an instance running under IIS, specifically running under IIS 7.5 (Windows 7). This is a quick post to help explain a very simple issue I had because of my lack of familiarity with IIS 7.5.

I downloaded the latest binaries and followed the instructions for setting up RavenDB can be found here. This was very quick and simple, I thought I had everything working, but then I started seeing the following:



I know RavenDB is being loaded into the IIS Worker Process - because I can see 'Raven' in the error message. Apart from that 'Your request didn't match anything that Raven knows to do, sorry...' didn't really help point me in any useful direction. I can't even tell if the problem is related to RavenDB or IIS 7.5.

It turns out the problem was related to the ACL for the website configured in IIS 7.5. Specifically I hadn't associated the Application Pool Identity with the website. This link has all the background and information required to complete this association, below is the screenshot for creating the 'RavenDB' app pool association:



Once this was done I was able to run management studio and create the default database and actually start some work :)




Read More
Posted in RavenDB IIS 7.5 Development | No comments

Friday, 4 November 2011

Please welcome FINDaPAD to the WP7 app store

Posted on 10:50 by Unknown
I'm proud to announce the release of FINDaPAD into the WP7 app store, it's been a long journey working on this app and I'd like to thank my co-workers Rich & Nick for all their hard work. We've spent the last 6 months working on this at the weekends and as with all software released to market the last few weeks seem to have been the hardest.

So what is a FINDaPAD? 

FINDaPAD is a property search app for buy or rental properties in the UK housing market.

We aren't the first app to go to market offer property search services but we do believe we offer something different from a UI perspective - we've tried to follow the Metro-style guidelines for WP7 as much as possible. The app is very much designed with the idea of being used when you're out & about looking for properties and you need a quick and easy way to search the local area. You also have the ability to search locations using post code, place name or geo-location.

The rest of this post describes the technologies used in developing the app.

The app is currently NOT a mango app - yes I've said it, it's NOT a mango app. The simple reason being we started the app on the 7.0 and we took the decision in late August not to move to Mango until after we had a stable release. August might seem a long time ago but when you're trying to get something out of the door, days and weeks seem to go by very quickly indeed. The app was first submitted for approval prior to the Microsoft BUILD conference in early September and after two failed submissions it was finally approved and in the store by late September.

You might be wondering why wait until now to start talking and publicising the app? We realised after getting the app into the market place there was still plenty to do - website, twitter, PR, support, etc. We choose the achievement of a successful submission to be a soft launch of the app with friends and relatives testing and giving feedback. Since the initial release we've submitted eight updates to the market place in the last 6 weeks, these including a couple of big bug fixes and the addition of missing functionality which only became obvious after family used it to find their new home in Brighton. So now we're ready for a hard release with a PR push.

We built the app using the following APIs, frameworks & libraries:

Nestoria API - open source API providing property information for the UK and other countries,

UK Crime API - open source API providing crime stats for the UK,

WP7Contrib - we use this for all communication with back end web services, custom MVVMLight messenger, UI transitions and custom controls including SmartTextBlock,

Silverlight Toolkit - LongListSelector for infinite scrolling lists and bing maps control,

MVVMLight Toolkit - Laurent's great framework for making life with MVVM easier,

Reactive Extensions (Rx) - we use this for handling asynchronous calls and event subscriptions,

Visiblox - a great charting package for visualising data, big thanks to @ColinEberhardt,

Funq- a compact and fast DI container for WP7,

PreEmptive Solutions - post build weaving of runtime analytics into executables.

We're now working on a Mango release and hope to have this out in a couple of weeks and we're looking forward to performance improvements around HTTP compression support and fast app switching.

Until then happy property searching :)







Read More
Posted in FindaPad Property Rental Windows Phone 7 Mobile Devices | No comments

Thursday, 3 November 2011

Tessellating shapes on top of Bing Maps in a WP7 app - part 2

Posted on 15:47 by Unknown
In my previous post I showed how to tessellate polygons over Bing Maps control. This was a demonstration of how to achieving tessellation over the map control for a WP7 app. The problem is this is a sub-optimal solution from a UI perspective. This post shows how I've changed to code to use an asynchronous pattern for creating the polygons. The code is available for download.

The primary problem with the solution is not the actual calculation but 'where' the calculation was being performed. All the work was done on the main UI (Dispatcher) thread. Simply this means the app would freeze whilst calculating the required the polygons for the currently visible map area.

The secondary problem was overloading the UI thread with rendering requests. Obviously all the visible polygons need rendering to the screen, but if you chuck a lot of work at the UI thread nothing else in your app is going to be able to do any UI work until all those requests have been processed. This means at best you'll get a jerk response or at worst you'll app will freeze.

And finally there isn't any caching for already calculated polygons for a geo-location, why would we want to repeat the same work over and over again.

The first approach to address these issues is the introduction of a service interface exposing the polygon methods asynchronously:

public interface ICreatePolygons
{
ISettings Settings { get; }

Polygon Polygon(GeoCoordinate location, int sides, double diameter, double offset, double offsetBearing, double startAngle);

IObservable<Polygon> Square(GeoCoordinate centre, double size);
IObservable<Polygon> AdjacentSquares(Polygon polygon);
IObservable<Polygon> TessellateVisibleSquares(LocationRect visibleRectangle, IList<Polygon> existingPolygons, double size);

IObservable<Polygon> Hexagon(GeoCoordinate centre, double size);
IObservable<Polygon> AdjacentHexagons(Polygon polygon);
IObservable<Polygon> TessellateVisibleHexagons(LocationRect visibleRectangle, IList<Polygon> visiblePolygons, double size);

IObservable<Polygon> Triangle(GeoCoordinate centre, double size);
IObservable<Polygon> AdjacentTriangles(Polygon polygon);
IObservable<Polygon> TessellateVisibleTriangles(LocationRect visibleRectangle, IList<Polygon> visiblePolygons, double size);
}

As you can see all the methods apart from the Polygon method all return the polygons using the Rx (Reactive extensions) approach. This allows the actual work of calculating the polygons to be done on a background worker thread and solve the primary problem with the previous solution - freezing of the UI.

Shown below is the Hexagon method, what you can see is how I schedule the work onto the thread pool using Rx:

public IObservable<Polygon> Hexagon(GeoCoordinate centre, double size)
{
try
{
this.ValidateDatum();

return Observable.Create<Polygon>(obs =>
{
var disposable = new BooleanDisposable();
Scheduler.ThreadPool.Schedule(o =>
{
var polygon = CreateHexagonImpl(centre, size);

if (disposable.IsDisposed)
{
return;
}

obs.OnNext(polygon);
obs.OnCompleted();
});

return disposable;
});
}
catch (Exception exn)
{
this.log.Write(FailedHexagon, exn);
throw new ServiceException(FailedHexagon, exn);
}
}

The secondary problem is solved easily with the primary change in place. The addition of a pause to the thread calculating the adjacent  polygons when tessellating the polygons for the map control.

Shown below is the recursive method used to calculate the visible adjacent polygons, what you'll see is the 'Thread.SpinWait' added every time an adjacent polygon is found and notified to any subscribers of the observer. This allows the background thread to cease work for a fixed amount of time (default is 66 ms) without causing a context switch. I found using a delay of 66 ms was enough to allow other threads\controls enough time to do their stuff, in my case this was allow the map control to render & download tiles and allow the use interact with the UI.

private void AddVisibleAdjacentPolygons(LocationRect visibleRectangle,
Polygon polygon, ICollection<Polygon> newPolygons,
Func<Polygon, IList<Polygon>> adjacentPolygonFunc,
IObserver<Polygon> observer,
BooleanDisposable disposable)
{
foreach (var adjacentPolygon in adjacentPolygonFunc(polygon))
{
if (disposable.IsDisposed)
{
return;
}

if (!visibleRectangle.Intersects(adjacentPolygon.TileBoundingRectangle))
{
continue;
}

if (newPolygons.Contains(adjacentPolygon))
{
continue;
}

newPolygons.Add(adjacentPolygon);
observer.OnNext(adjacentPolygon);

Thread.SpinWait(this.settings.Throttle);

this.AddVisibleAdjacentPolygons(visibleRectangle, adjacentPolygon, newPolygons, adjacentPolygonFunc, observer, disposable);
}
}

The final problem is address by a standard pattern - caching. For this I'm using the WP7Contrib caching assembly. Before I show how I use the cache provider lets look at the generation times for different polygon tessellations.

Shown below is with no caching for the initial tessellation generation for 1 mile squares (on a device not in the emulator). As you can see the duration is 8247 ms:



When I move the map around in the local vicinity you can see the durations are about half of the start-up time when caching is not enabled:



When caching for adjacent polygons is enabled we get similar result for the initial start-up:



But when you compare the subsequent requests for the local vicinity you can see the time for generating the adjacent polygons has been reduced:



This demo makes use of the WP7Contrib in memory cache provider. The code for this demo app is available on SkyDrive.

Read More
Posted in WP7 Bing Maps Development UK Polygons Clustering Performance | No comments
Newer Posts Older Posts Home
Subscribe to: Posts (Atom)

Popular Posts

  • Unit testing Rx methods Timeout & Retry with moq
    Earlier this week I was trying to unit test an asynchronous service (Foo) which used another asynchronous service (Bar) internally and ran i...
  • Understanding RefCount in Reactive Extensions
    A couple of weeks ago  @LordHanson  & I ran into an issue converting a stateless async service exposed as an Rx cold observable to a  co...
  • StructureMap: ILifecycle
    The other day I wanted to control the scope of a service inside a web based app with semantics which didn't fit either 'HttpContextS...
  • MVVM anti-pattern: Injecting the IoC container into a View Model
    This is another anti-pattern I've seen a lot recently, the dynamic use of the IoC container inside a view model to resolve child view mo...
  • How many pins can Bing Maps handle in a WP7 app - part 1
    part2 -  http://awkwardcoder.blogspot.com/2011/10/how-many-pins-can-bing-maps-handle-in.html part3 -  http://awkwardcoder.blogspot.com/2011/...
  • Bad developers love 'The Daily WTF'
    When 'The Daily WTF' started up back in 2003/2004 it was a great laugh looking at shocking code other developers wrote, but after a ...
  • Using CompositeDisposable in base classes
    To help make an object eligible for collection by the GC (garbage collector) one would implement the IDisposable interface. Executing the di...
  • Implementing a busy indicator using a visual overlay in MVVM
    This is a technique we use at work to lock the UI whilst some long running process is happening - preventing the user clicking on stuff whil...
  • Daily Dilbert Service - the most important service I've ever written...
    NuGet package available here ... First off a big shout to  @hamish  &  @leeoades  on this one - I'm just blogging about it. At work ...
  • Comparing performance of .Net 4.5 to .Net 4.0 for WPF
    Currently I'm working on a .Net 4.0 WPF app and we've had some discussion about moving to .Net 4.5, we don't get to make the dec...

Categories

  • .Net
  • .Net 4.5
  • Abstractions
  • Advertising
  • Agile
  • Agile Courage
  • AOP
  • Async
  • automated testing
  • Azure
  • Azure IIS RESTful development
  • BDD
  • Bing Maps
  • Bounded Context
  • C#
  • C# 5.0
  • Caching
  • Chocolatey
  • CLoud
  • CodePlex
  • Coding
  • Coding Building CI Testing
  • Coding C#
  • coding C# IoC StructureMap
  • Coding Functional-Programming
  • Coding REST Knowledge
  • Coding Services
  • Coding TDD Refactoring Agile
  • Command
  • continuous testing
  • coupling
  • CultureInfo
  • DAL
  • databases
  • DDD
  • DDD Coaching
  • DDD Domain Events Auditing nHibernate
  • DDD Entities Value Objects
  • Debugging
  • Design Patterns
  • Design Patterns Databases Auditing
  • Developement
  • Development
  • Development Coding
  • Development Process
  • Development unit testing
  • Development VS 2011
  • Diagnostics
  • Disposable
  • Exceptions
  • FINDaPAD
  • FindaPad Property Rental Windows Phone 7 Mobile Devices
  • Fun Coding Duct-Tape
  • Hotfixes
  • integration testing
  • IoC
  • jasmine
  • javascript
  • Jobs Development
  • LINQ
  • marketplace
  • Mobile Devices
  • Mocking
  • MSDN Coding
  • MSpec
  • Multilingual
  • MVC
  • MVVM
  • nCrunch
  • nHbiernate Repository Pattern Criteria
  • nHibernate Auditing Design Fluent
  • nHibnerate Entities Events Listeners
  • node.js
  • nodes.js
  • Nokia
  • NoSQL RavenDB Azure Development
  • Observations
  • OO
  • ORM
  • Performance
  • Portable Class Library
  • Portable Library
  • PostSharp
  • Process
  • Rants
  • RavenDB IIS 7.5 Development
  • Reactive
  • Reactive Extension
  • Reactive Extensions
  • ReadOnlyCollections
  • Resharper
  • REST Distributed-Systems
  • REST HTTP
  • rest web
  • RESTful
  • Rx
  • Serialization
  • Silverlight
  • Silverlight Installation
  • Task
  • TDD
  • TDD IoC DI
  • TDD Mocking
  • TDD Team Observation
  • Telerik
  • testing
  • threading
  • TPL
  • UI
  • Undo-Redo
  • unit testing
  • ViewModels
  • VS 2012
  • wcf
  • web api
  • Web Services
  • web services mobile devices data
  • WebAPI
  • Windows
  • Windows 8
  • windows phone
  • Windows Phone 7
  • WP7
  • WP7 Bing Maps Development Network HTTP
  • WP7 Bing Maps Development UK Crime
  • WP7 Bing Maps Development UK Crime Clustering
  • WP7 Bing Maps Development UK Polygons Clustering Performance
  • WP7 cryptography bouncy castle
  • WP7 Cultures C#
  • WP7 feedback development app store
  • WP7 Javascript web browser
  • WP7 MSBuild
  • WP7 ORM Databases performance
  • WP7 Serialisation
  • WP7 SilverlightSerializer C#
  • WP7 sqlite performance development
  • WP7 WP7Contrib Bing Maps Development
  • WP7 WP7Contrib Bing Maps Polygon Development
  • WP7 WP7Contrib CodePlex
  • WP7 WP7Contrib CodePlex Bing Maps Development
  • WP7 WP7Contrib CodePlex ObservableCollection
  • WP7 WP7Contrib ILMerge .Net
  • WP7 WP7Contrib Phone Maps
  • WP7 WP7Contrib SilverlightSerializer C#
  • WP7Contrib
  • WP7Contrib Bing Maps WP7
  • WP7Contrib WP7 Geo-Location development C#
  • WP7Contrib WP7 HTTP Compression
  • WP7Contrib WP7 Url Development Rx
  • WP7Dev
  • WPF
  • WPF Cultures
  • WuApi
  • XAML

Blog Archive

  • ►  2013 (16)
    • ►  November (5)
    • ►  September (3)
    • ►  August (1)
    • ►  July (1)
    • ►  June (3)
    • ►  May (2)
    • ►  January (1)
  • ►  2012 (44)
    • ►  November (2)
    • ►  October (8)
    • ►  September (5)
    • ►  August (2)
    • ►  July (4)
    • ►  June (3)
    • ►  May (1)
    • ►  April (2)
    • ►  March (13)
    • ►  February (4)
  • ▼  2011 (52)
    • ►  December (3)
    • ▼  November (5)
      • Observations on web service design for mobile devices
      • How many pins can Bing Maps handle in a WP7 app - ...
      • Setting up RavenDB in IIS 7.5
      • Please welcome FINDaPAD to the WP7 app store
      • Tessellating shapes on top of Bing Maps in a WP7 a...
    • ►  October (7)
    • ►  September (7)
    • ►  August (11)
    • ►  July (4)
    • ►  May (2)
    • ►  April (1)
    • ►  March (5)
    • ►  February (3)
    • ►  January (4)
  • ►  2010 (1)
    • ►  August (1)
  • ►  2009 (32)
    • ►  December (3)
    • ►  November (7)
    • ►  October (6)
    • ►  September (11)
    • ►  April (1)
    • ►  March (4)
Powered by Blogger.

About Me

Unknown
View my complete profile