Intersection of features

Oct 29, 2009 at 7:38 PM

 

Hi All,
I have used this below code for intersection of a point geometry and a vector layer.
<code>
public SharpMap.Data.FeatureDataRow FindGeoNearPoint(SharpMap.Geometries.Point pos, SharpMap.Layers.VectorLayer layer,double amountGrow)
{
SharpMap.Geometries.BoundingBox bbox = pos.GetBoundingBox().Grow(amountGrow);
SharpMap.Data.FeatureDataSet ds = new SharpMap.Data.FeatureDataSet();
layer.DataSource.ExecuteIntersectionQuery(bbox, ds);
DataTable tbl = ds.Tables0 as SharpMap.Data.FeatureDataTable;
GisSharpBlog.NetTopologySuite.IO.WKTReader reader = new GisSharpBlog.NetTopologySuite.IO.WKTReader();
GeoAPI.Geometries.IGeometry point = reader.Read(pos.ToString());
if (tbl.Rows.Count == 0)
return null;
double distance = point.Distance(reader.Read((tbl.Rows0 as SharpMap.Data.FeatureDataRow).Geometry.ToString()));
SharpMap.Data.FeatureDataRow selectedFeature = tbl.Rows0 as SharpMap.Data.FeatureDataRow;
if (tbl.Rows.Count > 1)
for (int i = 1; i < tbl.Rows.Count; i++)
{
GeoAPI.Geometries.IGeometry line = reader.Read((tbl.Rowsi as SharpMap.Data.FeatureDataRow).Geometry.ToString());
if (point.Distance(line) < distance)
{
distance = point.Distance(line);
selectedFeature = tbl.Rowsi as SharpMap.Data.FeatureDataRow;
}
}
return selectedFeature;
}
</code>
pos: position click mouse on map
layer: layer click
amountGrow: area need grow surround pos. ( about 50 pixel)
Now You can draw geometry in datarow :
<code>
SharpMap.Data.FeatureDataRow rowSelected=FindGeoNearPoint( pointClick, layerSelected,50);
//create the selected layer
SharpMap.Layers.VectorLayer laySelected = new SharpMap.Layers.VectorLayer("Selection");
laySelected.DataSource = new SharpMap.Data.Providers.GeometryProvider(rowSelected.Geomertry);
laySelected.Style.Fill = new System.Drawing.SolidBrush(SystemColor.Hightlight);
map.Layers.Add(laySelected); //map is a gloabal variable which type is "Map"
</code>
This is working fine. Now my goal is the user will click on a polygon and the point features included in that polygon will be selected.Till now I am only able to select the polygon which the user selects with the above code.Now how am I suppose to select the points lying inside the polygon.
I am using getting the data from postgis.I have gone through the Do true intersection testing using NetTopologySuite code.But there I see that parameters for the GetIntersectingFeaturesUsingFilterDelegate method are - string pathToShapefile and SharpMap.Geometries.Geometry testGeometry.
But in my case it will be the path for point geometry in database layer and another is the polygon which the user clicks.
Please help how to achive this.
Regards,
Sayan

 

Hi All,

I have used this below code for intersection of a point geometry and a vector layer.

 

<code>

public SharpMap.Data.FeatureDataRow FindGeoNearPoint(SharpMap.Geometries.Point pos, SharpMap.Layers.VectorLayer layer,double amountGrow)

{

SharpMap.Geometries.BoundingBox bbox = pos.GetBoundingBox().Grow(amountGrow);

SharpMap.Data.FeatureDataSet ds = new SharpMap.Data.FeatureDataSet();

layer.DataSource.ExecuteIntersectionQuery(bbox, ds);

DataTable tbl = ds.Tables0 as SharpMap.Data.FeatureDataTable;

GisSharpBlog.NetTopologySuite.IO.WKTReader reader = new GisSharpBlog.NetTopologySuite.IO.WKTReader();

GeoAPI.Geometries.IGeometry point = reader.Read(pos.ToString());

if (tbl.Rows.Count == 0)

return null;

double distance = point.Distance(reader.Read((tbl.Rows0 as SharpMap.Data.FeatureDataRow).Geometry.ToString()));

SharpMap.Data.FeatureDataRow selectedFeature = tbl.Rows0 as SharpMap.Data.FeatureDataRow;

if (tbl.Rows.Count > 1)

for (int i = 1; i < tbl.Rows.Count; i++)

{

GeoAPI.Geometries.IGeometry line = reader.Read((tbl.Rowsi as SharpMap.Data.FeatureDataRow).Geometry.ToString());

if (point.Distance(line) < distance)

{

distance = point.Distance(line);

selectedFeature = tbl.Rowsi as SharpMap.Data.FeatureDataRow;

}

}

return selectedFeature;

}

