find and use layer by name, change point color

Topics: SharpMap v0.9 / v1.x
May 13, 2009 at 10:39 PM

I cannot seem to find a property of the map that allows me to locate and use a previously created vector layer, knowing the name of the layer.   I am sure this is relatively simple, just need an example.  My previously created layer name is "ReachLayer".

I can create the layer, and set a data source to a list of points that I populate programmatically:

 reachLayer.DataSource = new SharpMap.Data.Providers.GeometryProvider(nList);

The initial layer creation works just fine (thanks to previous help on this forum).

Color changing

I am using a simulation program that steps through time,   I want to update the previously created  map layer at each time step.  I know the state of the objects represented by each point at each time step.  As my simulation program progresses, I want to change the coloring of individual points on this layer, based on a known attribute of each point.

I would appreciate advice as to whether it is best to create separate layers with different styles based on the attribute, in which case I will need to remove and replace individual layers at each time step, or if there is a better way to change the layer style.

 

Thanks in advance.

 

Richard Males

Cincinnati, Ohio, USA

 

 

 

 

Coordinator
May 13, 2009 at 10:47 PM

Hi Richard,

VectorLayer layer = map.Layers["layerName"] as VectorLayer;

will get you the layer. To colour individual features you may like to consider using a CustomTheme which can color features based on an attribute

hth jd

May 14, 2009 at 4:30 PM

Thank you for your rapid reply, I completely missed the overload on map.Layers[].   As for the issue of coloring individual features, I am using a geometryprovider, which I fill by looping through an arraylist of my objects.

  Collection<Geometry> nList = new Collection<Geometry>();

            Collection<SharpMap.Geometries.Point> lList = new Collection<SharpMap.Geometries.Point>();
                                   
            reachLayerRepair.DataSource = new SharpMap.Data.Providers.GeometryProvider(nList);
           
                         
            double northing, easting;
            foreach (Reach.Reach reach in ReachesList)
            {
                SharpMap.Geometries.Point point1 = new SharpMap.Geometries.Point();
                northing = reach.Northing;
                easting = reach.Easting;
                point1.X = easting;
                point1.Y = northing;
                if (reach.InRepair)
                {
                    nList.Add(point1);
                }
            }

 

 

  So, although the reach object has many other attributes I want to use for coloring/style,  there are no attributes associated with the geometry provider, so it is unclear to me how to use custom theme when the data source is not a shape file.  The current version of SharpMap I am using does not have GeometryFeatureProvider, by browsing on the forums that may provide I solution.   I could migrate to that if it seems worthwhile.  In the meantime, my workaround is to simply develop separate layers with different styles, based on the attributes of my object (I will typically only have about 20 of these to update at each time step, so it is rather quick).

 

Thanks again for your assistance.

 

Dick Males

Coordinator
May 14, 2009 at 5:24 PM
Edited May 14, 2009 at 5:25 PM

Instead of adding your points to a collection you can add them to a FeatureDataTable and then use the GeometryFeatureProvider which can access attributes hth jd

May 14, 2009 at 5:46 PM

again, thanks for prompt reply, and all of your efforts.  I assume this requires recompiling the trunk to get at GeometryFeatureProvider, are you aware if this can be done in C# 2005 Express Edition?

As a point of interest, perhaps you can clarify why compiled trunk binaries updates are not posted on the site, as the v 09 binary available for download is dated august 2006, and is noted to be limited with respect to current capabilities.

thanks.

dick males

Coordinator
May 14, 2009 at 6:27 PM

I am not sure - I don't have any version of vs 2005 installed currently. AFAIK there is no 2008 code so it should compile as long as the csproj files are in sync with the 2008 csproj files. Failing that you could get vs2008 express and compile for .net 2 - your exisiting vs2005 projects should be able to reference them fine..

WRT trunk releases, I don't really have an answer.. I usually point tortoise at an svn and run the latest available code, I find having the code local enables more effective debugging (and general interest reading ;)) cheers jd

May 15, 2009 at 4:02 PM

thanks, got tortoise, point at trunk.  c# express 2005 will not compile, complains about multiple solutions.  I got a compiled trunk from a colleague, to work on GeometryFeatureProvider, hacked together an example from stuff found in source code, as follows - fails on myMap.ZoomToExtents(), complaining of NullReferenceException.  I gather that I am not properly setting extents somewhere, but since I am flailing here, spent a number of hours searching, any help greatly appreciated.

thanks in advance, Dick.

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

namespace SharpMapTrunkTest
{
    public partial class Form1 : Form
    {
        private SharpMap.Map myMap;
        public Form1()
        {
            InitializeComponent();
        }

        private void Form1_Load(object sender, EventArgs e)
        {
            myMap = new SharpMap.Map(mapImage1.Size);
            this.mapImage1.Map = myMap;

            SharpMap.Data.FeatureDataTable fdt = new SharpMap.Data.FeatureDataTable();

            DataTable source = createDataTableSource();

            foreach (DataColumn column in source.Columns)
            {
                fdt.Columns.Add(column.ColumnName, column.DataType);
            }

            foreach (DataRowView rowView in source.DefaultView)
            {
                 fdt.ImportRow(rowView.Row);
            }

            SharpMap.Data.Providers.GeometryFeatureProvider gfdt = new SharpMap.Data.Providers.GeometryFeatureProvider(fdt);

            SharpMap.Layers.VectorLayer layerfdt = new SharpMap.Layers.VectorLayer("george");
            layerfdt.DataSource = gfdt;
               
            layerfdt.Style.Fill = new SolidBrush(Color.Red);
            layerfdt.Style.Outline = new Pen(Color.Black);
            layerfdt.Style.EnableOutline = true;

            myMap.Layers.Add(layerfdt);
                   

            myMap.ZoomToExtents();
          

            this.mapImage1.Refresh();

        }

