def ring_in_order(center: h3.H3Index, k: int) -> t.Iterable[h3.H3Index]:
    """Return a hexagonal approximation of a circle.

    Give the elements of the k-ring around center in clockwise or anticlockwise
    order.

    """
    points: t.Set[h3.H3Index] = h3.k_ring_distances(center, k)[k]
    start = points.pop()
    n = start
    yield start
    while points:
        n = (h3.k_ring_distances(n, 1)[1] & points).pop()
        points.remove(n)
        yield n
def users_in_hex_plus_neighbors_list(db, hexid, contiguity=1, resolution='9'):
    """Adding neigbors of specified contiguity using h3 ring functions

    # comment> Shouldnt be necessary to specify resolution once hexid is given> check h3 documentation to obtain resoltuion on the basis of hexid
    """

    neighboring_hex_list = list(h3.k_ring_distances(hexid, ring_size=contiguity)[contiguity])

    # funcion para graficar los poligonos
    # gdf=hexlist_to_geodataframe(neighboring_hex_list)
    # gdf.plot()

    users_in_hex_plus_neighbors_list = []

    users_in_hex_list2 = users_in_hex_list(db, hexid, resolution=resolution)

    users_in_hex_plus_neighbors_list.extend(users_in_hex_list2)  # adding first those living in hex

    hexfieldname_indb = 'hex' + resolution + "." + 'hex' + resolution

    for n_hexid in neighboring_hex_list:

        users_in_n_hex_cursor = db.users.find({hexfieldname_indb: n_hexid})
        users_in_n_hex_df = pd.DataFrame(list(users_in_n_hex_cursor))

        try:
            users_in_n_hex_list = list(users_in_n_hex_df['u_id'])
        except KeyError:
            pass
        else:
            users_in_hex_plus_neighbors_list.extend(users_in_n_hex_list)
    return users_in_hex_plus_neighbors_list
Beispiel #3
0
def create_city_hexagons(lat=49.83826, lon=24.02324):
    """
    For Lviv, coordinates: 49.83826, 24.02324.
    Function, for deviding city into regions, and save coordinates for this boundaries to DF.
    Coordinates must be a city center from OpenStreetMap

    Takes:
        lat: float value of latitude
        lon: float value of longitude
    Return:
        df with coordinates

    """
    h3_address = h3.geo_to_h3(lat, lon, 8)
    hexagons = h3.k_ring_distances(h3_address, 6)
    list_address = [hex for el in hexagons for hex in el]

    latitudes1, latitudes2, latitudes3, latitudes4, latitudes5, latitudes6 = \
        list(), list(), list(), list(), list(), list()
    longitudes1, longitudes2, longitudes3, longitudes4, longitudes5, longitudes6 = \
        list(), list(), list(), list(), list(), list()
    hexagon_id = list()

    for index, element in enumerate(list_address):
        hex_boundary = h3.h3_to_geo_boundary(element)
        hexagon_id.append(index + 1)
        latitudes1.append(hex_boundary[0][0])
        longitudes1.append(hex_boundary[0][1])
        latitudes2.append(hex_boundary[1][0])
        longitudes2.append(hex_boundary[1][1])
        latitudes3.append(hex_boundary[2][0])
        longitudes3.append(hex_boundary[2][1])
        latitudes4.append(hex_boundary[3][0])
        longitudes4.append(hex_boundary[3][1])
        latitudes5.append(hex_boundary[4][0])
        longitudes5.append(hex_boundary[4][1])
        latitudes6.append(hex_boundary[5][0])
        longitudes6.append(hex_boundary[5][1])

    df_address = pd.DataFrame({
        "hexagon_id": hexagon_id,
        "latitude1": latitudes1,
        "latitude2": latitudes2,
        "latitude3": latitudes3,
        "latitude4": latitudes4,
        "latitude5": latitudes5,
        "latitude6": latitudes6,
        "longitude1": longitudes1,
        "longitude2": longitudes2,
        "longitude3": longitudes3,
        "longitude4": longitudes4,
        "longitude5": longitudes5,
        "longitude6": longitudes6
    })

    return df_address
