ThinkGeo.com    |     Documentation    |     Premium Support

Routing according to the attribute table in the shapefile

Now we need to find the route according to the attribute table in the shapefile. For example, we have a column called " Quality of Road"—Good, average and poor. What we need is to find the specific route according to the quality of road.



How can we generate different rtg files according to specific column?

Or use different algorithms and one rtg file to find routes?

Or use one algorithm and different rtg files to find routes?






Hi Junxuan,



I think there are two ways for your case: 

One is when we are building the rtg file with APIs, in the BuildingRoutingData event method, we can skip it if the current feature road type is not equal with your specify column value. Some codes as following:


RtgRoutingSource.BuildingRoutingData += RtgRoutingSource_BuildingRoutingData;
 
void RtgRoutingSource_BuildingRoutingData(object sender, BuildingRoutingDataRtgRoutingSourceEventArgs e)
        {
            Feature currentFeature = featureSource.GetFeatureById(e.RouteSegment.FeatureId, new string[]{“Quality of Road”});
            if (currentFeature.ColumnValues[“Quality of Road”] != “Good”)
            {
                e.RouteSegment.StartPointAdjacentIds.Clear();
                e.RouteSegment.EndPointAdjacentIds.Clear();
            }
        }

With the above codes, we can get three rtg index files for the column values, then we can choose one of them as the routing index file when you are using it.



The other way is we skip the finding when we get routing on the fly and don’t change the rtg file. Some codes as following:


RoutingEngine routingEngine = new RoutingEngine(routingSource, featureSource);
            routingEngine.RoutingAlgorithm.FindingRoute += RoutingAlgorithm_FindingRoute;
            RoutingResult routingResult = routingEngine.GetRoute(routingLayer.StartPoint, routingLayer.EndPoint);
 
 void RoutingAlgorithm_FindingRoute(object sender, FindingRouteRoutingAlgorithmEventArgs e)
        {
            Feature currentFeature = featureSource.GetFeatureById(e.RouteSegment.FeatureId, new string[] { “Quality of Road” });
            if (currentFeature.ColumnValues[“Quality of Road”] != “Good”)
            {
                e.RouteSegment.StartPointAdjacentIds.Clear();
                e.RouteSegment.EndPointAdjacentIds.Clear();
            }
        }

Please let us know if any questions.



Thanks,



Troy




Hi, Troy:



Thanks for your reply.

But it seems that the code can not recognize the different values in a specific column.

For the two methods above, we prefer the latter one( use one rtg file to find the routes).



We can not check the content in the rtg file, what we can see is the shapefile. When we generate rtg file from shp file, is it still have the corresponding columns? Because I think the rtg file is an index file.

Hi Junxuan,



Sorry I didn’t get “can not recognize the different values”? In the code, I only returned one column to fill the feature, you can call featuresource.GetFeatureById("",ReturningColumnsType.AllColumns) to get all the column information.



For rtg file content, it doesn’t store any corresponding dbf column information, it only includes the geometries like .shp file, but you still can get the columns from .dbf file.



Please let us know if any questions.



Thanks,



Troy

Hi Junxuan,



Sorry I didn’t get “can not recognize the different values”? In the code, I only returned one column to fill the feature, you can call featuresource.GetFeatureById("",ReturningColumnsType.AllColumns) to get all the column information.



For rtg file content, it doesn’t store any corresponding dbf column information, it only includes the geometries like .shp file, but you still can get the columns from .dbf file.



Please let us know if any questions.



Thanks,



Troy

Hi, 

I checked an optimize roadtype sample online. I think it is similar to what I want to do.



For the following code, I do not totally understand. I checked the dbf file, it does not have certain column contains the information about "localroads and highways".



