ThinkGeo.com    |     Documentation    |     Premium Support

Code Optimization - Distance between two points

The code below is a prototype created to determine the speed with which MapSuite can take a starting address, and an array of many addresses, and calculate the driving distance between the starting address, and each of the destination addresses.


The results will be displayed to the user in a web interface indicating how many addresses fall within a certain radius of the starting address. Example UI:


Radius from Address                        Number of Records


2.5 - 5.0 miles                                             400


5.0 - 7.5 miles                                             700


With the code below, we're seeing performance of about 1 second per record. How can this performance be improved to something usable within our web app?


 






        ///
        /// The function below is used to test the ThinkGeo Geocoder and Route Extension. Purpose of the code is to get 
        /// get driving distance from one location to another
        ///
        public void TestCode()
        {
            UsaGeocoder usaGeocoder;
 
            // Assign .shp and .rtg objects
            FeatureSource featureSource = new ShapeFileFeatureSource(Server.MapPath(@"\ChicagoRouteData\tl_2009_17031_edges.shp"));
            RoutingSource routingSource = new RtgRoutingSource(Server.MapPath(@"\ChicagoRouteData\tl_2009_17031_edges.rtg"));
 
            dataPath = Server.MapPath("~/ChicagoData");
            usaGeocoder = new UsaGeocoder(dataPath, MatchMode.ExactMatch);
 
            try
            {
                featureSource.Open();
                routingSource.Open();
 
                addresses.Clear();
                SQLDatabase objSQLDatabase = new SQLDatabase(conn);
 
                int found = 0;
                int notFound = 0;
 
    
 
                SqlParameter[] sqlParam = new SqlParameter[1];
                sqlParam[0] = new SqlParameter("@username", txtUserName.Text);
 
                // Open the geocoder
                Collection<GeocoderMatch> matchResult;
                usaGeocoder.Open();
 
 
                // Get starting address
                DataTable userAddress = objSQLDatabase.GetDataTable(userAddressQuery, CommandType.Text, sqlParam);
 
 
                SqlParameter[] sqlParam2 = new SqlParameter[1];
                sqlParam2[0] = new SqlParameter("@username", txtUserName.Text);
 
                // Get Set of Address. approx 1200 records
                DataTable resultSet = objSQLDatabase.GetDataTable(addressQuery, CommandType.Text, sqlParam2);
 
 
 
 
                string startAddress = string.Format("{0}, {1}, {2}, {3}", userAddress.Rows[0]["StreetAddress"].ToString(),
                                                userAddress.Rows[0]["City"].ToString(), userAddress.Rows[0]["State"].ToString(),
                                                userAddress.Rows[0]["Zip"].ToString());
 
                lblStartAddress.Text = startAddress;
                matchResult = usaGeocoder.Match(startAddress);
 
                string startLat = "0.0";
                string startLon = "0.0";
 
                // Get Lan and Lon for the starting Address
                //-----------------------------------------------------------------------------------------
                if (!matchResult[0].Ranking.Equals(0))
                {
                    matchItems = matchResult;
 
                    if (matchResult[0].NameValuePairs.ContainsKey("FromLatitude") && matchResult[0].NameValuePairs.ContainsKey("FromLongitude"))
                    {
                        lblStartCoordinates.Text = matchResult[0].NameValuePairs["FromLatitude"].ToString() + "," + matchResult[0].NameValuePairs["FromLongitude"].ToString();
                        startLat = matchResult[0].NameValuePairs["FromLatitude"].ToString();
                        startLon = matchResult[0].NameValuePairs["FromLongitude"].ToString();
                    }
                    else
                    {
                        lblStartCoordinates.Text = "Not Found";
                    }
                }
                //-----------------------------------------------------------------------------------------
                // Get Driving Distance
                //-----------------------------------------------------------------------------------------
                RoutingEngine routingEngine = new RoutingEngine(routingSource, featureSource);
                RoutingResult routingResult;
                routingEngine.RoutingSource = routingSource;    // Assign the spatial or rtg data.
 
                // Loop through the address
                foreach (DataRow dr in resultSet.Rows)
                {
                    matchResult = usaGeocoder.Match(string.Format("{0}, {1}, {2}, {3}", dr["StreetAddress"].ToString(),
                                                                                        dr["City"].ToString(), dr["State"].ToString(), dr["Zip"].ToString()));
                    // Show result in the page
                    if (!matchResult[0].Ranking.Equals(0))
                    {
                        matchItems = matchResult;
 
                        if (matchResult[0].NameValuePairs.ContainsKey("FromLatitude") && matchResult[0].NameValuePairs.ContainsKey("FromLongitude"))
                        {
                            try
                            {
                     
 
                                routingResult = routingEngine.GetRoute(new PointShape(Double.Parse(startLon), Double.Parse(startLat)),
                                                                      new PointShape(Double.Parse(matchResult[0].NameValuePairs["FromLongitude"].ToString()),
                                                                                     Double.Parse(matchResult[0].NameValuePairs["FromLatitude"].ToString())));
 
                                addresses.Add(new Addresses(string.Format("{0}, {1}, {2}, {3}", dr["StreetAddress"].ToString(),
                                                            dr["City"].ToString(), dr["State"].ToString(), dr["Zip"].ToString()),
                                                            string.Format(" {0}", (routingResult.Distance * 0.621371192).ToString() + "driving miles")));
 
 
                                found++; // Increment found address
                            }
                            catch (Exception)
                            {
                                System.Diagnostics.Debug.WriteLine(dr["StreetAddress"].ToString() + "," +
                                                            dr["City"].ToString() + "," + dr["State"].ToString() + "," +
                                                            dr["Zip"].ToString());
 
                                notFound++; // Increment found non address
                            }
                        }
                        else
                        {
                            notFound++; // Increment found non address
                        }
                    }
                    else
                    {
                        notFound++; // Increment found non address
                    }
                }
                //-----------------------------------------------------------------------------------------
 
                //Show Results
                lblTotal.Text = resultSet.Rows.Count.ToString();
                lblFound.Text = found.ToString();
                lblNotFound.Text = notFound.ToString();
 
                var q = (from p in addresses.AsEnumerable()
                         select p).Take(50);
 
                GridView1.DataSource = q;
                GridView1.DataBind();
 
            }
            catch (Exception ex)
            {
                Response.Write(ex.Message);
            }
            finally
            {
                usaGeocoder.Close();
                featureSource.Close();
                routingSource.Close();
            }
 
        }
 


