Changes to the version now include:
- Speed/Memory improvement using feature clipping.
- Tooltips tags for features, (mouse over a line or area to see)
The neeed for speed: performance investigation
This is where the ability to swap drawers has been helpful, I was able to create try out new ideas without having to worry about breaking the existing drawing system. One of the technique's I investigated was drawing using Silverlight's mini-language, this allows you to draw complex shapes using a LOGO like definition:
<Canvas> <Path Stroke="Black" Fill="Gray"Data="M 10,100 C 10,300 300,-200 300,100" /> </Canvas>
Since I need to draw this dynamically I need to load the Path.Data from a string:
StringBuilder sb = new StringBuilder(); sb.Append("<Path xmlns=\"http://schemas.microsoft.com/winfx/2006/xaml/presentation\""); sb.Append(" xmlns:x=\"http://schemas.microsoft.com/winfx/2006/xaml\""); sb.Append(" Data=\""); sb.Append(""); ShowWay(sb, tileBorder); foreach (var gpp in quadrant.GeoPolyPoints) DrawFeature(sb, gpp); sb.Append("\"/>"); GeometryGroup gg = new GeometryGroup(); Path uiPath = (Path)System.Windows.Markup.XamlReader.Load(sb.ToString());
using a helper function to turn a set of points into a set of draw instructions:
private void DrawFeature(StringBuilder sb, GeoPolyPoint gpp) { bool isFirst = true; foreach (GeoPoint geoPoint in gpp.GeoPoints) { int y = geoPoint.GetScaledX(viewport); int x = geoPoint.GetScaledY(viewport); if (isFirst) { isFirst = false; sb.Append(" M "); } else sb.Append("L "); sb.Append(x); sb.Append(','); sb.Append(y); } if (gpp.PolyConstruct == PolyConstruct.Polygon) sb.Append("Z "); return count; }
I then timed this against my previous attempt, and found hardly any difference - and I also tried create PathFigures, Geometries etc - these were painfully slow (mainly due to the need to create lots of LineSegment objects). So I am sticking with creating Shapes (Polygon and Polyline) as both of these take a collection of points, so no need to create lots of lines.
I then had a look at Seema's blog again and had a play with
<param name="enableRedrawRegions" value="true" />
This showed that I was updating a vast region of the screen, this seems to be related to clipping not behaving as expected - I've asked Seema for some clarification on this. However I also knew my draw routine was pretty lazy - it did not check when drawing a feature if it would even be visible on the tile (for example to the left of the tile).
I was relying on Silverlight clipping to do all the work. So I put in a simple check to only draw features that actually appear in the tile. This reduced the New Malden draw set from 26,038 features to 7,979. This means my code is drawing 3 times less shapes - a massive memory and speed improvement (10% faster), but more importantly ~20,000 shapes that Silverlight does not have to calculate, rotate, clip for no visible effect.
Once I get an answer from Seema on the clipping issue things should get even quicker!
1 comment:
use http://www.codeplex.com/StringToPathGeometry
to cover String To PathGeometry
Post a Comment