void Algorithm_FindingPath(object sender, FindingRouteRoutingAlgorithmEventArgs e)
        {
            Collection<string> localRoads = new Collection<string>();  // define string local roads
            Collection<string> highways = new Collection<string>();     // define string highways



            foreach (string item in e.RouteSegment.StartPointAdjacentIds)
            {
                RouteSegment road = routingEngine.RoutingSource.GetRouteSegmentByFeatureId(item); // what is item?
                if (road.RouteSegmentType == 2)     // what does this mean?
                {
                    highways.Add(item);   
                }
                else
                {
                    localRoads.Add(item);
                }
            }



           




We have some questions about the code of the "optimized roadtype" sample in the Routing Extension demos (samples.thinkgeo.com/RoutingEdition/HowDoISamples/). 



For the code of this sample, we have focused on the following lines 47 to 63, as shown below:
 void Algorithm_FindingPath(object sender, FindingRouteRoutingAlgorithmEventArgs e)
        {
            Collection<string> localRoads = new Collection<string>();
            Collection<string> highways = new Collection<string>();



            foreach (string item in e.RouteSegment.StartPointAdjacentIds)  //Q1
            {
                RouteSegment road = routingEngine.RoutingSource.GetRouteSegmentByFeatureId(item);
                if (road.RouteSegmentType == 2) // Q2
                {
                    highways.Add(item);
                }
                else
                {
                    localRoads.Add(item);
                }
            }



            foreach (string item in e.RouteSegment.EndPointAdjacentIds)
            {
                RouteSegment road = routingEngine.RoutingSource.GetRouteSegmentByFeatureId(item);
                if (road.RouteSegmentType == 2)
                {
                    highways.Add(item);
                }
                else
                {
                    localRoads.Add(item);
                }
            }









Our questions are as follows:




Q1: What is "item" in e. RouteSegement.StartPointAdjacentIds? We think "item" should at least contains the featureID and RoutesegementType information in the sample, which come from the shapefile. If so, we are wondering how to read the information from the shapefile and add them into "item".  



Q2: What is RouteSegmentType? Is it an int variable? What does "road.RouteSegmentType == 2" mean? Can RouteSegmentType be other values, like 1, or 3, 4? Again, How we can get the value of RouteSegmentType? From rtg or shape file?   




Hi Junxuan,



For the Q1, the StartPointAdjacentIds and EndPointAdjacentIds are actually mapping the feature ids connecting the current segment at the start point and end point, for instance:





In the above image, there are 5 features connecting with current segment and you can find all the feature column information with the feature id from the dbf file. As you may see, in some cases, we clear the StartPointAdjacentIds or EndPointAdjacentIds to end the finding path if we don’t want to pass those segment.



For Q2, yes it is an int variable and is assigned by ourselves when we build the rtg file. For this sample value 2, you can check the HowDoI => BuildingRoutingData, in this sample, we assigned a value 2 if the current feature is a highway, then we will save this segment information like RouteSegmentType,Weight, even distance in the rtg file.



Hope it helps.

Thanks,

Troy

Hi, 

1.    I refered the buildingRoutingData sample to generate my rtg file. The code is as follows and I used a listbox to check the value of RouteSegment Type( The results are correct ).

private void RtgRoutingSource_BuildingRoadData(object sender, BuildingRoutingDataRtgRoutingSourceEventArgs e)
        {
            featureSource.Open();
            Feature feature = featureSource.GetFeatureById(e.LineShape.Id, new string[] { “NHS” });    // Column name is NHS          
           if (Convert.ToInt32 (feature.ColumnValues[“NHS”])>5)
            {
                e.RouteSegment.RouteSegmentType = 2;     // if the value of NHS is greater than 5, then RouteSegmentType = 2
            }
            else
            {
                e.RouteSegment.RouteSegmentType = 1;     // Else, RouteSegmentType =1
            }
            listBox1.Items.Add(e.RouteSegment.RouteSegmentType);      // display the value of  RouteSegmentType (correct)


        }








2.  I also refer to the Optimized RoadType sample online. I want to divide road data into two category(Good and Average) using the routeSegmentType as criteria. I also used a listbox to show the value of road.RouteSegmentType. But all the values are 0 which is wrong because I have checked the values of RouteSegmentType when I generating rtg file. My code is as follows:





 void Algorithm_FindingPath(object sender, FindingRouteRoutingAlgorithmEventArgs e)
        {
            Collection<string> Good = new Collection<string>();
            Collection<string> Average = new Collection<string>();      




            foreach (string item in e.RouteSegment.StartPointAdjacentIds)
            {
                RouteSegment road = routingEngine.RoutingSource.GetRouteSegmentByFeatureId(item);
                listBox1.Items.Add(road.RouteSegmentType );   // Display the Value  ( so I think there is something wrong with the above line because                                                                                                                                            “road” does not have correct value)



                if (road.RouteSegmentType == 2)
                {
                    Good.Add(item);
                }



                if (road.RouteSegmentType == 1)
                {
                    Average.Add(item);
                }
      


            }






Hi Junxuan,



I found this is a bug caused by upgrade on our Routing Structure. In the latest version, we don’t store this Segment type field in rtg file, but in old version, we do store it and our samples were built on old version. Currently, our manager said we maybe consider to add this field back and will start after tomorrow, I guess it may be take a few days as we need to do more tests before release it.



Before that, I think you can try the other way which built difference rtg files as we mentioned before.



Thanks,



Troy

Hi, Troy:

Thanks for your previous help! It helps me a lot with my project.

Please keep me updated about this issue.



Junxuan

Junxuan, 
  
 You’re welcome, we are happy to assist you and sure please feel free to update here on this issue. 
  
 Have a good day. 
 Troy 


Hi, Troy:



Today I refered the desktopedition.dll and mapsuitecore.dll from the "Map Suite 9.0\Map Suite Desktop\Daily Full Production 9.0.0.90\Managed Assemblies - Strong Named" and mapsuiteRouting.dll from the "Map Suite 9.0\Map Suite Routing\Daily Eval Production 9.0.0.97\Managed Assemblies - Strong Named". They are all the latest version. But I met the same problem—It seems that the code still can not store the segment type in rtg file.



So, 1. I want to know if your technicians have found the methods to solve this bug.

      2. For this issue, is it related to Routing.dll or desktopedition and mapsuitecore.dll?

      3. For your product, what is difference between Daily Full Development and Daily Full Production? I should find .dll from which file?





Thanks!

Junxuan 

Hi Junxuan, 
  
 Sorry for the delay, it’s still in progress now, as to resolve this problem, we need to change the data format of the *.rtg file, thus a new version of the format is there. Actually the RouteSegmentType property should be depredated property, which should be marked with Obsolete in last release. Anyway, we will check your requirement to see if there is any other workaround without any effect to performance for you. I think everything should be provided to you in this week. I will mark this thread “In Progress”. 
  
 This is an issue in Routing.dll. 
  
 Please refer to wiki.thinkgeo.com/wiki/Map_Suite_Daily_Builds_Guide for the detailed description on the differences between Daily Full Development and Daily Full Production. 
  
 Thanks, 
 Johnny

Hi Junxuan,



We’ve finished the data structure upgrade and including the roadsegmentstype field now, would you please try the latest dev daily build? The version should be at 9.0.108.0, but may be building now, please wait for several hours.



Please let us know if the new dlls works for this field.



Thanks,

Troy

Hi,



I used the new dll to test the code. 

1. I think I generate the correct rtg files which are the same as the attached file you send to me.

2. But I meet the new problem, which is not occured in the past----I can not generate the map.

   The error is “An unhandled exception of type ‘System.MissingMethodException’ occurred in MapSuiteRouting.dll
   Additional information: 找不到方法:“ThinkGeo.MapSuite.Core.GeoColor ThinkGeo.MapSuite.Core.SimpleColors.get_Black()”






    I  am sure my code is correct because I used the old dll to run and map is displayed. So at this point, I can not test the algorithm_finding path.



 // map button
        private void button5_Click(object sender, System.EventArgs e)
        {
            mapControl.MapUnit = GeographyUnit.DecimalDegree;



            ShapeFileFeatureLayer austinStreetsLayer = new ShapeFileFeatureLayer(str1);



            ClassBreakStyle classBreakStyle = new ClassBreakStyle(“NHS”);
            classBreakStyle.BreakValueInclusion = BreakValueInclusion.IncludeValue; 



           
            classBreakStyle.ClassBreaks.Add(new ClassBreak(double.MinValue, LineStyles.CreateSimpleLineStyle(GeoColor.StandardColors.Green, 2, true)));
            classBreakStyle.ClassBreaks.Add(new ClassBreak(1, LineStyles.CreateSimpleLineStyle(GeoColor.StandardColors.Orange, 2, true)));
            classBreakStyle.ClassBreaks.Add(new ClassBreak(4, LineStyles.CreateSimpleLineStyle(GeoColor.StandardColors.Red, 2, true)));



            austinStreetsLayer.ZoomLevelSet.ZoomLevel01.CustomStyles.Add(classBreakStyle);           
            austinStreetsLayer.ZoomLevelSet.ZoomLevel01.ApplyUntilZoomLevel = ApplyUntilZoomLevel.Level20;
            LayerOverlay austinStreetOverlay = new LayerOverlay();
            austinStreetOverlay.Layers.Add(“austinStreetsLayer”, austinStreetsLayer);
            mapControl.Overlays.Add(“austinStreetOverlay”, austinStreetOverlay);                    



            InitRoutingOverlays();
  
        }
 private void InitRoutingOverlays()
        {



           // WorldMapKitWmsDesktopOverlay worldMapKitsOverlay = new WorldMapKitWmsDesktopOverlay();



           // mapControl.Overlays.Add(worldMapKitsOverlay);



            routingOverlay = new LayerOverlay();
            mapControl.Overlays.Add(“RoutingOverlay”, routingOverlay);



            routingLayer = new RoutingLayer();        
            routingLayer.StartPointStyle = new PointStyle(new GeoImage(@”…/…/Image/start.png"));
            routingLayer.EndPointStyle = new PointStyle(new GeoImage(@"…/…/Image/end.png"));
            routingLayer.XOffsetInPixelOfStopOrder = -3;
            routingLayer.YOffsetInPixelOfStopOrder = 14;
            routingOverlay.Layers.Add(“RoutingLayer”, routingLayer);



            mapControl.Refresh();



        }









Hi Junxuan,



I met this issue before and it is fixed when I keep the MapSuiteCore and Product dlls with a same version. Would you please check your MapSuiteCore dll and Routing dll, Desktop.dll version are the same, all of them should be dev dlls (9.0.xxx.0)?



Thanks,

Troy

Hi, Troy:

I used the latest the desktop.dll, mapsuitecore.dll(Daily Full Development 9.0.111.0/Managed Assemblies-strong Named) and routing.dll(Daily Eval Developement 9.0.111.0/Managed Assemblies-strong Named), but still met some problems.



1. There is something wrong with InitializeComponent(); It shows that bufferedGraphics Context cannot be disposed of because a buffer operation is currently in process.

Note: My whole project has 5 functions and routing is just one of them. I run the whole program and met this problem. If I open another project to test the routing function only, the initialization is correct.







2.I use a project to test the routing function only.(I send the whole project document to forumsupport@thinkgeo.com)

The map is displayed correctly. But the routing function is not valid.

(1) No route is displayed for shortest path(I use the original rtg file)

(2) No route is displayed for categories ( I use the rtg file generated from routable shapefile)

I have a question about choosing rtg file. I think I need to use original rtg file to find the shortest path, right? 

Or I just need one rtg file from routable shapefile to do all the routing tasks.



3. In the past, I used the desktop and mapsuitecore.dll from Daily Full Production 9.0.0.72 and routing.dll from Eval Release Mapsuite 9.0.0.0. (We bought the desktop software from your company ). Everything was  correct except routing according to our own criterion. But now, even finding the shortest path is wrong when using the new dll.



For the detail, please refer to the email.



Thanks!



junxuan






Junxuan,



For the first question, sorry we didn’t meet it before and would you please check those projects relationships again? Could you provide us more details?



For the #2 issue, We received your sample, it helps us a lot. I modified your sample and also rebuild the routable and rtg file, then it works fine for me. Please download the sample with the link: ap.thinkgeo.com:5001/fbsharing/Mxw1iKsl



Comparing with your sample, I did the below changes:



1. rebuild the routable shpe file and rtg file.

2. using routable shape file (TexasRoads.routable.shp) as the FeatureSource rather than the original shape file (TexasRoads.shp). Actually, we should use the routable shape file all the time while we get routing as this shape file are processed to fit for routing comparing the original’s. So, let’s forget the original shape file after this step.







3. The shortest rtg file and road type filter can use a same one rtg file. We don’t need to generate two rtg file.

4. Improve the code in Findpath event.

5. Assign the new SearchRadiusInMeters property as 2000. This is an new property only in Development branch and it is used to get the nearest feature within such radius when we pin a start/end point on the map. You can try to give a large value if no path is found.



Here are what I got with 9.0.111.0 dll packages (including routing dll).

 









Please let us know if any questions.



Thanks,



Troy

Hi, Troy:



I downloaded your routing sample and it did work in my laptop with little modification(I think in this function it should have more code than only DoRouting() because we need to call the Algorithm_FindingPath)

 private void cbmPriority_SelectedIndexChanged(object sender, EventArgs e)
        {
            string rtgFilePathName = routableRtgFile;



            routingEngine = new RoutingEngine(new RtgRoutingSource(rtgFilePathName), routingFeatureLayer.FeatureSource);
            routingEngine.SearchRadiusInMeters = 2000;
            routingEngine.RoutingAlgorithm.FindingRoute += new EventHandler<findingrouteroutingalgorithmeventargs>(Algorithm_FindingPath);</findingrouteroutingalgorithmeventargs>



            DoRouting();
        }


But when I added this routing function to my whole project, there still something wrong with initialization. According to the messagebox, I need to release graphics.GetHdc, but I do not how to do it.(Maybe this problem is related to the Systems.Drawing.dll). I use another laptop to run the whole project and meet the same problem).



I send the whole project to forumsupport@thinkgeo.com

For the project detail, please refer to my email.









Thanks!

Junxuan