Beispiel #1
0
  def test_geo(self):
    _populate_db()

    results = PublicSchool.bounding_box_fetch(
      PublicSchool.query().order(PublicSchool.school_id),
      geotypes.Box(39, -82, 41, -84),
      max_results=10)
    self.assertEqual(len(results), 2)
    self.assertEqual(results[0].school_id, '390000104683')
    self.assertEqual(results[1].school_id, '390000204684')

    results = PublicSchool.bounding_box_fetch(
      PublicSchool.query().order(PublicSchool.school_id),
      geotypes.Box(38, -83, 40, -85),
      max_results=10)
    self.assertEqual(len(results), 1)
    self.assertEqual(results[0].school_id, '390002001515')

    results = PublicSchool.proximity_fetch(
      PublicSchool.query(),
      geotypes.Point(40, -83),
      max_results=10,
      max_distance=50000) # Within 50km.
    self.assertEqual(len(results), 2)
    self.assertEqual(results[0].school_id, '390000104683')
    self.assertEqual(results[1].school_id, '390000204684')

    results = PublicSchool.proximity_fetch(
      PublicSchool.query(),
      geotypes.Point(34, -117),
      max_results=10,
      max_distance=50000) # Within 50km.
    self.assertEqual(len(results), 2)
    self.assertEqual(results[0].school_id, '590019700136')
    self.assertEqual(results[1].school_id, '590010500138')
Beispiel #2
0
def compute_box(cell):
    """Computes the rectangular boundaries (bounding box) of the given geocell.

  Args:
    cell: The geocell string whose boundaries are to be computed.

  Returns:
    A geotypes.Box corresponding to the rectangular boundaries of the geocell.
  """
    if cell is None:
        return None

    bbox = geotypes.Box(90.0, 180.0, -90.0, -180.0)

    while len(cell) > 0:
        subcell_lon_span = (bbox.east - bbox.west) / _GEOCELL_GRID_SIZE
        subcell_lat_span = (bbox.north - bbox.south) / _GEOCELL_GRID_SIZE

        x, y = _subdiv_xy(cell[0])

        bbox = geotypes.Box(bbox.south + subcell_lat_span * (y + 1),
                            bbox.west + subcell_lon_span * (x + 1),
                            bbox.south + subcell_lat_span * y,
                            bbox.west + subcell_lon_span * x)

        cell = cell[1:]

    return bbox
Beispiel #3
0
def distance_sorted_edges(cells, point):
    """Returns the edges of the rectangular region containing all of the
  given geocells, sorted by distance from the given point, along with
  the actual distances from the point to these edges.

  Args:
    cells: The cells (should be adjacent) defining the rectangular region
        whose edge distances are requested.
    point: The point that should determine the edge sort order.

  Returns:
    A list of (direction, distance) tuples, where direction is the edge
    and distance is the distance from the point to that edge. A direction
    value of (0,-1), for example, corresponds to the South edge of the
    rectangular region containing all of the given geocells.
  """
    # TODO(romannurik): Assert that lat,lon are actually inside the geocell.
    boxes = [geocell.compute_box(cell) for cell in cells]

    max_box = geotypes.Box(max([box.north for box in boxes]),
                           max([box.east for box in boxes]),
                           min([box.south for box in boxes]),
                           min([box.west for box in boxes]))
    return zip(*sorted(
        [((0, -1),
          geomath.distance(geotypes.Point(max_box.south, point.lon), point)),
         ((0, 1),
          geomath.distance(geotypes.Point(max_box.north, point.lon), point)),
         ((-1, 0),
          geomath.distance(geotypes.Point(point.lat, max_box.west), point)),
         ((1, 0),
          geomath.distance(geotypes.Point(point.lat, max_box.east), point)
          )], lambda x, y: cmp(x[1], y[1])))
Beispiel #4
0
    def test_Box(self):
        # an invalid box
        self.assertRaises(ValueError, geotypes.Box, 95, 0, 0, 0)

        # a valid box
        box = geotypes.Box(37, -122, 34, -125)
        self.assertEquals(37, box.north)
        self.assertEquals(34, box.south)
        self.assertEquals(-122, box.east)
        self.assertEquals(-125, box.west)

        # assert north can't be under south
        self.assertRaises(ValueError, box._set_north, 32)
        self.assertRaises(ValueError, box._set_south, 39)

        self.assertTrue(isinstance(box.__str__(), str))

        # valid boxes
        self.assertEquals(geotypes.Box(37, -122, 34, -125),
                          geotypes.Box(34, -122, 37, -125))