</code>

pos: position click mouse on map

layer: layer click

amountGrow: area need grow surround pos. ( about 50 pixel)

Now You can draw geometry in datarow :

<code>

SharpMap.Data.FeatureDataRow rowSelected=FindGeoNearPoint( pointClick, layerSelected,50);

//create the selected layer

SharpMap.Layers.VectorLayer laySelected = new SharpMap.Layers.VectorLayer("Selection");

laySelected.DataSource = new SharpMap.Data.Providers.GeometryProvider(rowSelected.Geomertry);

laySelected.Style.Fill = new System.Drawing.SolidBrush(SystemColor.Hightlight);

map.Layers.Add(laySelected); //map is a gloabal variable which type is "Map"

</code>

 

This is working fine. Now my goal is that,the user will click on a polygon and the point features included in that polygon will be selected.Till now I am only able to select the polygon which the user selects with the above code.Now how am I suppose to select the points lying inside the polygon.

I am getting the data from postgis. I have gone through the  Do true intersection testing using NetTopologySuite . But there I see that parameters for the GetIntersectingFeaturesUsingFilterDelegate method are - string pathToShapefile and SharpMap.Geometries.Geometry testGeometry.

But in my case it will be the path for point layer in database and another is the polygon which the user clicks.

Please help how to achive this.

Regards,

Sayan

 

 

Coordinator
Oct 29, 2009 at 7:42 PM

Hi Sayan you can use the second method (PostFilterExistingFeatureDataTable) from [Do true intersection testing using NetTopologySuite] hth jd

Oct 30, 2009 at 7:38 AM

Hi Johndiss,

Hi I gone through the method (PostFilterExistingFeatureDataTable). This method takes FeatureDataTable & Geometry as parameters.

In my case I have 2 vector layer.Now How to convert them.

My code is as below -  First I am doing an intersection between the point where the user clicks and the 'State boundary layer' to get the name of state.For this I am using the (FindGeoNearPoint) which is returning the row selected.Now I wan't to do another intersection between the selected state  and 'city layer' to see how many citiies are lying inside that state. 

if (rblMapTools.SelectedValue == "5")

        {

 

            SharpMap.Geometries.Point p = myMap.ImageToWorld(new System.Drawing.Point(e.X, e.Y));

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

            layphc.DataSource = new SharpMap.Data.Providers.PostGIS("Server=localhost;Port=5432;User;Password=san@123;Database=postgis", "State_boundary", "gid");

            SharpMap.Data.FeatureDataRow rowSelected = FindGeoNearPoint(p, layphc, 50);

            SharpMap.Layers.VectorLayer laySelected = new SharpMap.Layers.VectorLayer("Selection");

            laySelected.DataSource = new SharpMap.Data.Providers.GeometryProvider(rowSelected.Geometry);           

            laySelected.Style.Fill = new System.Drawing.SolidBrush(Color.Yellow);

            myMap.Layers.Add(laySelected);

 

      }

 

The FindGeoNearPoint method goes like this -

 

