// !!!! HELPER FUNCTIONS !!!! public List<PointOfInterest> getPlaces(Location start, int timeInMinutes) { //create query //build ("https://maps.googleapis.com/maps/api/place/nearbysearch/output?" + parameters) //OR (less data) string URI = "https://maps.googleapis.com/maps/api/place/radarsearch/json?"; //add parameters //key URI += "key=" + (new Secrets()).GoogleAPIServerKey + "&"; //location URI += "location=" + start.latitude.ToString() + "," + start.longitude.ToString() + "&"; //radius; estimate 1 meter per second walking speed URI += "radius=" + (timeInMinutes * 60 / 2).ToString() + "&"; //types; start with "park" and possibly add more later //see https://developers.google.com/places/supported_types for list of types URI += "types=park"; //create a new, empty list of Points Of Interest List<PointOfInterest> candidatePoIs = new List<PointOfInterest>(); //request processing var googleRadarObject = JToken.Parse(callAPIgetJSon(URI)); var status = googleRadarObject.Children<JProperty>().FirstOrDefault(x => x.Name == "status").Value; if (status.ToString() == "OK") { var resultsArray = googleRadarObject.Children<JProperty>().FirstOrDefault(x => x.Name == "results").Value; //iterate over the json and parse into PointsOfInterest, placing each in the list foreach (var item in resultsArray) { //extract the google place id string GooglePlaceId = item.Children<JProperty>().FirstOrDefault(x => x.Name == "place_id").Value.ToString(); //extract the lattitude from JSon structuret decimal lat = decimal.Parse( item.Children<JProperty>().FirstOrDefault(x => x.Name == "geometry").Value. Children<JProperty>().FirstOrDefault(x => x.Name == "location").Value. Children<JProperty>().FirstOrDefault(x => x.Name == "lat").Value.ToString()); //extract the longitude from JSon structure decimal lng = decimal.Parse( item.Children<JProperty>().FirstOrDefault(x => x.Name == "geometry").Value. Children<JProperty>().FirstOrDefault(x => x.Name == "location").Value. Children<JProperty>().FirstOrDefault(x => x.Name == "lng").Value.ToString()); //create new PoI with above properties PointOfInterest point = new PointOfInterest(lat, lng, GooglePlaceId); //add it to the list of candidates candidatePoIs.Add(point); } } //return processed list return candidatePoIs; }
public ActionResult Walk(FormCollection collection) { Location start = new Location(decimal.Parse(collection["startLatitude"]), decimal.Parse(collection["startLongitude"])); int time = int.Parse(collection["timeInput"]); List<PointOfInterest> radarList = getPlaces(start, time); List<PointOfInterest> goldilocks = screenPlaces(radarList, start, time); PointOfInterest chosen = null; if (goldilocks.Count() > 0) { chosen = goldilocks[0]; } else if (radarList.Count() > 0) { chosen = radarList[radarList.Count() - 1]; } if (chosen != null) { ViewBag.GoogleId = chosen.GooglePlaceId; ViewBag.Latitude = chosen.location.latitude; ViewBag.Longitude = chosen.location.longitude; ViewBag.OriginLat = start.latitude; ViewBag.OriginLon = start.longitude; ViewBag.NoneInRange = false; } else { ViewBag.NoneInRange = true; } ViewBag.time = time; if (chosen != null){ ViewBag.GoogleId = chosen.GooglePlaceId; ViewBag.Latitude = chosen.location.latitude; ViewBag.Longitude = chosen.location.longitude; ViewBag.NoneInRange = false; string poiURL = "http://maps.google.com/maps?q="; poiURL += chosen.location.latitude + "," + chosen.location.longitude; ViewBag.PoIMapLink = poiURL; } else { ViewBag.NoneInRange = true; } ViewBag.time = time; return View(); }
List<PointOfInterest> screenPlaces(List<PointOfInterest> candidates, Location start, int timeInMinutes) { //if the candidates list is empty, return the/an empty list if (!(candidates.Any<PointOfInterest>())) { return candidates; } //create distance matrix query string URI = "https://maps.googleapis.com/maps/api/distancematrix/json?"; //add parameters //key URI += "key=" + (new Secrets()).GoogleAPIServerKey + "&"; //specifiy walking URI += "mode=walking&"; //origin location URI += "origins=" + start.latitude.ToString() + "," + start.longitude.ToString() + "&"; //list all candidate points of interest by lat/lon as destinations URI += "destinations="; //iterate over candidate destinations, and add each location, separated by a pipe | int count = candidates.Count(); for (int i = 0; i < count; i++) { URI += candidates[i].getLatitude().ToString() + "," + candidates[i].getLongitude().ToString(); if (i < count - 1) // if not the last item in the list { URI += "|"; //add a pipe to separate destinations } } List<PointOfInterest> viable = new List<PointOfInterest>(); //create a new empty list //calculate Goldilocks range (not too far but also not too close) in seconds //use 90-100% of available one-way time to start //may need to iterate or otherwise process & if so, should probably save the times instead of make decisions in loop //note that these use integer math int ceiling = (timeInMinutes * 60) / 2; //max length of each leg of round trip int floor = (ceiling * 9) / 10; //min length of each leg of round trip var client = new WebClient(); var values = System.Web.HttpUtility.ParseQueryString(string.Empty); var result = client.DownloadData(URI.ToString()); var json = Encoding.UTF8.GetString(result); var serializer = new JavaScriptSerializer(); var distanceResponse = serializer.Deserialize<DistanceResponse>(json); //extract elements' travel times //remember there is only one destination, so the elements list the times to destinations in order if (string.Equals("OK", distanceResponse.Status, StringComparison.OrdinalIgnoreCase)) { var elements = (distanceResponse.Rows[0]).Elements; for (int i = 0; i < count; i++) { //extract the time in seconds from origin to the current (i'th) destination if (string.Equals("OK", distanceResponse.Status, StringComparison.OrdinalIgnoreCase)) { // making a new int value to be able to better understand what the actual value is. int value = elements[i].Duration.Value; //compare to Goldilocks zone to evaluate and add to list if in the range if (value > floor && value <= ceiling) { viable.Add(candidates[i]); } } } } Console.WriteLine(candidates); return viable; }