Sorry for the delay on responding your request. I let you know that we are currently working on your case. You should have a response on Monday morning. Thank you.

Jason, 
  
 I’m sure that lots of time is spent on matching the address and calculating the distance. One solution is that you can use “MapEngine.GenerateServiceArea” with the distances you want, and then do the spatial query between the service area polygon and the array of addresses. Please refer the installed routing sample “ServiceAreaDefinition.cs” for details. 
  
 Thanks, 
  
 Johnny. 


Johnny,


Is there sample code to do a spatial query between the service area poygon and the arary of addresses to get driving distance? Thanks.


 


Jose



The Service Area represents the area that can be reached from a certain point within a certain time at a certain speed. The Service Area is a Polygon. If you want to know if an address belongs to that polygon, simply use the Contains method with the PointShape representing the address. If you have an array of addresses, do it in a loop.



 PolygonShape polygonShape = routingEngine.GenerateServiceArea(txtStartId.Text, new TimeSpan(0, drivingMinutes, 0), averageSpeed, speedUnit);
            InMemoryFeatureLayer routingLayer = (InMemoryFeatureLayer)((LayerOverlay)winformsMap1.Overlays["RoutingOverlay"]).Layers["RoutingLayer"];

            bool IsContained = polygonShape.Contains(addressPointShape);