static void showResult(string[] orig, DistanceResults distances) { Console.WriteLine("Searched:\t{0}", string.Join(" | ", orig)); Console.WriteLine("Status:\t{0}", distances.Status); Console.WriteLine("Locations:\t{0}", string.Join(" | ", distances.Origin)); int j = 0; foreach (var row in distances.Row) { int i = 0; foreach (var col in row) { Console.WriteLine("Path:\t{0}...{1}", distances.Origin[i], distances.Destination[j]); if (col != null) { Console.WriteLine("\tDuration:\t{0}", col.DurationText); Console.WriteLine("\tDistance:\t{0}", col.DistanceText); } else { Console.WriteLine("Data not found. Check the name of the location. Chnage it to a land address."); } i++; } j++; } }
public void WriteXML(DistanceResults store, string f) { XmlSerializer writer = new XmlSerializer(typeof(DistanceResults)); var path = f; using (FileStream file = System.IO.File.Create(path)) { writer.Serialize(file, store); file.Close(); } }
public DistanceResults getCachedDistances(string[] places) { string cachefile = GetFilenameFor(places, places); if (File.Exists(cachefile) && DateTime.Now - (new FileInfo(cachefile)).LastWriteTime < __30_DAYS) { try { return(ReadXML(cachefile)); } catch (Exception ex) { System.Diagnostics.Debug.WriteLine(ex.Message); File.Delete(cachefile); } } DistanceResults result = getDistancesFromGoogle(places); WriteXML(result, cachefile); return(result); }
//we want a system of ordering the requests to make best use of caching... order the requests by origin and destination public DistanceResults GetDistanceMatrix(IList <string> origin, IList <string> dest) { DistanceResults matrix = new DistanceResults() { Status = "OK" }; matrix.Origin.AddRange(origin); matrix.Destination.AddRange(dest); matrix.OriginResponse = new string[origin.Count]; matrix.DestinationResponse = new string[dest.Count]; //find out if an existing resultset was requested and cached var filename = getNTFSName(matrix.ToFilename()); //hash the filename to comply with NTFS rules if (File.Exists(filename)) { try { return(_service.ReadXML(filename)); //return GoogleDistanceMatrix.ReadXML(filename); } catch { File.Delete(filename); } } //resultset not cached matrix.Row.AddRange(origin.Select(s => new List <DistElement>(dest.Select <string, DistElement>(s2 => null)))); //so assume some are cached...some are not... //how do we group the stuff not cached which gets send remotely //get the stuff cached, and assign scores to each origin with a correlated misses //getting the misses is easy... how do we group the misses together, so we make a one big request with stuff we want. //previously, we did it with same counts... // we can do it with flags ANDed together // A B C D E F // Z 1 1 1 0 0 1 = 4 (previous code grouped all the 4's together and tried to figure which dest matched) // Y 1 1 1 0 0 1 = 4 // X 1 1 0 1 0 1 = 4 // W 1 1 0 0 1 1 = 4 // ---------------- // 1 1 0 0 0 1 = 3 But if we AND all the bits, then look at it, we know we only request [Z Y X W] x [A B F] // But this means we have to do a cross-AND with every row, of every origin with same number of misses, to determine 2nd-order sort // plus the excluded [Z Y X W] x [C D E], which only has 4x 1's, out of 12 requests // // so this turns above into // A B F C D E // Z 1 1 1 = 3 1 0 0 // Y 1 1 1 = 3 1 0 0 // X 1 1 1 = 3 0 1 0 // W 1 1 1 = 3 0 0 1 // // C // Z 1 // Y 1 // D // X 1 // E // W 1 // // so to minimize the number of costable requests to google..., though we can call [Z Y X W] x [C D E], with a 75% miss rate // is a var notfound = false; var matrixRow = matrix.Row; var oricount = origin.Count; var destcount = dest.Count; bool[,] found = new bool[destcount, oricount]; for (int j = 0; j < oricount; j++) { for (int i = 0; i < destcount; i++) { var from = origin[j]; var to = dest[i]; if (this.Contains(from, to)) { found[j, i] = true; matrixRow[j][i] = this[from, to]; } else if (!notfound) { notfound = true; } } } if (notfound) { ReduceSurfaceAreaByReordering waterdrop = new ReduceSurfaceAreaByReordering() { Area = found }; waterdrop.SortPass += delegate(object sender, EventArgs e) { Console.WriteLine("Finding missing elements"); }; BiggestContiguousBlock skimmer = new BiggestContiguousBlock(waterdrop); foreach (var item in skimmer.Chunkify(false)) { //item.SetAllTrue(); const int GOOGLE_MAX_ORIGIN_OR_DEST = 25; const int GOOGLE_MAX_REQUESTS = 100; const int GOOGLE_DEFACTO_MAX_ORIGIN_AND_DEST = 10; foreach (var subitem in item.Chunkify(GOOGLE_DEFACTO_MAX_ORIGIN_AND_DEST)) { var suborigin = subitem.RowIndices.Select(s => origin[s]).ToArray(); var subdest = subitem.ColIndices.Select(s => dest[s]).ToArray(); if (this.RemoteRetreive != null) { this.RemoteRetreive(this, new UserRequestEventArgs("[" + string.Join("; ", suborigin) + "] to [" + string.Join("; ", subdest) + "]")); } var googleresults = _service.RetryDistancesFromGoogle(10, 1000, suborigin, subdest); //GetDistancesFromGoogle(suborigin, subdest); //change this to var row = 0; var col = 0; foreach (var fromindex in subitem.RowIndices) { col = 0; foreach (var toindex in subitem.ColIndices) { var from = origin[fromindex]; var to = dest[toindex]; var data = googleresults.Row[row][col++]; if (data.Status == "OK") { matrixRow[fromindex][toindex] = data; } else if (this.UserRequestError != null) { this.UserRequestError(this, new UserRequestEventArgs("[" + from + "] to [" + to + "]", data.Status)); } } row++; } //until alias system is up, update with user requested name row = 0; col = 0; foreach (var fromindex in subitem.RowIndices) { matrix.OriginResponse[fromindex] = googleresults.Origin[row++]; } foreach (var toindex in subitem.ColIndices) { matrix.DestinationResponse[toindex] = googleresults.Destination[col++]; } subitem.SetAllTrue(); } } _service.WriteXML(matrix, filename); } //and group the stuff cached, in such a way that it takes the best use of the deserialized object cache... (obviously file caching works better too) return(matrix); }
public DistanceResults GetDistancesFromGoogle(string[] from, string[] to) { string joined1 = string.Join("|", ToUrlSafeRequest(from)); string joined2 = from == to ? joined1 : string.Join("|", ToUrlSafeRequest(to)); // string url = "http://maps.googleapis.com/maps/api/distancematrix/xml?origins=New+York+NY|Seattle&destinations=San+Francisco|New+York+NY|Boston&mode=driving&language=en-US&sensor=false"; string url = string.Format(@"https://maps.googleapis.com/maps/api/distancematrix/xml?key={0}&origins={1}&destinations={2}&mode=driving&language=en-US&sensor=false", __API_KEY, joined1, joined2); XmlDocument doc = MakeRequest(url); /* * <?xml version="1.0" encoding="UTF-8"?> * <DistanceMatrixResponse> * <status>OK</status> * <origin_address>New York, NY, USA</origin_address> * <origin_address>Seattle, WA, USA</origin_address> * <destination_address>San Francisco, CA, USA</destination_address> * <destination_address>New York, NY, USA</destination_address> * <destination_address>Boston, MA, USA</destination_address> * <row> * <element> * <status>OK</status> * <duration> * <value>152102</value> * <text>1 day 18 hours</text> * </duration> * <distance> * <value>4674274</value> * <text>4,674 km</text> * </distance> * </element> * <element> * <status>OK</status> * <duration> * <value>0</value> * <text>1 min</text> * </duration> * <distance> * <value>0</value> * <text>1 m</text> * </distance> * </element> * <element> * <status>OK</status> * <duration> * <value>13039</value> * <text>3 hours 37 mins</text> * </duration> * <distance> * <value>346503</value> * <text>347 km</text> * </distance> * </element> * </row> * <row> * <element> * <status>OK</status> * <duration> * <value>44447</value> * <text>12 hours 21 mins</text> * </duration> * <distance> * <value>1299975</value> * <text>1,300 km</text> * </distance> * </element> * <element> * <status>OK</status> * <duration> * <value>148892</value> * <text>1 day 17 hours</text> * </duration> * <distance> * <value>4589407</value> * <text>4,589 km</text> * </distance> * </element> * <element> * <status>OK</status> * <duration> * <value>158468</value> * <text>1 day 20 hours</text> * </duration> * <distance> * <value>4901431</value> * <text>4,901 km</text> * </distance> * </element> * </row> * </DistanceMatrixResponse> */ int value = 0; DistanceResults result = new DistanceResults(); XmlNode statusnode = doc.DocumentElement.SelectSingleNode("/DistanceMatrixResponse/status"); if (statusnode != null) { result.Status = statusnode.InnerText; } XmlNodeList orinode = doc.DocumentElement.SelectNodes("/DistanceMatrixResponse/origin_address"); foreach (XmlNode node in orinode) { result.Origin.Add(node.InnerText); } XmlNodeList destnode = doc.DocumentElement.SelectNodes("/DistanceMatrixResponse/destination_address"); foreach (XmlNode node in destnode) { result.Destination.Add(node.InnerText); } XmlNodeList rownode = doc.DocumentElement.SelectNodes("/DistanceMatrixResponse/row"); foreach (XmlNode node in rownode) { List <DistElement> row = new List <DistElement>(); XmlNodeList colnode = node.SelectNodes("element"); foreach (XmlNode elenode in colnode) { DistElement element = new DistElement(); XmlNode statmnode = elenode.SelectSingleNode("status"); if (statmnode != null) { element.Status = statmnode.InnerText; } XmlNode dursnode = elenode.SelectSingleNode("duration/value"); if (dursnode != null && int.TryParse(dursnode.InnerText, out value)) { element.DurationSeconds = dursnode.InnerText; } XmlNode durnode = elenode.SelectSingleNode("duration/text"); if (durnode != null) { element.DurationText = durnode.InnerText; } XmlNode dstmnode = elenode.SelectSingleNode("distance/value"); if (dstmnode != null && int.TryParse(dstmnode.InnerText, out value)) { element.DistanceMeters = dstmnode.InnerText; } XmlNode dstnode = elenode.SelectSingleNode("distance/text"); if (dstnode != null) { element.DistanceText = dstnode.InnerText; } row.Add(element); } result.Row.Add(row); } return(result); }
static int Main(string[] args) { bool __USER_PERMISSION_FOR_GOOGLE = false; if (args.Length == 0 && System.Console.WindowWidth != 0 && System.Console.WindowHeight != 0) { showUsage(); return(1); } if (string.IsNullOrWhiteSpace(GoogleApiKeys.DistanceApiKey)) { Console.WriteLine("No API key for Distance API. Please enter:"); Console.Write(">"); var key = Console.ReadLine(); if (string.IsNullOrWhiteSpace(key)) { Console.WriteLine("Bad API key"); return(2); } else { GoogleApiKeys.DistanceApiKey = key; } } GoogleLocalDistanceIndex.Index.RemoteRetreive += delegate(object sender, GoogleLocalDistanceIndex.UserRequestEventArgs e) { Console.WriteLine("Data not local, Remotely requesting : {0}", e.Requested); if (!__USER_PERMISSION_FOR_GOOGLE) { Console.WriteLine(); Console.WriteLine("Google charges $ for Distance Matrix API per Data Element. \nThis application can request hundreds of data elements. \nPlease check the terms of your Google use agreement about cost. This may incur billing to the API KEY."); Console.Write("Do you wisth to proceed? (Y/N) >"); var response = Console.ReadLine(); if (response == "Y" || response == "y") { __USER_PERMISSION_FOR_GOOGLE = true; } else { Environment.Exit(0); } Console.WriteLine(); } }; GoogleLocalDistanceIndex.Index.UserRequestError += delegate(object sender, GoogleLocalDistanceIndex.UserRequestEventArgs e) { Console.WriteLine(); Console.WriteLine("Error with : {0}", e.Requested); Console.WriteLine("Message : {0}", e.Error); Console.WriteLine(); }; //see if its a file int rcode = 0; if (args.Length == 1 && System.Console.WindowWidth != 0 && System.Console.WindowHeight != 0 && File.Exists(args[0])) { using (var fs = File.OpenText(args[0])) { var line = fs.ReadToEnd().Split('\n'); //DistanceResults location = getCachedDistances(line); DistanceResults location = GoogleLocalDistanceIndex.Index.GetDistanceMatrix(line); if (location != null) { showResult(line, location); } else { rcode = 2; } } return(rcode); } // stdin /* * string sin; * if (System.Console.WindowWidth == 0 && System.Console.WindowHeight == 0) * while ((sin = Console.ReadLine()) != null) * { * LocationResults location = getCachedLocation(sin); * if (location != null) * showResult(sin, location); * else * rcode = 2; * } */ // all the arguments must be locations then { //DistanceResults location = getCachedDistances(args); DistanceResults location = GoogleLocalDistanceIndex.Index.GetDistanceMatrix(args); if (location != null) { showResult(args, location); } else { rcode = 2; } } #if DEBUG Console.WriteLine("Press [enter] to end"); Console.ReadLine(); #endif return(rcode); }