ThinkGeo.com    |     Documentation    |     Premium Support

Find closest street in map once marker marked in map

Please help me in winform map. In winform map i selected one street using marker then i need which street is closest street to selected street in desktop edition.



Hello yakub, 



It’s feasible. You can use the method “GetFeaturesNearestTo(BaseShape targetShape, GeographyUnit unitOfData, int numberOfItemsToFind, IEnumerable returningColumnNames, double distanceLimits, DistanceUnit unitOfDistance)” of featureSource to return all the features inside specified “DistanceLimits”, and then check the WellknownType of the feature is WellKnownType.MultiLine or WellKnownType.Line or some other shape as the same as your street. 



Here is the code, please have a look at it: 




Collection<Feature> features = featureSoruce.GetFeaturesNearestTo(e.Position, GeographyUnit.DecimalDegree, 10, new Collection<string>() { }, 100, DistanceUnit.Meter);

            Feature selectedFeature;
            foreach (Feature feature in features)
            {
                if (feature.GetWellKnownType() == WellKnownType.Line || feature.GetWellKnownType() == WellKnownType.Multiline)
                {
                    selectedFeature = feature;
                    break;
                }
            }


Regards, 



Gary



In above code i need full method.  Where will i put this code?. In winformMap_MapClickevent i created marker. please guide me, 
  
  
 Regards 
  
 Yakub

Hello yakub, 



You can put it in any function you want, let's put this in a button click, and then I just guess you are using a layer to show the map and use a SimpleMarkerOverlay to show the marker. 


        private void btnGetNearest_Click(object sender, EventArgs e)
        {
            SimpleMarkerOverlay markerOverlay = (SimpleMarkerOverlay)winformsMap1.Overlays["MarkerOverlay"];
            Marker marker = markerOverlay.Markers[0];
            Collection<Feature> features = winformsMap1.FindFeatureLayer("WorldLayer").FeatureSource.GetFeaturesNearestTo(new PointShape(marker.Location.X, marker.Location.Y), GeographyUnit.DecimalDegree, 10, ReturningColumnsType.AllColumns);
            //put the rest logic here
        }



In this code, you can see, first you need to find the marker you have added, then get the layer, use the GetFeaturesNearestTo function to get some features which fit the conditions, then use some logic to filter them, get the one you want. 



Regards, 



Gary



Hi Gary,


            This is my code, where will i add your code in this code,  Please guide me for the closest street.


 


  private void POI_SelectedIndexChanged(object sender, EventArgs e)

        {



            if (POI.SelectedValue.ToString() == "System.Data.DataRowView")

            {

                return;

            }

            if (POI.SelectedValue.ToString() == "-1" || POI.SelectedValue == null)

            {

                return;

            }

            SimpleMarkerOverlay markerOverlay = (SimpleMarkerOverlay)winformsMap2.Overlays["MarkerOverlay"];

            markerOverlay.Markers.Remove(marker);

            winformsMap2.Refresh();

            ShapeFileFeatureLayer SelectedPOILayer = new ShapeFileFeatureLayer(@"C:\Program Files\ThinkGeo\Map Suite Desktop Evaluation Edition 5.0\Samples\SampleData\Data\RIYADH_POI.shp");

            SelectedPOILayer.Open();

            winformsMap2.CurrentExtent = SelectedPOILayer.FeatureSource.GetBoundingBoxById(POI.SelectedValue.ToString());

            markerOverlay = (SimpleMarkerOverlay)winformsMap2.Overlays["MarkerOverlay"];

            markerOverlay.DragMode = MarkerDragMode.Drag;

            marker = new Marker(SelectedPOILayer.FeatureSource.GetBoundingBoxById(POI.SelectedValue.ToString()).GetCenterPoint());

            marker.Image = Properties.Resources.AQUA;

            marker.Click += new EventHandler(marker_Click);

            markerOverlay.Markers.Add(marker);

            winformsMap2.CurrentExtent.ScaleUp(300);

            LayerOverlay staticOverlay = new LayerOverlay();

            staticOverlay.Layers.Add("SelectedPOILayer", SelectedPOILayer);

            winformsMap2.Overlays.Add(staticOverlay);

            SelectedPOILayer.Close();

            winformsMap2.Refresh();

       }

 



