'Returns Features within a Radius (in km) of a LatLon Location
Unused'

def get_features_in_radius(self, lat, lon, radius, tablename=None, category=None):

    import math
    db = current.db
    settings = current.deployment_settings
    if (settings.gis.spatialdb and (settings.database.db_type == 'postgres')):
        import psycopg2
        import psycopg2.extras
        dbname = settings.database.database
        username = settings.database.username
        password = settings.database.password
        host = settings.database.host
        port = (settings.database.port or '5432')
        radius = math.degrees((float(radius) / RADIUS_EARTH))
        connection = psycopg2.connect(('dbname=%s    user=%s    password=%s    host=%s    port=%s' % (dbname, username, password, host, port)))
        cursor = connection.cursor(cursor_factory=psycopg2.extras.DictCursor)
        info_string = ("SELECT    column_name,    udt_name    FROM    information_schema.columns    WHERE    table_name    =    'gis_location'    or    table_name    =    '%s';" % tablename)
        cursor.execute(info_string)
        if tablename:
            query_string = cursor.mogrify(("SELECT    *    FROM    gis_location,    %s    WHERE    %s.location_id    =    gis_location.id    and    ST_DWithin    (ST_GeomFromText    ('POINT    (%s    %s)',    4326),    the_geom,    %s);" % (tablename, tablename, lat, lon, radius)))
        else:
            query_string = cursor.mogrify(("SELECT    *    FROM    gis_location    WHERE    ST_DWithin    (ST_GeomFromText    ('POINT    (%s    %s)',    4326),    the_geom,    %s);" % (lat, lon, radius)))
        cursor.execute(query_string)
        features = []
        for record in cursor:
            d = dict(record.items())
            row = Storage()
            if tablename:
                row.gis_location = Storage()
                row.gis_location.id = d['id']
                row.gis_location.lat = d['lat']
                row.gis_location.lon = d['lon']
                row.gis_location.lat_min = d['lat_min']
                row.gis_location.lon_min = d['lon_min']
                row.gis_location.lat_max = d['lat_max']
                row.gis_location.lon_max = d['lon_max']
                row[tablename] = Storage()
                row[tablename].id = d['id']
                row[tablename].name = d['name']
            else:
                row.name = d['name']
                row.id = d['id']
                row.lat = d['lat']
                row.lon = d['lon']
                row.lat_min = d['lat_min']
                row.lon_min = d['lon_min']
                row.lat_max = d['lat_max']
                row.lon_max = d['lon_max']
            features.append(row)
        return features
    else:
        bbox = self.get_bounds_from_radius(lat, lon, radius)
        locations = db.gis_location
        query = ((((locations.lat > bbox['lat_min']) & (locations.lat < bbox['lat_max'])) & (locations.lon > bbox['lon_min'])) & (locations.lon < bbox['lon_max']))
        deleted = (locations.deleted == False)
        empty = ((locations.lat != None) & (locations.lon != None))
        query = ((deleted & empty) & query)
        if tablename:
            table = current.s3db[tablename]
            query &= (table.location_id == locations.id)
            records = db(query).select(table.ALL, locations.id, locations.name, locations.level, locations.lat, locations.lon, locations.lat_min, locations.lon_min, locations.lat_max, locations.lon_max)
        else:
            records = db(query).select(locations.id, locations.name, locations.level, locations.lat, locations.lon, locations.lat_min, locations.lon_min, locations.lat_max, locations.lon_max)
        features = Rows()
        for row in records:
            if tablename:
                distance = self.greatCircleDistance(lat, lon, row['gis_location.lat'], row['gis_location.lon'])
            else:
                distance = self.greatCircleDistance(lat, lon, row.lat, row.lon)
            if (distance < radius):
                features.records.append(row)
            else:
                continue
        return features