        private static DataTable createDataTableSource()
        {
            DataTable source = new DataTable("PointSource");
            source.Columns.AddRange(new DataColumn[] {
                new DataColumn("oid", typeof(uint)),
                new DataColumn("name", typeof(string)),
                new DataColumn("x", typeof(double)),
                new DataColumn("y", typeof(double))});

            Random rnd = new Random();
            for (int i = 0; i < 100; i++)
            {
                DataRow row = source.NewRow();
                row["oid"] = i;
                row["name"] = "Feature #" + i;
                row["x"] = rnd.NextDouble() * 1000;
                row["y"] = rnd.NextDouble() * 1000;
                source.Rows.Add(row);
            }

            return source;
        }
      
        }
   
}

 

 

Coordinator
May 16, 2009 at 1:04 PM

Hi Dick, you need to create the Geometry objects (in this case points)

private static FeatureDataTable createDataTableSource()
        {
            DataTable source = new FeatureDataTable();
            source.Columns.AddRange(new DataColumn[] {
                new DataColumn("oid", typeof(uint)),
                new DataColumn("name", typeof(string)),
                new DataColumn("x", typeof(double)),
                new DataColumn("y", typeof(double))});

            Random rnd = new Random();
            for (int i = 0; i < 100; i++)
            {

                double x,y;

                x = rnd.NextDouble() * 1000;

                y = rnd.NextDouble() * 1000;
                DataRow row = source.NewRow();
                row["oid"] = i;
                row["name"] = "Feature #" + i;
                row["x"] = x;
                row["y"] = y;

                row.Geometry = new Point(x,y);
                source.Rows.Add(row);
            }

            return source;
        }

hth jd

May 18, 2009 at 5:19 PM

Thank you, worked with some minor modifications.  For the record, my eventual solution, just colors the sample points red or yellow.

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

namespace SharpMapTrunkTest
{
    public partial class Form1 : Form
    {
        private SharpMap.Map myMap;
        public Form1()
        {
            InitializeComponent();
        }
       
        private void Form1_Load(object sender, EventArgs e)
        {
            myMap = new SharpMap.Map(mapImage1.Size);
            this.mapImage1.Map = myMap;

            SharpMap.Data.FeatureDataTable source = new SharpMap.Data.FeatureDataTable();
            source = createDataTableSource();
                     
            SharpMap.Data.Providers.GeometryFeatureProvider gfp = new SharpMap.Data.Providers.GeometryFeatureProvider(source);

            SharpMap.Layers.VectorLayer layerfdt = new SharpMap.Layers.VectorLayer("george");
            SharpMap.Rendering.Thematics.CustomTheme myTheme = new SharpMap.Rendering.Thematics.CustomTheme(GetStyle);
            layerfdt.Theme = myTheme;
            layerfdt.DataSource = gfp;
                                 
            myMap.Layers.Add(layerfdt);

            myMap.ZoomToExtents();
            this.mapImage1.Refresh();

        }

        private static SharpMap.Data.FeatureDataTable createDataTableSource()
        {
            SharpMap.Data.FeatureDataTable source = new SharpMap.Data.FeatureDataTable();

            source.Columns.AddRange(new DataColumn[] {
                new DataColumn("oid", typeof(uint)),
                new DataColumn("name", typeof(string)),
                new DataColumn("x", typeof(double)),
                new DataColumn("y", typeof(double))});

            Random rnd = new Random();
            for (int i = 0; i < 100; i++)
            {

                double x, y;

                x = rnd.NextDouble() * 1000;
                y = rnd.NextDouble() * 1000;

                SharpMap.Data.FeatureDataRow row = source.NewRow();
                row["oid"] = i;
                row["name"] = "Feature #" + i;
                row["x"] = x;
                row["y"] = y;

                row.Geometry = new SharpMap.Geometries.Point(x, y);
                source.Rows.Add(row);
            }

            return source;
                      
        }

        private SharpMap.Styles.VectorStyle GetStyle(SharpMap.Data.FeatureDataRow row)
        {
            SharpMap.Styles.VectorStyle style = new SharpMap.Styles.VectorStyle();
            uint kk = (uint) row["oid"];
            Bitmap circle = new Bitmap(20, 20);
            Graphics g = Graphics.FromImage(circle);

            if (kk > 50)
                          
            {
                    SolidBrush solidBrush = new SolidBrush(Color.Red);
                    g.FillEllipse(solidBrush, new Rectangle(5, 5, 15, 15));
                    style.Symbol = circle;
                    return style;
            }
            else
            {
               
                    SolidBrush solidBrush = new SolidBrush(Color.Yellow);
                    g.FillEllipse(solidBrush, new Rectangle(5, 5, 15, 15));
                    style.Symbol = circle;
                    return style;
            }
              

        }
        }
   
}

 

Dick

Jul 23, 2009 at 12:46 PM

Hi,

for me that's very interesting only I have to display lines instead of points. With points it's running pretty well i.e. the points change their style as it is configured in the method 'GetStyle'.

When I change the geometry of a row to

row.Geometry = new SharpMap.Geometries.LineString(pointColl);

the changed style is used for the complete line. What I'm interested in is, that the line changes it's color only from the point 'kk>50'  in the sample above.

Martin

Coordinator
Jul 23, 2009 at 4:03 PM

Hi Martin, you will have to break your line string into sub linestrings - you could do this either by preprocessing the data or on the fly with a custom provider which wraps the original one calls down to the internal provider before processing hth jd