public SharpMap.Data.FeatureDataRow FindGeoNearPoint(SharpMap.Geometries.Point pos, SharpMap.Layers.VectorLayer layer, double amountGrow)

    {

        SharpMap.Geometries.BoundingBox bbox = pos.GetBoundingBox().Grow(amountGrow);

        SharpMap.Data.FeatureDataSet ds = new SharpMap.Data.FeatureDataSet();

        layer.DataSource.ExecuteIntersectionQuery(bbox, ds);

        DataTable tbl = ds.Tables[0] as SharpMap.Data.FeatureDataTable;

        GisSharpBlog.NetTopologySuite.IO.WKTReader reader = new GisSharpBlog.NetTopologySuite.IO.WKTReader();

        GeoAPI.Geometries.IGeometry point = reader.Read(pos.ToString());

        if (tbl.Rows.Count == 0)

            return null;

 

        double distance = point.Distance(reader.Read((tbl.Rows[0] as SharpMap.Data.FeatureDataRow).Geometry.ToString()));

        SharpMap.Data.FeatureDataRow selectedFeature = tbl.Rows[0] as SharpMap.Data.FeatureDataRow;

 

        if (tbl.Rows.Count > 1)

            for (int i = 1; i < tbl.Rows.Count; i++)

            {

                GeoAPI.Geometries.IGeometry line = reader.Read((tbl.Rows[i] as SharpMap.Data.FeatureDataRow).Geometry.ToString());

                if (point.Distance(line) < distance)

                {

                    distance = point.Distance(line);

                    selectedFeature = tbl.Rows[i] as SharpMap.Data.FeatureDataRow;

                }

            }

        return selectedFeature;      

 

    }

 

Please help.

 

Thanks in advance ,

Sayan

 

 

 

Coordinator
Oct 30, 2009 at 3:46 PM

Hi sayan, now you just need to take the geometry from the row from the state boundary layer, take the bounding box from the geometry and use that to query the city layer.

You will then use the same geometry from the state boundary row to do the PostFilterExistingFeatureDataTable method against the found city features...

hth jd

Oct 30, 2009 at 6:52 PM

Hi Johndiss,

Thanks for the help.I have understood to what you said.I feel I am very close.

I am not getting how to take the geometry from the row from the state boundary layer and take the bounding box from the geometry.Please help with a piece of code so that I can carry on with the rest.

Once I get the bounding box from the geometry then I need to do the query with the city layer.Did you mean by this ExecuteIntersectionQuery??

And after that I need to call the PostFilterExistingFeatureDataTable method. I got what you said.

But please help me with "how to take the geometry from the row from the state boundary layer and take the bounding box from the geometry".

Previously I have created bounding box for a point.But I am not sure to take the geometry and create bounding box  for polygon row selected.

Tiill now I have - SharpMap.Data.FeatureDataRow rowSelected = FindGeoNearPoint(p, layphc, 50); // rowSelected is containing the state row which is selected by the user.

 

Thanks in advance.

Sayan

Coordinator
Oct 30, 2009 at 9:33 PM

Hi Sayan, Unfortunately I dont have enough time to write an example but: Geometry is a property on the FeatureDataRow (which is the type of row you will have in the FeatureDataTable returned from ExecuteIntersectionQuery)

The geometry then has a method GetBoundingBox() whcih you can use to get the box to pass into the second ExecuteIntersectionQuery

hth jd

Nov 1, 2009 at 1:45 PM

Hi Johndiss,

Thanks for a simpler explanation.I got it right. But I am having another problem off late. After the last intersection query I have bind all the cities falling on a state to a dropdown list.Now my goal is to select a city from the dropdown list and it should zoom to that feature(In my case its city).

But the problem I am facing is I have only the feature name(i.e, the name of the city) in the dropdown list. So how to get the handle on the corresponding row so that I can create a bounding box for that feature geometry and zoom to that box.

Sorry for asking simple questions. I am still very new.

Thanks in advance,

Regards,

Sayan

 

Coordinator
Nov 1, 2009 at 2:19 PM

Hi again Sayan, are you binding to the FeatureDataTable or to a list of strings? if you are binding to the FeatureDataTable you can still get at the Geometry through the SelectedItem property of the ComboBox... hth jd

Nov 1, 2009 at 5:35 PM

Hi Johndiss,

I think it is list of strings.To be sure, this is the way I did -

 

