Double Buffering and Animation overlays

Topics: General Topics
Editor
May 16, 2013 at 12:21 PM
Hi,

This is my first post to the forum.

Have been looking at using sharp map for a project of ours and I must say it looks great. I do have a question though. I'm sure I could look through the source code and find the answer myself, but I'm a little too busy right now.

I need a mapping component that we can display animated icons (like flashing icons and moving polygons. To do this I'll probably need to set up and animation loop that redraws them a few times a second. So the first question is, does Sharpmap have any double buffering available so I could simply keep on hitting the paint event and not have the layer redrawing overhead? So of these icons may be moving too, so might already be in a variable layer.

I'm assuming that if this functionality is not here then it would probably not be too difficult to add.

Also is there any geometry editing functionality yet?

I can see there is add geometry functionality, but is there any editing?

Thanks,

Rob Smart
Coordinator
May 17, 2013 at 8:24 AM
SharpMap cannot use animated gif's as point symbols. You might achive similar functionality using VariableLayerCollection. Using VariableLayerCollection the basemap and static map components will be buffered, only the variable ones are actually requeried. There is a sample for vehicle tracking in the WinFormSamples, but unfortunatly the service has quit operating so you can't see it work.

Apart from the geometry adding functionality, there is no editing at the moment.

Hth FObermiaer
Editor
May 17, 2013 at 9:45 AM
Hi,

Sorry I should have made myself more clear.

I'm planning on handling the animation myself. So I'll have the map as the background then use an animation loop (so possibly refreshing up to 5 times a second) to animate the drawn icons (so I will be drawing them in code behind using GDI+). On every trigger of the animation loop, the icons will call a draw method, that will handle there animation, so a bit like a GIF, but done in code. I don't see this as being a big issue as you are effectively doing the same thing with the thematic themes.

Would the variable layer be able to handle this?
I tried calling the paint method on a timer and it seemed to draw the background every time. Or does this only work if there is a variable layer on the map?

I'll probably need some editing functionality so I could possibly code it myself and then try and add the code back into trunk?

Thanks for you help so far
Coordinator
May 17, 2013 at 4:04 PM
If the approach using varianble layer collection will work depends on the amount of data you are having.
If querying and rendering of the data takes more than 1/5th of a second your approach will not work.

Instead of using thematics you might want to create a custom geometry style, that returns a different icon/symbol depending on the time (Milliseconds % 200).
This will be considerably faster that using thematics as it won't involve getting attribute data (GetGeometriesInView instead of ExecuteIntersectionQuery).

Any code that will enhance SharpMap is highly appreciated.

Hth FObermaier
Editor
May 17, 2013 at 6:15 PM
Hi,

Yes that confirms what i thought. I don't think that will be too much of a problem.

Going back to the original question though, is there a way to set the map as double buffered so i can keep refreshing the graphics without it rerendering the other layers?

I'll be happy to upload any code that i generate.

Thanks
Coordinator
May 17, 2013 at 6:59 PM
If you use VariableLayersCollection only the variable layers will be redrawn. The map is then blitted using a the background image, a static image and the image of the variable layers. If you change the viewport all layers are redrawn .
Editor
May 28, 2013 at 1:51 PM
So I tried Adding OSM as the background layer, a polygon layer as normal layer and and am creating a single point geometry (using geomtryServiceProvider) into the VariableLayers collection. I've then set up a timer that shifts the point in every second and calls the mapbox.refresh method to update the position on the map.

This works fine except for when I zoom in beyond this level 1059777.50437857 (to 847822.00350286). then the point disappears. It reappears if I zoom out again (in the correct place too).

Is there some limit on the redrawing of the layers beyond a certain zoom?

This is the code:
public partial class Form1 : Form
{
    private Boolean FlashSides = false;
    private Boolean Flash = false;
    private Timer ThisTimer = new Timer();
    private SharpMap.Layers.VectorLayer MyLayer2;
    private GeoAPI.Geometries.Coordinate mousePosition;
    Graphics graphic;
    GraphicsPath path;
    private IPoint myPoint;

    public Form1()
    {
        InitializeComponent();

        ThisTimer.Tick += ThisTimer_Tick;
        ThisTimer.Interval = 1000;

        mapBox1.MapZoomChanged += mapBox1_MapZoomChanged;
    }

    void mapBox1_MapZoomChanged(double zoom)
    {
        Console.WriteLine(mapBox1.Map.Zoom);
    }



    void ThisTimer_Tick(object sender, EventArgs e)
    {

        myPoint.Coordinate.X = myPoint.Coordinate.X + 10000;

        mapBox1.Refresh();

    }



    private void Form1_Load(object sender, EventArgs e)
    {
        SharpMap.Map myMap = mapBox1.Map;

        myMap.SRID = 4326;
        var osmTileSource = new TileSource(new WebTileProvider(
new TmsRequest(new Uri("http://b.tile.openstreetmap.org"), "png"), new FileCache(@"c:\temp\BruTile", "png"))
, new SphericalMercatorInvertedWorldSchema());
        mapBox1.Map.BackgroundLayer.Add(new SharpMap.Layers.TileAsyncLayer(osmTileSource, "OSM"));

        MyLayer2 = new SharpMap.Layers.VectorLayer("MyLayer2");

        MyLayer2.DataSource = new SharpMap.Data.Providers.ShapeFile("C:\\Users\\roberts\\Downloads\\surrey-latest\\landuse_google.shp", false, false, 900913);

        //Create the style for Land
        SharpMap.Styles.VectorStyle landStyle = new SharpMap.Styles.VectorStyle();
        Color c = Color.FromArgb(80, 0, 0, 0);
        Brush b = new SolidBrush(c);
        landStyle.Fill = b; // new SolidBrush(Color.FromArgb(20,15, 255, 15));


        MyLayer2.Style = landStyle;
        mapBox1.Map.VariableLayers.Add(MyLayer2);

        AddPoint(mapBox1.Map);

        mapBox1.Refresh();

      ThisTimer.Start();

    }


    public void AddPoint(SharpMap.Map myMap)
{
    SharpMap.Layers.VectorLayer vectorLayer = new VectorLayer("GeometryLayer");

    Collection<GeoAPI.Geometries.IGeometry> geomColl = new Collection<GeoAPI.Geometries.IGeometry>();



    //Get the default geometry factory

    GeoAPI.GeometryServiceProvider.Instance = new NetTopologySuite.NtsGeometryServices();
    var gf = GeoAPI.GeometryServiceProvider.Instance.CreateGeometryFactory();

    //Add a single Point

    myPoint = gf.CreatePoint(new Coordinate(-1, 52));


    geomColl.Add(myPoint);

    System.Drawing.Image bitmapCity = Image.FromFile("C:\\cctv_camera.png");  // Mapper.Properties.Resources.city_pin;


    vectorLayer.DataSource = new SharpMap.Data.Providers.GeometryProvider(geomColl);
    myMap.VariableLayers.Add(vectorLayer);

    myMap.ZoomToExtents();

}
Coordinator
May 28, 2013 at 3:13 PM
You need to invalidate the geometries envelope by calling
myPoint.GeometryChanged();
after you changed the ordinates. If you don't, your moving point will only be displayed if the inital location is in the viewport.
If you use VariableLayerCollection, the goal is not call MapBox.Refresh. Instead, call VariableLayerCollection.TouchTimer()

Hth FObermaier
Editor
May 28, 2013 at 3:27 PM
Hi,

Thanks for the quick reply.

yes this works well.
    void ThisTimer_Tick(object sender, EventArgs e)
    {
       myPoint.Coordinate.X = myPoint.Coordinate.X + 10000;
       myPoint.GeometryChanged();
       VariableLayerCollection.TouchTimer();

       // mapBox1.Refresh();


    }

Or should I be using the variableLayers timer instead of the existing timer?
Coordinator
May 28, 2013 at 8:48 PM
I don't know what your goal eventually will be, but I'd try to derive some provider that notifies the VariableLayersCollection as soon as anything has changed using VariableLayersCollection.TouchTimer() instead of keeping it alive all the time
Editor
May 28, 2013 at 9:12 PM
Yes i agree, more of a push than pull request.

Will probably try and implement this, but might have to sort to a timer of some sorts for some other bits