Slow rendering on fat machine

Topics: Data Access, WinForms Controls
Sep 27, 2007 at 1:26 PM
Hi!

I've tried the given WinForms example (modified to scale to user defined factor or if the window control size got changed).
The used shape file is randomly choosed as strassen-joined.shp from archive frida-1.0.1-shp-joined.tar.gz (can be easily found on internet site http://frida.intevation.org/download.html).
The read operation and resample operations are all very slow and taken 3-5 seconds to complete on my X5355 Intel Xeon Quad Core 2GB machine with WinXP Pro SP2 (no time consuming hidden processes).
What I'm doing wrong? It's possible, the next version (using V0.9RC) gets the things faster?

Thanks.
Coordinator
Sep 28, 2007 at 8:24 AM
Hi Alex -

I don't know exactly what the problem could be without measuring it, but I have a few guesses which might help out.

The WinForms example uses a control to display the map which is quite slow. The first and easiest way to deal with it is to limit the Layer.MaxRange so only a limited number of features in the layer are rendered.

Another speedup would come from replacing the map image control. BladeWise created a replacement map display control which works with version v0.9 / v1.0. You can find it here: Improved MapImage control.

Version 2.0 has a different rendering system. The Beta 1 speeds will be on the level of v1.0, but there is a lot of room for improvement in Beta 2 and beyond.
Sep 28, 2007 at 9:29 AM
Hi!

Thanks for suggestion. At the momemnt I use a simple PictureBox, generate Bitmap from a Map and assign this Bitmap to the Image of PictureBox. The slowest operation is generation of an image.
Can Improved MapImage control relly help with this issue?
Maybe the problem ist that I don't explicitelly load an *.shp.sidx file?
The test code (really only for tests!) is small I will post it here for suggestion. Moreover it's interesting for me to port this to V2.0.
Here the main code:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;

namespace WinFormsSharpMap
{
public partial class Form1 : Form
{
private SharpMap.Map myMap = new SharpMap.Map(new Size(1000, 1000));//null;
private SharpMap.Layers.VectorLayer myLayer = new SharpMap.Layers.VectorLayer("My ESRI vector layer");//null;
private SharpMap.Layers.LabelLayer myLabelLayer = new SharpMap.Layers.LabelLayer("My ESRI label layer");
private double iOldMapWidth = 0;
private double iOldMapHeight = 0;
private double mMaxZoomOut = 1000.0;

public Form1()
{
InitializeComponent();
}

private void button1_Click(object sender, EventArgs e)
{
openFileDialog1.ShowDialog(this);
}

private void openFileDialog1_FileOk(object sender, CancelEventArgs e)
{
OpenFileDialog iOpenFileDialog = sender as OpenFileDialog;
string iOpenFileName = iOpenFileDialog.FileName;
this.Text = iOpenFileName;

// Initialize Map
//myMap = new SharpMap.Map(pictureBox1.Size);
myMap.MinimumZoom = 0.1; // Minimum zoom 0.1 degree allowed
myMap.MaximumZoom = 360 * mMaxZoomOut; // Maximum zoom 360 degree allowed
myMap.BackColor = Color.White; // Set background color
//myMap.Center=new SharpMap.Geometries.Point(pictureBox1.Width/2, pictureBox1.Height/2); // Set center of map
myMap.Zoom = 360; // Set zoom level
myMap.Size = pictureBox1.Size; // Set ouput size

//myLayer = new SharpMap.Layers.VectorLayer("My ESRI layer");
myLayer.MinVisible = 0.1; // Minimum zoom for this layer
myLayer.MaxVisible = 360 * mMaxZoomOut; // Maximum zoom for this layer
myLayer.DataSource = new SharpMap.Data.Providers.ShapeFile(iOpenFileName, false);
myMap.Layers.Add(myLayer);

// Zoom To extend all layers
myMap.ZoomToExtents();
myMap.Size = pictureBox1.Size; // Set ouput size
GraphicsUnit iUnit = GraphicsUnit.Pixel;

// Render the map
System.Drawing.Image iImgMap = myMap.GetMap();
pictureBox1.Image = iImgMap;

// Store width and height of map-image
iOldMapWidth = pictureBox1.Image.Width;
iOldMapHeight = pictureBox1.Image.Height;

// Print zoom on Title
this.Text = "Zoom " + myMap.Zoom;// iImgMap.Size;
trackBar1.Maximum = (int)(myMap.Zoom*4.0);
trackBar1.TickFrequency = (int)(myMap.Zoom*4.0 / 10.0);

}

private void trackBar1_ValueChanged(object sender, EventArgs e)
{
TrackBar iTrackBar = sender as TrackBar;
if (myMap != null)
{
myMap.Zoom = iTrackBar.Value;
// Render the map
System.Drawing.Image iImgMap = myMap.GetMap();
pictureBox1.Image = iImgMap;
this.Text = myLayer.Theme + " Zoom value " + iTrackBar.Value;// iImgMap.Size;
//iPicBox.Refresh();
}
}
/// <summary>
/// Gets the style for each element in the country layer
/// </summary>
/// <param name="row">Element description</param>
/// <returns></returns>
private SharpMap.Styles.VectorStyle GetCountryStyle(SharpMap.Data.FeatureDataRow row)
{
SharpMap.Styles.VectorStyle style = new SharpMap.Styles.VectorStyle();
//string iNameStr = row"NAME".ToString().ToLower();
string iNameStr = row2.ToString().ToLower();
string iGroupStr = row3.ToString().ToLower();
switch (iNameStr)
{
case "denmark": // If county name is Danmark, fill it with green
style.Fill = Brushes.Green;
return style;
case "united states": // If county name is USA, fill it with blue and add a red outline
style.Fill = Brushes.Blue;
style.Outline = Pens.Red;
return style;
case "china": // If county name is China, fill it with red
style.Fill = Brushes.Red;
return style;
default:
break;
}
// if country name starts with 'S' make it yellow
if (row"NAME".ToString().StartsWith("S"))
{
style.Fill = Brushes.Yellow;
return style;
}
// If geometry is a (multi)polygon and the area of polygon is less than 30, make it cyan
else if (row.Geometry.GetType() == typeof(SharpMap.Geometries.MultiPolygon) &&
(row.Geometry as SharpMap.Geometries.MultiPolygon).Area < 30 ||
row.Geometry.GetType() == typeof(SharpMap.Geometries.Polygon) &&
(row.Geometry as SharpMap.Geometries.Polygon).Area < 30)
{
style.Fill = Brushes.Cyan;
return style;
}
else // None of the above -> use the default style
return style;
}
private SharpMap.Styles.VectorStyle GetAreasStyle(SharpMap.Data.FeatureDataRow row)
{
SharpMap.Styles.VectorStyle style = new SharpMap.Styles.VectorStyle();
//string iNameStr = row"NAME".ToString().ToLower();
string iNameStr = row2.ToString().ToLower();
string iGroupStr = row3.ToString().ToLower();
switch (iGroupStr)
{
case "wald": // If county name is Danmark, fill it with green
style.Fill = Brushes.Green;
return style;
}
// None of the above -> use the default style
return style;
}

private void checkBox1_CheckedChanged(object sender, EventArgs e)
{
CheckBox iCheckBox = sender as CheckBox;
if (iCheckBox.Checked)
{
//SharpMap.Rendering.Thematics.CustomTheme myTheme = new SharpMap.Rendering.Thematics.CustomTheme(GetCountryStyle);
SharpMap.Rendering.Thematics.CustomTheme myTheme = new SharpMap.Rendering.Thematics.CustomTheme(GetAreasStyle);
myLayer.Theme = myTheme;
}
else
{
myLayer.Theme = null;
}
// Render the map
myMap.Size = pictureBox1.Size; // Set ouput size
System.Drawing.Image iImgMap = myMap.GetMap();
pictureBox1.Image = iImgMap;
}

private void checkBox2_CheckedChanged(object sender, EventArgs e)
{
CheckBox iCheckBox = sender as CheckBox;
myLabelLayer.Enabled=iCheckBox.Checked;
// Render the map
System.Drawing.Image iImgMap = myMap.GetMap();
pictureBox1.Image = iImgMap;
}

private void pictureBox1_SizeChanged(object sender, EventArgs e)
{
PictureBox iPicBox = sender as PictureBox;

if (myMap != null)
{
myMap.Size = new Size(iPicBox.Width, iPicBox.Height);
// Render the map
System.Drawing.Image iImgMap = myMap.GetMap();
pictureBox1.Image = iImgMap;
this.Text = myLayer.Theme + " Zoom " + myMap.Zoom;// iImgMap.Size;
}

}

}
}

In V.20 SharpMap.Map has no more such properties as Zoom and other, there are part of "Presenter" class, but Presenter's are internal. If You ask, why I need the "raw presenter" is to generate an Image and put this as layer in some other Image or Window outside MapImage Control, i.e. as layer in WPF. In case of WPF it would be great to get scalable Image as XAML. Of course, it's possible to modify the code and make the class public, but this will broke the consistency with future updates. SharpMap.Layers.VectorLayer is probably an GeometryLayer but I'm not sure. And i completelly misunderstand how to use custom themes.

Thanks for any suggestions.
Coordinator
Sep 28, 2007 at 5:17 PM
Yes, you will get better performance from the MapBox control since it implements control painting in a much more advisable manner.

In v2.0, the view controls have been moved out of the Map object and to whatever implements IMapView2D. This allows the view to be separated from the model. The actual view metrics computation is done in the MapPresenter2D class, since this allows a consolidation of the view logic without having to repeat it in each view. What happens, then, is that you make a ZoomToExtents call on the IMapView2D implementation (ShaprMap.Presentation.WinForms.MapViewControl, for example), and the view delegates this call via an event to a MapPresenter2D subclass instance to do the actual computation of the view metrics. Putting the methods on the view like this allows a simple programming model which most .Net developers will feel comfortable with right away.

Once a WPF view is developed, it will also implement IMapView2D, and so the usage will be the same.

As for custom themes, Volleyknaller has a good example here: SimpleChart.
Sep 29, 2007 at 9:57 PM
Hi!

Many thanks for the answers.
The stuff with the themesI've already done for V0.9. But I don't know how to do this with V2.0. The example is also for V0.9.

I'll try how to do things with IMapView2D and see if I undestand the interface, and wait for later WPF-Presenter.

Till later :)
Dec 5, 2008 at 12:15 PM

First of all thanks for this useful sample,

I implemented in my application and it works good, but I need to know the vector layer name in side the GetAreasStyle method.

 

I’m using a special configuration style for each Layer

 

is there a way to know witch vector Layer has fire the GetAreasStyle method

 

can you help to implement some think like that :

 

private SharpMap.Styles.VectorStyle GetAreasStyle(SharpMap.Data.FeatureDataRow row, VectorLayer sender)
{

 

}