Exemple #1
0
    def __init__(self,fileName):
        """Opens the local CSV file with place names, latitudes, and longitudes."""
        m = "GetLatLon/init:"
        sop(3,m,"Entry. fileName=%s" % ( fileName ))

        # Open and parse the local CSV file.
        ignoreStringList = [ "/", "#", '"Place Name"', '"=====' ]
        recordName = "Place Name"
        columnNameList = [ "Place Name", "Latitude", "Longitude" ]
        self.latLonDatabase = CSVFile(fileName,ignoreStringList,recordName,columnNameList)

        sop(3,m,"Exit.")
Exemple #2
0
class GetLatLon:
    def __init__(self,fileName):
        """Opens the local CSV file with place names, latitudes, and longitudes."""
        m = "GetLatLon/init:"
        sop(3,m,"Entry. fileName=%s" % ( fileName ))

        # Open and parse the local CSV file.
        ignoreStringList = [ "/", "#", '"Place Name"', '"=====' ]
        recordName = "Place Name"
        columnNameList = [ "Place Name", "Latitude", "Longitude" ]
        self.latLonDatabase = CSVFile(fileName,ignoreStringList,recordName,columnNameList)

        sop(3,m,"Exit.")

    def get(self,placeName):
        """Returns two strings, latitude and longitude, for the specified placeName.
        Returns the value found in the local CSV file, or from Google Maps.
        If fetched from Google Maps, also stores the value into the local CSV file."""
        m = "GetLatLon/get:"
        sop(5,m,"Entry. placeName=%s" % ( placeName ))

        # For verbose debug only
        # self.latLonDatabase.toString()

        # Clean up the place name.
        # Tolerate wierd sequences of spaces, single quotes, and double quotes.
        placeName = placeName.strip("'").strip('"').strip().strip("'").strip('"').strip()
        sop(5,m,"Stripped. placeName=%s" % ( placeName ))

        lat = self.latLonDatabase.get(placeName, "Latitude")
        lon = self.latLonDatabase.get(placeName, "Longitude")
        sop(5,m,"lat=%s lon=%s" % ( lat, lon ))

        if None != lat and None != lon:
            lat6 = self.getSignificantDigits(lat)
            lon6 = self.getSignificantDigits(lon)
            sop(5,m,"Exit. Returning lat/lon from local CSV file. lat6=%s lon6=%s" % ( lat6, lon6 )) 
            return lat6,lon6

        # Get new coordinates from Google.
        latLonJSON = self.getLatLonJSONForAddress(placeName)
        #sop(5,m,"After fetching from Google, latLonJSON=%s" % ( latLonJSON ))

        # Parse and extract the lat/lon from JSON response string.
        lat,lon = self.getLatLonFromGoogleJSON( latLonJSON )
        #sop(5,m,"After parsing, lat=%s lon=%s" % ( lat, lon ))

        # Add lat/lon to database propertiess file for future use.
        # (It would be nice to clean this up and abstract the 'schema'.)
        self.latLonDatabase.put( [placeName, lat, lon] )

        lat6 = self.getSignificantDigits(lat)
        lon6 = self.getSignificantDigits(lon)
        sop(5,m,"Exit. Returning lat/lon from Google. lat6=%s lon6=%s" % ( lat6, lon6 )) 
        return lat6,lon6

    def getLatLonJSONForAddress(self, address):
       """Issues an HTTP request to Google Maps Geocoding API in order to 
       fetch latitude and longitude values for a searchable address string.  
       Returns a JSON string containing latitude,longitude, etc."""
       m = "GetLatLon/getLatLonJSONForAddress:"
       sop(5,m,"Entry. address=%s" % ( address ))
       responseJSON = None

       # Trim leading and trailing whitespace.
       address = address.strip()

       # Trim leading and trailing double quotes.
       address = address.strip('"')

       # Convert all spaces in the address to plus signs.
       address = address.replace(" ","+")

       sop(5,m,"After stripping and converting, address=%s" % ( address ))

       # Define the URL to transmit to Google Maps.
       geocodeHostname = "maps.googleapis.com"
       geocodeURL = "http://%s/maps/api/geocode/json?address=%s&sensor=false" % ( geocodeHostname, address )
       sop(5,m,"geocodeURL=%s" % ( geocodeURL ))

       # Fetch
       # (MY mod:  sleep 0.15 seconds for rate limiting)
       sop(5,m,"Sleeping to stay within rate limits")
       time.sleep(0.15) # Google rate limit is 2500 per day or 10 per second
       sop(5,m,"Issuing request.")
       try:
           httpConnection = httplib.HTTPConnection(geocodeHostname)
           httpConnection.request('GET',geocodeURL)
           httpResponse = httpConnection.getresponse()
           sop(5,m,"httpResponse.status=%s" % ( httpResponse.status ))

           # Evaluate response code.
           if 200 == httpResponse.status:
               # Read response data.
               responseJSON = httpResponse.read()
               sop(5,m,"responseJSON=%s" % ( responseJSON ))
           else:
               sop(5,m,"Error. Could not fetch address information from Google Maps.")

           # Close the connection.
           httpConnection.close()
       except:
           raise RuntimeError(m + " ERROR: Could not fetch lat/lon from Google Geocode API for address %s" % ( address ))

       sop(5,m,"Exit. Returning responseJSON.")
       return responseJSON

    def getLatLonFromGoogleJSON( self, jsonString ):
        """Parses a JSON string received as a response
        from the Google Maps Geocoding API.  For example,
            { "status": "OK",
              "results": [ {"types": [ "street_address" ],
                            "formatted_address": "1600 Amphitheatre Pkwy, Mountain View, CA 94043, USA",
                            "address_components": [ { "long_name": "1600",
                                                      "short_name": "1600",
                                                      "types": [ "street_number" ]  },
                                                    { "long_name": "Amphitheatre Pkwy",
                                                      "short_name": "Amphitheatre Pkwy",
                                                      "types": [ "route" ]  },
                                                  ],
                            "geometry" : { "location": { "lat": 37.4219720,
                                                         "lng": -122.0841430 },
                                           "location_type": "ROOFTOP",
                                           "viewport": { "southwest": { "lat": 37.4188244,
                                                                        "lng": -122.0872906 },
                                                         "northeast": { "lat": 37.4251196,
                                                                        "lng": -122.0809954}}}} ]}'

        This method is hard-coded to assume: results-> geometry-> location-> lat/lon.
        This method uses python library simplejson.
        This method returns two string values: latitude,longitude"""
        m = "getLatLonFromGoogleJSON:"
        sop(5,m,"Entry.")
        sop(5,m,"jsonString=%s" % ( jsonString ))

        # Convert the JSON string into a python object.
        jsonObject = simplejson.loads( jsonString )
        #sop(5,m,"jsonObject=%s" % ( jsonObject ))

        # Verify status is 'OK'
        statusString = jsonObject["status"]
        #sop(5,m,"statusString=%s" % ( statusString ))
        if "OK" != statusString:
            raise RuntimeError(m + " Error: Status is not OK. Status=%s" % ( statusString ))

        # Extract the results list, which is expected to contain one element.
        resultsList = jsonObject["results"]
        #sop(5,m,"resultsList=%s" % ( resultsList ))
        if 1 != len(resultsList):
            sop(5,m, "WARNING: Unexpected number of elements in results list. Using first element. expected=1 actual=%i" % ( len(resultsList )))

        # Extract the first and only element.
        results = resultsList[0]
        #sop(5,m,"results=%s" % ( results ))

        # Extract the geometry element from the results.
        geometry = results["geometry"]
        #sop(5,m,"geometry=%s" % ( geometry ))

        # Extract the location from geometry.
        location = geometry["location"]
        #sop(5,m,"location=%s" % ( location ))

        # And finally, extract the latitude and longitude from the location.
        # Note the variable name translation:  lon (my preference) vs lng (Google's preference)
        lat = location["lat"]
        lon = location["lng"]
        #sop(5,m,"lat=%s lon=%s" % ( lat, lon ))

        # Convert to strings, in case they are parsed as numbers.
        latString = "%s" % ( repr(lat) )
        lonString = "%s" % ( repr(lon) )

        sop(5,m,"Exit. Returning latString=%s, lonString=%s" % ( latString, lonString ))
        return latString,lonString

    def getSignificantDigits(self, input):
        """Returns a max number of digits following the decimal point for a lat and/or lon string.
        This is done in an attempt to simplify the processing load at google maps.
        Input is a string holding what looks like a floating point number.
        Returns the same type of string."""
        m = "getSignificantDigits:"
        sop(5,m,"Entry.")
        sop(5,m,"input=%s" % ( input ))

        # Find the decimal point.
        indexPoint = input.index(".")
        sop(5,m,"indexpoint=%i" % ( indexPoint ))

        if 0 > indexPoint:
            output = input
        else:
            if len(input) < (indexPoint + 5):
                output = input
            else:
                output = input[:(indexPoint + 5)]

        sop(5,m,"Exit. Returning output=>>>%s<<< for input=%s" % ( output, input ))
        return output