Hello yakub, 



I think maybe you meet problem in marker click when you try the code above? Is it not working? It’s because the real point of a marker is very small, you need clicked the point exactly right, then the event will be fire. You can try it by click the marker’s bottom many times.  



And because our marker’s event is inherit from Microsoft, so we can’t change it, then we have a workaround to resolve this problem. Please see the code below: 


        private void winformsMap1_MapClick(object sender, MapClickWinformsMapEventArgs e)
        {
            LayerOverlay markerOverlay = (LayerOverlay)winformsMap1.Overlays["MarkerOverlay"];
            InMemoryFeatureLayer inmemoryFeatureLayer = markerOverlay.Layers[0] as InMemoryFeatureLayer;

            MultipolygonShape buffer = e.WorldLocation.Buffer(350, GeographyUnit.DecimalDegree, DistanceUnit.Kilometer);

            Collection<Feature> clickedMarker = inmemoryFeatureLayer.QueryTools.GetFeaturesWithin(buffer, ReturningColumnsType.NoColumns);
            if (clickedMarker.Count > 0)
            {
                Collection<Feature> features = winformsMap1.FindFeatureLayer("SelectedPOILayer ").FeatureSource.GetFeaturesNearestTo(new PointShape(e.WorldLocation.X, e.WorldLocation.Y), GeographyUnit.DecimalDegree, 10, ReturningColumnsType.AllColumns);
                Feature selectedFeature;
                foreach (Feature feature in features)
                {
                    if (feature.GetWellKnownType() == WellKnownType.Line || feature.GetWellKnownType() == WellKnownType.Multiline)
                    {
                        selectedFeature = feature;
                        break;
                    }
                }
                //selectedFeature is what you want, do anything you want to do, like hight it, change the color, show some tooltip.
            }
        }
 

Any more questions please feel free to let us know. 



Regard, 



Gary




 Hi Gary, 
  
             I am using MarkerOVerLay, How to Change this code for LayerOverlay to MarkerOverlay 
  
 LayerOverlay markerOverlay = (LayerOverlay)winformsMap1.Overlays["MarkerOverlay"]; 
            
 InMemoryFeatureLayer inmemoryFeatureLayer = markerOverlay.Layers[0] as InMemoryFeatureLayer; 
  
  


 Hello yakub,


 
Ok, I can explain this more clearly.
 
First, in your old way, you want to add marker into SimpleMarkerOverlay and handle the Marker.Click event to get the closest street, this is the code depends on your code.

void marker_Click(object sender, EventArgs e)
        {
            SimpleMarkerOverlay markerOverlay = (SimpleMarkerOverlay)winformsMap1.Overlays["MarkerOverlay"];
            Marker marker = markerOverlay.Markers[0];
            Collection<Feature> features = winformsMap1.FindFeatureLayer("WorldLayer").FeatureSource.GetFeaturesNearestTo(new PointShape(marker.Location.X, marker.Location.Y), GeographyUnit.DecimalDegree, 10, ReturningColumnsType.AllColumns);
            Feature selectedFeature;
                foreach (Feature feature in features)
                {
                    if (feature.GetWellKnownType() == WellKnownType.Line || feature.GetWellKnownType() == WellKnownType.Multiline)
                    {
                        selectedFeature = feature;
                        break;
                    }
                }
                //selectedFeature is what you want, do anything you want to do, like hight it, change the color, show some tooltip.
         }

Then there is very big possibility you can't fire the marker_Click because  the real point of a marker is very small, you need clicked the point exactly right, and our marker’s event is inherit from Microsoft, so we can’t change it.
 
So I give a workaround that don't use the SimpleMarkerOverlay, use a pointshape inplace the marker, and then handle it in the winformsMap1_MapClick event, you can also get the same result.
 
So I have post the code above, if you would like try this way, I can make it more details.
 