public void PostFilterExistingFeatureDataTable(FeatureDataTable featureDataTable, SharpMap.Geometries.Geometry testGeometry)
    {
        //first we create a new GeometryFactory.
        GisSharpBlog.NetTopologySuite.Geometries.GeometryFactory geometryFactory = new GisSharpBlog.NetTopologySuite.Geometries.GeometryFactory();
        //then we convert the testGeometry into the equivalent NTS geometry
        GisSharpBlog.NetTopologySuite.Geometries.Geometry testGeometryAsNtsGeom =
            SharpMap.Converters.NTS.GeometryConverter.ToNTSGeometry(testGeometry, geometryFactory);
        //now we loop backwards through the FeatureDataTable 
        for (int i = featureDataTable.Rows.Count - 1; i > -1; i--)
        {
            
            //we get each row
            FeatureDataRow featureDataRow = featureDataTable.Rows[i] as FeatureDataRow;
            //and get the rows' geometry
            SharpMap.Geometries.Geometry compareGeometry = featureDataRow.Geometry;
            //convert the rows' geometry into the equivalent NTS geometry
            GisSharpBlog.NetTopologySuite.Geometries.Geometry compareGeometryAsNts = SharpMap.Converters.NTS.GeometryConverter.ToNTSGeometry(compareGeometry, geometryFactory);


              
            //now test for intesection (note other operations such as Contains, Within, Disjoint etc can all be done the same way)
            bool intersects = testGeometryAsNtsGeom.Intersects(compareGeometryAsNts);
            //if it doesn't intersect remove the row.
            if (!intersects)
            {
                featureDataTable.Rows.RemoveAt(i);
             }
                                   
        }
        DropDownList1.DataSource = featureDataTable;
        DropDownList1.DataTextField = featureDataTable.Columns["city_name"].ColumnName.ToString();
        DropDownList1.DataValueField = featureDataTable.Columns["gid"].ColumnName.ToString();
        DropDownList1.DataBind();

Thanks and Regards,
Sayan

 

 

Coordinator
Nov 1, 2009 at 6:23 PM

Hi Sayan, are you using an asp.net DropDownList or a winforms ComboBox. From your code you are binding to the FeatureDataTable. If it is winforms you can get to the Geometry from the SelectedItem property if it is asp.net then you will need to requery the datasource using the text string to query, see the DefinitionQery property of the PostGIS2 provider hth jd 

Nov 1, 2009 at 8:46 PM
Edited Nov 1, 2009 at 8:48 PM

Hi Johndiss,

I am using asp.net. Sorry for not mentioning that before. I have checked the DefinitionQuery but not able to be sure.

Can I use it like this -

)

 protected void DropDownList1_SelectedIndexChanged(object sender, EventArgs e)
     {
      FeatureDataSet fs = new FeatureDataSet();
      SharpMap.Layers.VectorLayer laycity = new SharpMap.Layers.VectorLayer("laycity");
      string a = DropDownList1.SelectedItem.Value;
      SharpMap.Data.Providers.PostGIS provider = new SharpMap.Data.Providers.PostGIS("Server=localhost;Port=5432;User Id=postgres;Password=sam@123;Database=postgis", "city_table", "gid");
      provider.DefinitionQuery = "city_name = a";    // Here city_name is the field name.
      laycity.DataSource = provider;
Also after this is it that I need to get the row of the feature to zoom into it. If so then how to get the row from the DataDource??

Thanks for consistent help.
Regards,
Sayan

      

 

 

Coordinator
Nov 2, 2009 at 10:18 AM

Hi Sayan, you need to quote the value:

provider.DefinitionQuery = "city_name = 'a'";

To get at the row you would either call provider.ExecuteIntersectionQuery passing in the whole layer extents. Alternatively you could use the rowId as the value in your dropdownlist and then call provider.GetFeature(rowId) to get the individual row

 

hth jd

Nov 4, 2009 at 3:20 PM
Edited Nov 4, 2009 at 3:27 PM

Hi Jhondiss,

I am able to get the row by performing ExecuteIntersectionQuery and also have bind the FeatureDataSet Table  to a datagrid which is showing correct result.

I have taken the boundingbox of the FeatureDataRow geometry but I am unable to zoom to the box.I am not getting where I am wrong.It is not showing any error.

My goal is when I select a city from the dropdownlist then the map should zoom to that city.City is point layer.

 

  protected void DropDownList1_SelectedIndexChanged(object sender, EventArgs e)
     {
      
        FeatureDataSet fs = new FeatureDataSet();
        SharpMap.Layers.VectorLayer mylaycity = new SharpMap.Layers.VectorLayer("laycity");
        string a = DropDownList1.SelectedItem.Value;
        SharpMap.Data.Providers.PostGIS provider = new SharpMap.Data.Providers.PostGIS("Server=localhost;Port=5432;User Id=postgres;Password=sam@123;Database=postgis", "city_table", "gid");
        mylaycity.DataSource = provider;
        provider.DefinitionQuery = "gid =" + a; // Here city_name is the field name.
       provider.ExecuteIntersectionQuery(mylaycity.DataSource.GetExtents(), fs);
        SharpMap.Data.FeatureDataRow rowSelect = fs.Tables[0].Rows[0] as FeatureDataRow ;
        SharpMap.Geometries.BoundingBox QueryBox1 = rowSelect.Geometry.GetBoundingBox();
        myMap.ZoomToBox(QueryBox1);  // Zoom to box
        GridView1.DataSource = fs.Tables[0];
        GridView1.DataBind();
    }


Please help.
Thanks and Regards,
Sayan

 

 

Coordinator
Nov 4, 2009 at 4:03 PM

The code you have there sets the bounding box of the map but does not actually re-render or update any UI. you need to call myMap.GetMap() to get a bitmap and display it somewhere.. hth jd

Nov 4, 2009 at 5:06 PM

Hi Johndiss,

Thanks for the suggestion. And sorry for giving you trouble.

I have added a CreateMap() method.

  protected void DropDownList1_SelectedIndexChanged(object sender, EventArgs e)
     {
      
        FeatureDataSet fs = new FeatureDataSet();
        SharpMap.Layers.VectorLayer mylaycity = new SharpMap.Layers.VectorLayer("laycity");
        string a = DropDownList1.SelectedItem.Value;
        SharpMap.Data.Providers.PostGIS provider = new SharpMap.Data.Providers.PostGIS("Server=localhost;Port=5432;User Id=postgres;Password=sam@123;Database=postgis", "city_table", "gid");
        mylaycity.DataSource = provider;
        provider.DefinitionQuery = "gid =" + a; // Here city_name is the field name.
       provider.ExecuteIntersectionQuery(mylaycity.DataSource.GetExtents(), fs);
        SharpMap.Data.FeatureDataRow rowSelect = fs.Tables[0].Rows[0] as FeatureDataRow ;
        SharpMap.Geometries.BoundingBox QueryBox1 = rowSelect.Geometry.GetBoundingBox();
        myMap.ZoomToBox(QueryBox1);  // Zoom to box
	CreateMap();
        GridView1.DataSource = fs.Tables[0];
        GridView1.DataBind();
    }
The create map goes like this -
    private void CreateMap()
    {
        System.Drawing.Image img = myMap.GetMap();
        string imgID = SharpMap.Web.Caching.InsertIntoCache(1, img);
        imgMap.ImageUrl = "getmap.aspx?ID=" + HttpUtility.UrlEncode(imgID);
    }

But when I zoom the map display becomes white.And nothing is visible.Is it because of the zoom scale??
How to zoom to the feature.
When I render the feature, I can do it and also highlight with style option.But unable to zoom into the feature.


Thanks and Regards,
Sayan
    private void CreateMap()
    {
        System.Drawing.Image img = myMap.GetMap();
        string imgID = SharpMap.Web.Caching.InsertIntoCache(1, img);
        imgMap.ImageUrl = "getmap.aspx?ID=" + HttpUtility.UrlEncode(imgID);
    }


        
    
Coordinator
Nov 4, 2009 at 5:35 PM

Hi Sayan, do you get a broken image or a real image that is just white? It may be that the render styles are disabled at the zoom level you have zoomed to apart from looking at that I dont really know what to suggest.. hth jd

Nov 4, 2009 at 6:17 PM
Hi Johndiss,

I get a real image that is white .Can I specify the zoom level of ZoomToBox?

Also when I render the label along with the feature which I select, I get an error "Attribute data is not supported by the GeometryProvider" .This error is at -

private void CreateMap()
    {
        System.Drawing.Image img = myMap.GetMap(); \\Attribute data is not supported by the GeometryProvider
        string imgID = SharpMap.Web.Caching.InsertIntoCache(1, img);
        imgMap.ImageUrl = "getmap.aspx?ID=" + HttpUtility.UrlEncode(imgID);
    }
My code goes like this -
protected void DropDownList1_SelectedIndexChanged(object sender, EventArgs e)
     {
      
        FeatureDataSet fs = new FeatureDataSet();
        SharpMap.Layers.VectorLayer mylaycity = new SharpMap.Layers.VectorLayer("laycity");
        string a = DropDownList1.SelectedItem.Value;
        SharpMap.Data.Providers.PostGIS provider = new SharpMap.Data.Providers.PostGIS("Server=localhost;Port=5432;User Id=postgres;Password=sam@123;Database=postgis", "city_table", "gid");
        mylaycity.DataSource = provider;
        provider.DefinitionQuery = "gid =" + a; // Here city_name is the field name.
       provider.ExecuteIntersectionQuery(mylaycity.DataSource.GetExtents(), fs);

        SharpMap.Data.FeatureDataRow rowSelect = fs.Tables[0].Rows[0] as FeatureDataRow ;
      //  SharpMap.Geometries.BoundingBox QueryBox1 = rowSelect.Geometry.GetBoundingBox();
       // myMap.ZoomToBox(QueryBox1);  // Zoom to box
	
        SharpMap.Layers.VectorLayer layselect = new SharpMap.Layers.VectorLayer("select");
SharpMap.Layers.VectorLayer layselect = new SharpMap.Layers.VectorLayer("select"); layselect.DataSource = new SharpMap.Data.Providers.GeometryProvider(rowSelect.Geometry); layselect.Style.Symbol = new Bitmap(@"C:\citysymbol.jpg"); layselect.Style.SymbolScale = 0.1f; myMap.Layers.Add(layselect);
        layselect.DataSource = new SharpMap.Data.Providers.GeometryProvider(rowSelect.Geometry);
        layselect.Style.Symbol = new Bitmap(@"C:\hab1.jpg");
SharpMap.Layers.LabelLayer layselectLabel = new SharpMap.Layers.LabelLayer("layselect labels"); layselectLabel.DataSource = layselect.DataSource; layselectLabel.Enabled = true; layselectLabel.LabelColumn = "city_name"; layselectLabel.Style = new SharpMap.Styles.LabelStyle(); layselectLabel.Style.ForeColor = Color.Black; //layCityLabel.Style.Font = new Font(FontFamily.GenericSerif, 11); layselectLabel.Style.Font = new Font("Trebuchet MS", 11); layselectLabel.Style.HorizontalAlignment = SharpMap.Styles.LabelStyle.HorizontalAlignmentEnum.Left; layselectLabel.Style.VerticalAlignment = SharpMap.Styles.LabelStyle.VerticalAlignmentEnum.Bottom; layselectLabel.Style.Offset = new PointF(3, 3); layselectLabel.Style.Halo = new Pen(Color.White, 3); myMap.Layers.Add(layselectLabel);
        layselect.Style.SymbolScale = 0.1f;
        myMap.Layers.Add(layselect);
CreateMap(); }

Thanks and Regards,
Sayan

 

 

 

 

Coordinator
Nov 4, 2009 at 9:29 PM
Edited Nov 4, 2009 at 10:26 PM

Hi Sayan, you can set myMap.Zoom , and use a GeometryFeatureProvider if you need attribute data for theming or labelling.. hth jd

Nov 11, 2009 at 6:38 PM

Thanks Johndiss for all your suggestions.Your solutions has been simple and encouraging.

 

Cheers,

Sayan