Exemple #1
0
def distance_sorted_edges(box, point):
  """Returns the edge directions of the box, sorted by distance from a point.
  
  Returns the edge directions (i.e. NORTH, SOUTH, etc.) of the box, sorted by
  distance from the given point, along with the actual distances from the point
  to these edges.

  Args:
    box: The geotypes.Box 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
    direction and distance is the distance from the point to that edge.
    Direction values will be NORTH, SOUTH, EAST, or WEST
  """
  # TODO(romannurik): Assert that lat,lon are actually inside the box.
  return zip(*sorted([
      (geocell.NORTH,
       geomath.distance(geotypes.Point(box.north, point.lon), point)),
      (geocell.SOUTH,
       geomath.distance(geotypes.Point(box.south, point.lon), point)),
      (geocell.WEST,
       geomath.distance(geotypes.Point(point.lat, box.west), point)),
      (geocell.EAST,
       geomath.distance(geotypes.Point(point.lat, box.east), point))],
      lambda x, y: cmp(x[1], y[1])))
Exemple #2
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])))
Exemple #3
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')
Exemple #4
0
    def test_distance(self):
        # known distances using GLatLng from the Maps API
        calc_dist = geomath.distance(geotypes.Point(37, -122),
                                     geotypes.Point(42, -75))
        known_dist = 4024365

        # make sure the calculated distance is within +/- 1% of known distance
        self.assertTrue(abs((calc_dist - known_dist) / known_dist) <= 0.01)
Exemple #5
0
 def test_distance_rounding(self):
   # Test location that can cause math domain error (due to rounding) unless
   # the distance function clamps the spherical law of cosines value between
   # -1.0 and 1.0. 
   calc_dist = geomath.distance(geotypes.Point(47.291288, 8.56613),
                                geotypes.Point(47.291288, 8.56613))
   known_dist = 0.0
   self.assertTrue(calc_dist == known_dist)
Exemple #6
0
    def test_Point(self):
        # an invalid point
        self.assertRaises(ValueError, geotypes.Point, 95, 0)
        self.assertRaises(ValueError, geotypes.Point, 0, 185)

        # a valid point
        point = geotypes.Point(37, -122)
        self.assertEquals(37, point.lat)
        self.assertEquals(-122, point.lon)

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

        self.assertEquals(geotypes.Point(37, -122), geotypes.Point(37, -122))
        self.assertNotEquals(geotypes.Point(37, -122), geotypes.Point(0, 0))
Exemple #7
0
    def test_adjacent(self):
        cell = geocell.compute(geotypes.Point(37, -122), 14)
        box = geocell.compute_box(cell)

        # adjacency tests using bounding boxes
        self.assertEquals(
            box.north,
            geocell.compute_box(geocell.adjacent(cell, (0, 1))).south)
        self.assertEquals(
            box.south,
            geocell.compute_box(geocell.adjacent(cell, (0, -1))).north)
        self.assertEquals(
            box.east,
            geocell.compute_box(geocell.adjacent(cell, (1, 0))).west)
        self.assertEquals(
            box.west,
            geocell.compute_box(geocell.adjacent(cell, (-1, 0))).east)

        self.assertEquals(8, len(geocell.all_adjacents(cell)))

        # also test collinearity
        self.assertTrue(
            geocell.collinear(cell, geocell.adjacent(cell, (0, 1)), True))
        self.assertFalse(
            geocell.collinear(cell, geocell.adjacent(cell, (0, 1)), False))
        self.assertTrue(
            geocell.collinear(cell, geocell.adjacent(cell, (1, 0)), False))
        self.assertFalse(
            geocell.collinear(cell, geocell.adjacent(cell, (1, 0)), True))
Exemple #8
0
    def test_compute(self):
        # a valid geocell
        cell = geocell.compute(geotypes.Point(37, -122), 14)
        self.assertEqual(14, len(cell))
        self.assertTrue(geocell.is_valid(cell))
        self.assertTrue(geocell.contains_point(cell, geotypes.Point(37, -122)))

        # a lower resolution cell should be a prefix to a higher resolution
        # cell containing the same point
        lowres_cell = geocell.compute(geotypes.Point(37, -122), 8)
        self.assertTrue(cell.startswith(lowres_cell))
        self.assertTrue(
            geocell.contains_point(lowres_cell, geotypes.Point(37, -122)))

        # an invalid geocell
        cell = geocell.compute(geotypes.Point(0, 0), 0)
        self.assertEqual(0, len(cell))
        self.assertFalse(geocell.is_valid(cell))
Exemple #9
0
def mid_point(p1, p2):
    p1lat, p1lon = math.radians(p1.lat), math.radians(p1.lon)
    p2lat, p2lon = math.radians(p2.lat), math.radians(p2.lon)
    delta_lon = p2lon - p1lon
    bx = math.cos(p2lat) * math.cos(delta_lon)
    by = math.cos(p2lat) * math.sin(delta_lon)

    p3lat = math.atan2(
        math.sin(p1lat) + math.sin(p2lat),
        math.sqrt((math.cos(p1lat) + bx) * (math.cos(p1lat) + bx) + by * by))
    p3lon = p1lon + math.atan2(by,
                               math.cos(p1lat) + bx)
    return geotypes.Point(math.degrees(p3lat), math.degrees(p3lon))
Exemple #10
0
    def test_interpolation(self):
        cell = geocell.compute(geotypes.Point(37, -122), 14)
        sw_adjacent = geocell.adjacent(cell, (-1, -1))
        sw_adjacent2 = geocell.adjacent(sw_adjacent, (-1, -1))

        # interpolate between a cell and south-west adjacent, should return
        # 4 total cells
        self.assertEquals(4, len(geocell.interpolate(cell, sw_adjacent)))
        self.assertEquals(4, geocell.interpolation_count(cell, sw_adjacent))

        # interpolate between a cell and the cell SW-adjacent twice over,
        # should return 9 total cells
        self.assertEquals(9, len(geocell.interpolate(cell, sw_adjacent2)))
        self.assertEquals(9, geocell.interpolation_count(cell, sw_adjacent2))
Exemple #11
0
    def test_compute_box(self):
        cell = geocell.compute(geotypes.Point(37, -122), 14)
        box = geocell.compute_box(cell)

        self.assertTrue(box.south <= 37 and 37 <= box.north
                        and box.west <= -122 and -122 <= box.east)
Exemple #12
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
Exemple #13
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