First create the InMemoryFeatureLayer and set it's default pointshape style as same as your marker image.

  private void DisplayMap_Load(object sender, EventArgs e)
        {
            winformsMap1.MapUnit = GeographyUnit.DecimalDegree;
            winformsMap1.CurrentExtent = new RectangleShape(-155.733, 95.60, 104.42, -81.9);

            WorldMapKitWmsDesktopOverlay worldMapKitOverlay = new WorldMapKitWmsDesktopOverlay();
            winformsMap1.Overlays.Add(worldMapKitOverlay);
            InMemoryFeatureLayer inmemoryFeatureLayer = new InMemoryFeatureLayer();
            inmemoryFeatureLayer.ZoomLevelSet.ZoomLevel01.DefaultPointStyle = new PointStyle(new GeoImage(Properties.Resources.AQUA)); 
            inmemoryFeatureLayer.ZoomLevelSet.ZoomLevel01.ApplyUntilZoomLevel = ApplyUntilZoomLevel.Level20;

            LayerOverlay markerOverlay = new LayerOverlay();
            markerOverlay.Layers.Add(inmemoryFeatureLayer);
            winformsMap1.Overlays.Add("MarkerOverlay", markerOverlay);
            winformsMap1.Refresh();
        }

 
Then this is your POI_SelectedIndexChanged event, I just have some changes.