Beispiel #4
0
    def test_k_ring_distances(self):
        hexagons = h3.k_ring_distances('8928308280fffff', 1)

        self.assertEqual(2, len(hexagons))
        self.assertEqual(1, len(hexagons[0]))
        self.assertEqual(6, len(hexagons[1]))

        self.assertTrue('8928308280fffff' in hexagons[0])
        self.assertTrue('8928308280bffff' in hexagons[1])
        self.assertTrue('89283082807ffff' in hexagons[1])
        self.assertTrue('89283082877ffff' in hexagons[1])
        self.assertTrue('89283082803ffff' in hexagons[1])
        self.assertTrue('89283082873ffff' in hexagons[1])
        self.assertTrue('8928308283bffff' in hexagons[1])

        hexagons = h3.k_ring_distances('870800003ffffff', 2)
        self.assertEqual(3, len(hexagons))
        self.assertEqual(1, len(hexagons[0]))
        self.assertEqual(6, len(hexagons[1]))
        self.assertEqual(11, len(hexagons[2]))
def run_on_one_tile(
        lon: float, lat: float,
        db: sqlalchemy.engine.Engine,
        hex: sqlalchemy.Table, t_dist: sqlalchemy.Table
) -> t.Set[ArrayIndex]:
    """Compute pairwise distances and ecoregion composition

    Given a digital elevation model as raster map and a matching ecoregions
    raster map, compute the pairwise distance to its 1-hex and 2-hex neighbors
    for every H3 address hex at standard resolution, as well as the approximate
    cover of that cell in terms of ecoregions, for all cells where that is
    possible.

    Distances are computed in gross hours of travel while navigating off-track,
    following [@irmischer2018measuring].

    Returns
    =======
    d: A mapping. d[h1][h2] is the distance, in hours, from the center of h1 to
        the center of h2.
    e: A mapping. d[h1][b] is the proportion of hex h1 covered by ecoregion b.

    """
    elevation_file = gmted_tile_from_geocoordinates(lon, lat)
    m_trafo = elevation_file.transform
    height, width = elevation_file.shape
    elevation = numpy.full((height + 1000, width + 1000), -100, int)
    ecoregions = numpy.full((height + 1000, width + 1000), 999, int)
    elevation[500:-500, 500:-500] = elevation_file.read(1)
    ecoregions[500:-500, 500:-500] = ecoregion_tile_from_geocoordinates(lon, lat).read(1)
    print("Loading adjacent data…")
    try:
        elevation[:500, :500] = (gmted_tile_from_geocoordinates(lon - 30, lat + 20)).read(1)[-500:, -500:]
        ecoregions[:500, :500] = ecoregion_tile_from_geocoordinates(lon - 30, lat + 20).read(1)[-500:, -500:]
    except rasterio.RasterioIOError:
        pass
    try:
        elevation[:500, 500:-500] = (gmted_tile_from_geocoordinates(lon, lat + 20)).read(1)[-500:, :]
        ecoregions[:500, 500:-500] = ecoregion_tile_from_geocoordinates(lon, lat + 20).read(1)[-500:, :]
    except rasterio.RasterioIOError:
        pass
    try:
        elevation[:500, -500:] = (gmted_tile_from_geocoordinates(lon + 30, lat + 20)).read(1)[-500:, :500]
        ecoregions[:500, -500:] = ecoregion_tile_from_geocoordinates(lon + 30, lat + 20).read(1)[-500:, :500]
    except rasterio.RasterioIOError:
        pass
    try:
        elevation[500:-500, :500] = (gmted_tile_from_geocoordinates(lon - 30, lat)).read(1)[:, -500:]
        ecoregions[500:-500, :500] = ecoregion_tile_from_geocoordinates(lon - 30, lat).read(1)[:, -500:]
    except rasterio.RasterioIOError:
        pass
    try:
        elevation[500:-500, -500:] = (gmted_tile_from_geocoordinates(lon + 30, lat)).read(1)[:, :500]
        ecoregions[500:-500, -500:] = ecoregion_tile_from_geocoordinates(lon + 30, lat).read(1)[:, :500]
    except rasterio.RasterioIOError:
        pass
    try:
        elevation[-500:, :500] = (gmted_tile_from_geocoordinates(lon - 30, lat - 20)).read(1)[:500, -500:]
        ecoregions[-500:, :500] = ecoregion_tile_from_geocoordinates(lon - 30, lat - 20).read(1)[:500, -500:]
    except rasterio.RasterioIOError:
        pass
    try:
        elevation[-500:, 500:-500] = (gmted_tile_from_geocoordinates(lon, lat - 20)).read(1)[:500, :]
        ecoregions[-500:, 500:-500] = ecoregion_tile_from_geocoordinates(lon, lat - 20).read(1)[:500, :]
    except rasterio.RasterioIOError:
        pass
    try:
        elevation[-500:, -500:] = (gmted_tile_from_geocoordinates(lon + 30, lat - 20)).read(1)[:500, :500]
        ecoregions[-500:, -500:] = ecoregion_tile_from_geocoordinates(lon + 30, lat - 20).read(1)[:500, :500]
    except rasterio.RasterioIOError:
        pass

    print("Computing hex extents…")
    transform = rasterio.Affine(m_trafo.a, 0, m_trafo.c - 500 * m_trafo.a,
                                0, m_trafo.e, m_trafo.f - 500 * m_trafo.e)
    def rowcol(latlon):
        lat, lon = latlon
        if lon > 170:
            # FIXME: We can and need to do this because we are working on the
            # Americas and the Americas only. The generic solution is more
            # difficult.
            lon = lon - 360
        col, row = ~transform * (lon, lat)
        return int(row), int(col)

    center: t.Dict[h3.H3Index, t.Tuple[int, int]] = {}
    cs = sqlalchemy.select([hex.c.hexbin, hex.c.vlongitude, hex.c.vlatitude]).where(hex.c.vlongitude != None)
    for h, lon, lat in db.execute(cs).fetchall():
        row, col = rowcol((lat, lon))
        if 500 <= col < width + 500 and 500 < row < height + 500:
            center[h] = (row, col)

    print("Computing terrain coefficients…")
    terrain_coefficient_raster = TC[ecoregions]

    print("Computing distances on the grid…")
    distance_by_direction = all_pairwise_distances(
        elevation, transform, terrain_coefficient_raster)

    failed: t.Set[ArrayIndex] = set()
    finished: t.Set[ArrayIndex] = set()

    for start, (row, col) in center.items():
        print(f"Computing area around {start:}…")
        lon, lat = transform * (col, row)
        hexbin = h3.geo_to_h3(lat, lon, RESOLUTION)
        this, neighbors1, neighbors2, neighbors3 = list(h3.k_ring_distances(hexbin, 3))
        neighbors: t.Set[h3.H3Index] = neighbors1 | neighbors2
        distance_known = sqlalchemy.select([t_dist.c.hexbin2]).where(
            (t_dist.c.hexbin1 == start) & (t_dist.c.source == 0))
        missing = (neighbors - {k[0] for k in db.execute(distance_known).fetchall()}) & set(center)
        if not missing:
            print("Already known.")
            finished.add(start)
            continue
        print("Not found:", missing)
        if start in failed or start in finished:
            continue

        points = []
        for n in neighbors2 | neighbors3:
            try:
                points.append(center[n])
            except KeyError:
                points.append(rowcol(h3.h3_to_geo(n)))
        rmin = min(p[0] for p in points)
        rmax = max(p[0] for p in points)
        cmin = min(p[1] for p in points)
        cmax = max(p[1] for p in points)
        assert rmin >= 0
        assert cmin >= 0

        def rel_rowcol(latlon):
            lat, lon = latlon
            if lon > 170:
                lon = lon - 360
            col, row = ~transform * (lon, lat)
            return int(row) - rmin, int(col) - cmin

        destinations = [(center[n][0] - rmin, center[n][1] - cmin)
                        for n in neighbors
                        if n in center]

        print(f"Looking for {neighbors:}…")
        distances = distances_from_focus(
            (center[start][0] - rmin, center[start][1] - cmin),
            set(destinations),
            {(n, e): d[rmin-min(n, 0):rmax + 1 - max(0, n),
                       cmin-min(e, 0):cmax + 1 - max(0, e)]
             for (n, e), d in distance_by_direction.items()},
            pred=None
        )

        # For debugging: Output the results
        distances_by_center = {}
        for t, d in center.items():
            try:
                dist = distances[d[0] - rmin, d[1] - cmin]
                if numpy.isfinite(dist):
                    distances_by_center[t] = dist
            except IndexError:
                continue

        print(distances_by_center)

        with db.begin() as conn:
            for n, d in distances_by_center.items():
                try:
                    conn.execute(t_dist.insert({
                        "hexbin1": start,
                        "hexbin2": n,
                        "distance": d,
                        "source": 0}).prefix_with('OR IGNORE'))
                except sqlalchemy.exc.IntegrityError:
                    pass
        finished.add(start)

    return failed
Beispiel #6
0
 def k_ring_distances(self, hex_id: str, ring_size: int) -> set:
     """return indices for all hexagons within the range of `ring_size` hexagon from hex_id, hexagons are grouped by the distance.
     """
     return h3.k_ring_distances(hex_id, ring_size)
Beispiel #7
0
def neighbors(hex: h3.H3Index) -> t.Set[h3.H3Index]:
    this, neighbors = h3.k_ring_distances(hex, 1)
    return neighbors