Beispiel #5
0
def max_box(cells):
  """Returns the rectangular region containing all of the given geocells.
  
  Args:
    cells: A list of adjacent geocells.
  
  Returns:
    A geotypes.Box representing the maximum bounds of the set of adjacent cells.
  """
  boxes = [geocell.compute_box(cell) for cell in cells]
  return geotypes.Box(max([box.north for box in boxes]),
                      max([box.east for box in boxes]),
                      min([box.south for box in boxes]),
                      min([box.west for box in boxes]))
Beispiel #6
0
def best_bbox_search_cells(bbox, cost_function):
    """Returns an efficient set of geocells to search in a bounding box query.

  This method is guaranteed to return a set of geocells having the same
  resolution.

  Args:
    bbox: A geotypes.Box indicating the bounding box being searched.
    cost_function: A function that accepts two arguments:
        * num_cells: the number of cells to search
        * resolution: the resolution of each cell to search
        and returns the 'cost' of querying against this number of cells
        at the given resolution.

  Returns:
    A list of geocell strings that contain the given box.
  """
    cell_ne = compute(bbox.north_east, resolution=MAX_GEOCELL_RESOLUTION)
    cell_sw = compute(bbox.south_west, resolution=MAX_GEOCELL_RESOLUTION)

    # The current lowest BBOX-search cost found; start with practical infinity.
    min_cost = 1e10000

    # The set of cells having the lowest calculated BBOX-search cost.
    min_cost_cell_set = None

    # First find the common prefix, if there is one.. this will be the base
    # resolution.. i.e. we don't have to look at any higher resolution cells.\
    common_prefix = os.path.commonprefix([cell_sw, cell_ne])
    min_resolution = len(common_prefix)

    #ancho del viewport
    vpw = bbox.north_east.lon - bbox.south_west.lon
    deep = 1
    if vpw > 0:
        xx = log(360.0 / vpw)
        if xx > 0:
            deep = int(ceil(xx / log(_GEOCELL_GRID_SIZE))) - 1

    if deep > MAX_GEOCELL_RESOLUTION:
        deep = MAX_GEOCELL_RESOLUTION
    logging.debug(
        'best_bbox_search_cells() deep:[%s]; cell_sw:[%s]; cell_ne:[%s]; common_prefix:[%s]; min_resolution:[%s]; MAX_GEOCELL_RESOLUTION[%s]'
        % (str(deep), cell_sw, cell_ne, common_prefix, str(min_resolution),
           str(MAX_GEOCELL_RESOLUTION)))

    if min_resolution == deep or deep < 6:
        logging.debug(
            ' (if min_resolution == deep or deep<6:) ES VERDADERO!!!')
        return common_prefix, str(compute_box(common_prefix))

    #buscamos un primo sobre min_resolution (la caja grande)
    p0 = geotypes.Point(bbox.north_east.lat, bbox.south_west.lon)

    p0cell_gorda = compute(p0, MAX_GEOCELL_RESOLUTION, False)

    new_deep = deep

    p0cell = p0cell_gorda[:new_deep]

    p0New = compute_box(p0cell)

    dx = 360.0 / pow(_GEOCELL_GRID_SIZE, new_deep) / 4.0
    dy = 180.0 / pow(_GEOCELL_GRID_SIZE, new_deep) / 4.0

    primo_prefix = '0'
    primo_width = 4.0
    if vpw > (3 * dx):
        primo_prefix = '1'
        primo_width = 5.0

    #dx    => 1 de los chiquitos (deep+1)
    #dy    => 1 de los chiquitos (deep+1)
    #p0    => view port (top,left)
    #p0New => Box del gordo (deep-1)

    primoX0 = abs(int((p0.lon - p0New.south_west.lon) / dx))
    primoY0 = abs(int((p0.lat - p0New.north_east.lat) / dy))

    boxprimo = geotypes.Box(
        p0New.north_east.lat - (dy * primoY0),
        p0New.south_west.lon + (dx * primoX0) + (dx * primo_width),
        p0New.north_east.lat - (dy * primoY0) - (dy * primo_width),
        p0New.south_west.lon + (dx * primoX0))

    the_primo = p0cell + '.' + primo_prefix + str(primoX0) + str(primoY0)

    #logging.error('SIEMPRE ENCUENTRO EL PRIMO %s' % the_primo)

    return the_primo, boxprimo