private void POI_SelectedIndexChanged(object sender, EventArgs e)
        {

            if (POI.SelectedValue.ToString() == "System.Data.DataRowView")
            {
                return;
            }
            if (POI.SelectedValue.ToString() == "-1" || POI.SelectedValue == null)
            {
                return;
            }
            SimpleMarkerOverlay markerOverlay = (SimpleMarkerOverlay)winformsMap2.Overlays["MarkerOverlay"];
            markerOverlay.Markers.Remove(marker);
    LayerOverlay markerOverlay = (LayerOverlay)winformsMap1.Overlays["MarkerOverlay"];
            InMemoryFeatureLayer inmemoryFeatureLayer = markerOverlay.Layers[0] as InMemoryFeatureLayer;
    inmemoryFeatureLayer.InternalFeatures.Clear();
            winformsMap2.Refresh();
            ShapeFileFeatureLayer SelectedPOILayer = new ShapeFileFeatureLayer(@"C:\Program Files\ThinkGeo\Map Suite Desktop Evaluation Edition 5.0\Samples\SampleData\Data\RIYADH_POI.shp");
            SelectedPOILayer.Open();
            winformsMap2.CurrentExtent = SelectedPOILayer.FeatureSource.GetBoundingBoxById(POI.SelectedValue.ToString());
    inmemoryFeatureLayer.InternalFeatures.Add(new Feature(SelectedPOILayer.FeatureSource.GetBoundingBoxById(POI.SelectedValue.ToString()).GetCenterPoint());
            winformsMap2.CurrentExtent.ScaleUp(300);
            LayerOverlay staticOverlay = new LayerOverlay();
            staticOverlay.Layers.Add("SelectedPOILayer", SelectedPOILayer);
            winformsMap2.Overlays.Add(staticOverlay);
            SelectedPOILayer.Close();
            winformsMap2.Refresh();
       }

 
At last, it's the Click event to help you find out the street.

        private void winformsMap1_MapClick(object sender, MapClickWinformsMapEventArgs e)
        {
            LayerOverlay markerOverlay = (LayerOverlay)winformsMap1.Overlays["MarkerOverlay"];
            InMemoryFeatureLayer inmemoryFeatureLayer = markerOverlay.Layers[0] as InMemoryFeatureLayer;
            inmemoryFeatureLayer.InternalFeatures.Clear();
            MultipolygonShape buffer = e.WorldLocation.Buffer(350, GeographyUnit.DecimalDegree, DistanceUnit.Kilometer);
            Collection<Feature> clickedMarker = inmemoryFeatureLayer.QueryTools.GetFeaturesWithin(buffer, ReturningColumnsType.NoColumns);
            if (clickedMarker.Count > 0)
            {
                Collection<Feature> features = winformsMap1.FindFeatureLayer("WorldLayer").FeatureSource.GetFeaturesNearestTo(new PointShape(e.WorldLocation.X, e.WorldLocation.Y), GeographyUnit.DecimalDegree, 10, ReturningColumnsType.AllColumns);
                Feature selectedFeature;
                foreach (Feature feature in features)
                {
                    if (feature.GetWellKnownType() == WellKnownType.Line || feature.GetWellKnownType() == WellKnownType.Multiline)
                    {
                        selectedFeature = feature;
                        break;
                    }
                }
                //selectedFeature is what you want, do anything you want to do, like hight it, change the color, show some tooltip.
            }

            winformsMap1.Refresh();
        }

 
I hope this can be help.
 
Regards,
 
Gary.

Hi Gary, 
  
              I got the Closest POI which i Marker marked POI. Now closest POI i used for Marker. Instead of Marker i need arrow mark to highlighting that Closest POI. This is my code. 
  
       private void button1_Click_1(object sender, EventArgs e) 
         { 
             SimpleMarkerOverlay markerOverlay1 = (SimpleMarkerOverlay)winformsMap2.Overlays["MarkerOverlay"]; 
             markerOverlay1.Markers.Remove(marker1); 
             winformsMap2.Refresh(); 
             ShapeFileFeatureLayer SelectedPOILayer = new ShapeFileFeatureLayer(@"C:\Program Files\ThinkGeo\Map Suite Desktop Evaluation Edition 5.0\Samples\SampleData\Data\RIYADH_POI.shp"); 
             SelectedPOILayer.Open(); 
             winformsMap2.CurrentExtent = SelectedPOILayer.FeatureSource.GetBoundingBoxById(POI.SelectedValue.ToString()); 
  
             markerOverlay1 = (SimpleMarkerOverlay)winformsMap2.Overlays["MarkerOverlay"]; 
             markerOverlay.DragMode = MarkerDragMode.None; 
             PointShape myPoint = new PointShape(marker.Position.X, marker.Position.Y); 
             Collection<Feature> features = SelectedPOILayer.QueryTools.GetFeaturesNearestTo(myPoint, GeographyUnit.DecimalDegree, 3, new string[] { "Name_Lang2" }); 
  
             marker1 = new Marker(SelectedPOILayer.FeatureSource.GetBoundingBoxById(features[1].Id.ToString()).GetCenterPoint()); 
             marker1.Image = Properties.Resources.Circle; 
             markerOverlay1.Markers.Add(marker1); 
  
             winformsMap2.CurrentExtent.ScaleUp(300); 
             LayerOverlay staticOverlay = new LayerOverlay(); 
             staticOverlay.Layers.Add("SelectedPOILayer", SelectedPOILayer); 
             winformsMap2.Overlays.Add(staticOverlay); 
  
             SelectedPOILayer.Close(); 
             winformsMap2.Refresh(); 
         } 
  
 Regards Yakub

Hello Yakub, 
  
 Sorry for delay, I’m not very clear with you last post, what’s your requirement? And what’s the status now? You get error or something else? 
  
 Regards, 
  
 Gary

Hi Gary, 
  
              I found Closest POI of Selected POI. I used marker for closest POI.  Using this code i found it. 
 Collection features = SelectedPOILayer.QueryTools.GetFeaturesNearestTo(myPoint, GeographyUnit.DecimalDegree, 3, new string[] { "Name_Lang2" }); 
 marker1 = new Marker(SelectedPOILayer.FeatureSource.GetBoundingBoxById(features[1].Id.ToString()).GetCenterPoint()); 
 marker1.Image = Properties.Resources.Circle; 
 markerOverlay1.Markers.Add(marker1);  
  
 Now i need is two things 
 1. How to Highlight the Closest POI using arrow mark. 
 2. what is the street name to reach the Closest POI. 
  
 Regards Yakub 

Hello yakub, 



Thanks for the further information. 



For your first question, you can use a InMemoryFeatureLayer to do that job, create a new InMemoryFeatureLayer named HighlightLayer, and set it's style to what you want then: 


foreach (Feature closestFeature in closestFeatures)
{
      if (closestFeature.GetWellKnownType() == WellKnownType.Point)
      {
           HighlightLayer.Internalfeatures.add(closestFeature);
           break;
      }
}
 

For your second question, you can use QueryTools.GetFeaturesContaining to find out the street feature and then: 


streetName.Text = string.Format("Street Name : {0}", selectedFeatures[0].ColumnValues["YourNameColumn"].Trim());
 

Regards, 



Gary



Yakub,


  I would look at the sample Get Feature Clicked On (Desktop) in the Code Community. It show how to get the closest street to where the user clicked on the map. You will find the spatial method for doing that in the code. For finding the closest street from the selected street, the spatial method is basically the same.


wiki.thinkgeo.com/wiki/Map_Suite_De...Desktop.29