Beispiel #7
0
def compute(point, resolution=MAX_GEOCELL_RESOLUTION, get_primos=False):
    """Computes the geocell containing the given point to the given resolution.

  This is a simple 16-tree lookup to an arbitrary depth (resolution).

  Args:
    point: The geotypes.Point to compute the cell for.
    resolution: An int indicating the resolution of the cell to compute.

  Returns:
    The geocell string containing the given point, of length <resolution>.
  """
    north = 90.0
    south = -90.0
    east = 180.0
    west = -180.0

    primos = []
    cell = ''
    #print 'point: '+str(point)
    while len(cell) < resolution:
        subcell_lon_span = (east - west) / _GEOCELL_GRID_SIZE
        subcell_lat_span = (north - south) / _GEOCELL_GRID_SIZE

        x = min(int(_GEOCELL_GRID_SIZE * (point.lon - west) / (east - west)),
                _GEOCELL_GRID_SIZE - 1)
        y = min(
            int(_GEOCELL_GRID_SIZE * (point.lat - south) / (north - south)),
            _GEOCELL_GRID_SIZE - 1)

        cell += _subdiv_char((x, y))

        if get_primos and len(cell) > 4:
            #ancho del level dividido 4
            dx = subcell_lon_span / 4
            dy = subcell_lat_span / 4

            #celdas: 0 es en la que estamos, tenemos que probar en 1 y 2
            #     [2]
            #  [1][0]
            cells = [
                cell,
                adjacent(cell, (-1, 0)),
                adjacent(cell, (0, 1)),
                adjacent(cell, (-1, 1))
            ]

            # cell: The geocell string whose neighbor is being calculated.
            # dir: An (x, y) tuple indicating direction, where x and y can be -1, 0, or 1.
            #   -1 corresponds to West for x and South for y, and
            #   1 corresponds to East for x and North for y.

            # boxes=[]
            #print '    dx (dLon): '+str(dx)
            #print '    dy (dLat): '+str(dy)

            #iteramos longitud
            for k in range(len(cells)):
                cur_cell = cells[k]

                #Skipeamos si es la misma (caso borde del mundo)
                if cur_cell == cell and k > 0:
                    continue

                #Calculamos la caja de la celda actual
                box = compute_box(cur_cell)

                #Armamos el punto superior-izquierdo
                p0 = geotypes.Point(box.north_east.lat, box.south_west.lon)

                # print ' width: '+str(box.north_east.lon-box.south_west.lon)
                # print 'box: '+str(box)
                # print 'box point: '+str(p0)

                for xx in [0, 1]:
                    for i in range(0, 4):
                        for j in range(0, 4):
                            if xx == 0 and i == 0 and j == 0:
                                continue
                            bbox = geotypes.Box(
                                box.north_east.lat - (dy * j),
                                box.north_east.lon + (dx * i) + (dx * xx),
                                box.south_west.lat - (dy * j) - (dy * xx),
                                box.south_west.lon + (dx * i))
                            # bbox = geotypes.Box(  p0.lat-(dy*j)         # north
                            # , p0.lon+(dy*j)+(dy*xx) # east
                            # , p0.lat-(dx*i)-(dx*xx) # south
                            # , p0.lon+(dx*i)         # west
                            # )
                            # print '    '+cur_cell +'.'+str(xx) +str(i)+str(j)+str(bbox)
                            # print cur_cell +'.'+str(xx) +str(i)+str(j) + '|-|'+str(box)+'-'+str(bbox)

                            if is_in_box(bbox, point):
                                the_cell = cur_cell + '.' + str(xx) + str(
                                    i) + str(j)
                                primos.append(the_cell)
                                # boxes.append(bbox)

                # print 'k:'+str(k)+'  boxes:'+ str(map(lambda x:str(x),boxes))
                # boxes=[]
            # exit(0)
        south += subcell_lat_span * y
        north = south + subcell_lat_span

        west += subcell_lon_span * x
        east = west + subcell_lon_span

    if get_primos:
        return (cell, primos)

    return cell