def crawl_panos_by_area(bbox=None, geom=None, verbose=True, plot=True):
    if bbox is not None:
        geom = box(*bbox)
    assert geom is not None, "Check Input"
    
    pano_dict, visited = {}, set()
    queue = deque(get_unvisited_point(gpd.GeoDataFrame(), geom_wkt=geom.wkt, plot=False))

    while queue:
        node = queue.popleft()
        if node in visited:
            continue
        
        pid = query_pano_by_api(*node, memo=pano_dict)['pid']
        origin_size = len(pano_dict)
        bfs_panos(pid, geom=geom, memo=pano_dict)
        visited.add(node)
        
        if len(pano_dict) == origin_size:
            continue
        
        # TODO: 每次循环计算一次过于费劲,可适当减少节点的数量或者其他策略
        lst = get_unvisited_point(pano_dict_to_gdf(pano_dict), geom_wkt=geom.wkt, plot=False)
        queue = deque([i for i in lst if i not in visited])
        
        if verbose:
            print(len(queue), len(pano_dict))

    if plot:
        gdf_panos = pano_dict_to_gdf(pano_dict)
        gdf_roads = extract_gdf_roads_from_key_pano(gdf_panos)
        map_visualize(gdf_roads)
    
    return pano_dict
Exemple #2
0
def sort_pids_in_edge(edge_to_pid, gdf_panos, net, plot=False, filter=True):
    # TODO 针对有多个匹配方案的,选择距离最近的一个
    df_mapping = pd.DataFrame(edge_to_pid).stack()\
                                        .reset_index()\
                                        .rename(columns={'level_0': 'rid', 'level_1': 'eid', 0: 'pid'})\
                                        [['eid','rid', 'pid']]\
                                        .explode('pid')\
                                        .reset_index(drop=True)

    df_mapping = df_mapping.merge(gdf_panos[['MoveDir', 'lane_num']],
                                  left_on='pid',
                                  right_index=True)
    df_mapping.loc[:,
                   'offset'] = df_mapping.apply(lambda x: cal_relative_offset(
                       gdf_panos.loc[x.pid].geometry, net.df_edges.loc[x.eid].
                       geom_origin)[0] / net.df_edges.loc[x.eid].dist,
                                                axis=1)
    df_mapping.sort_values(['eid', 'offset'], inplace=True)

    if plot:
        map_visualize(gdf_panos.loc[df_mapping.pid])

    if filter:
        df_mapping = pids_filter(df_mapping)

    return df_mapping
Exemple #3
0
    def get_unvisited_edge(self, edges, plot=True):
        # TODO
        mathing_ = self.cal_coverage_helper(edges, format='dataframe')
        edges_ = edges.merge(mathing_, on=['eid'], how='left')
        edges_.visited = edges_.visited.fillna(False)

        if plot:
            map_visualize(edges_[~edges_.visited])

        return edges_[~edges_.visited]
def plot_pano_and_its_view(pid, DB_panos, DB_roads, road=None, heading=None):
    """绘制pano位置图,包括所在的路段,位置以及视角

    Args:
        pid ([type]): Pano id
        DB_panos ([type]): Panos DB.
        DB_roads ([type]): Roads DB.
        road ([type], optional): The whole road need to plot in the figure. Defaults to None.
        heading ([type], optional): The view heading. Defaults to None.

    Returns:
        [Image]: Image with the predicted info.
    """

    rid = DB_panos.query(f"PID=='{pid}' ").RID.iloc[0]
    pid_record = query_df(DB_panos, "RID", rid).query(f"PID == '{pid}'")
    assert (len(pid_record) > 0)
    pid_record = pid_record.iloc[0]

    if heading is None:
        heading = pid_record.DIR
    x, y = pid_record.geometry.coords[0]

    if road is None:
        fig, ax = map_visualize(DB_roads.query(f"RID == '{pid_record.RID}' "),
                                label="Lane")
    else:
        fig, ax = map_visualize(
            DB_roads.query(f"RID == '{pid_record.RID}' ").append(road),
            color='blue',
            linestyle='--')
        road.plot(ax=ax, label="Road", color='red')
        # fig, ax = map_visualize( road, label="Road" )

    x0, x1 = ax.get_xlim()
    aus_line_len = (x1 - x0) / 20
    dy, dx = math.cos(heading / 180 * math.pi) * aus_line_len, math.sin(
        heading / 180 * math.pi) * aus_line_len

    ax.annotate('',
                xy=(x + dx, y + dy),
                xytext=(x, y),
                arrowprops=dict(facecolor='blue', shrink=0.05, alpha=0.5))
    gpd.GeoSeries([Point(x, y)]).plot(ax=ax,
                                      label='Pano',
                                      marker='*',
                                      markersize=360)

    plt.axis('off')
    plt.legend()
    plt.tight_layout()
    plt.close()

    return fig
Exemple #5
0
    def plot_edge(self, rid):
        tmp = self.edge.query( f"rid == {rid}" )['shape']
        tmp = tmp[~tmp.isna()]
        road_shape = tmp.apply( lambda x:  LineString( np.array( [ coord.split(',') for coord in  x.split(" ")]).astype(np.float) ))
        if road_shape.shape[0] == 0:
            return False
        
        road_shape = gpd.GeoDataFrame(geometry = road_shape, crs = OSM_CRS).to_crs(epsg= 4326)
        map_visualize(road_shape)
        

        return True
 def get_panos(self, rid, plot=False):
     rids = self.get_traj(rid, False)
     if rids is None:
         return None
     
     lst = []
     for sub in self.gdf_roads.loc[rids].Panos.apply(lambda x: [i['PID'] for i in x]).tolist():
         lst += sub
     
     if plot and self.gdf_panos is not None:
         map_visualize(self.gdf_panos.loc[lst])
     
     return self.gdf_panos.loc[lst].reset_index()
Exemple #7
0
def get_pano_ids_by_rid(rid, DB_panos, vis=False):
    """Get panos ids in a road segement by its name.

    Args:
        rid (str): road id
        DB_panos ([type]): [description]
        vis (bool, optional): [description]. Defaults to False.

    Returns:
        [type]: [description]
    """
    tmp = DB_panos.query(f" RID == '{rid}' ")
    if vis: map_visualize(tmp)

    return tmp
def bidirection_bfs(pid, df_topo, df_topo_prev, visited=set(), similar_threds=.7, plot=False, logger=None):
    """[summary]

    Args:
        pid ([type]): [description]
        df_topo ([type]): [description]
        df_topo_prev ([type]): [description]
        visited_filter (bool, optional): Filter the visited roads. Defaults to True.
        plot (bool, optional): [description]. Defaults to True.
        satellite (bool, optional): [description]. Defaults to True.

    Returns:
        [type]: [description]
    """
    if pid not in df_topo.index and pid not in df_topo_prev.index:
        if logger is not None:
            logger.warning(f"{pid} not in df_topo")
        return []

    params = {'visited':visited, "plot":False, 'logger':logger, 'similar_threds':similar_threds}
    rids_0 = bfs(pid, df_topo_prev, False, **params)
    rids_1 = bfs(pid, df_topo, True, **params)
    rids = rids_0[::-1] + rids_1
   
    if rids and plot:
        roads = gdf_roads.loc[rids]
        roads.loc[:, 'order'] = range(roads.shape[0])
        fig, ax = map_visualize(roads, color='black')
        roads.plot(column='order', legend=True, ax=ax, linewidth=3)
    
    return rids
def _get_revert_df_edges(road_id, df_edges, vis=False):
    """create the revert direction edge of rid in OSM file

    Args:
        road_id ([type]): the id of road
        df_edges ([type]): gdf create by 
        vis (bool, optional): plot the process or not. Defaults to False.

    Returns:
        [gdf]: the geodataframe of revert edge
    """
    road_id = road_id if road_id > 0 else -road_id
    df_tmp = df_edges.query(f"rid == {road_id} ")

    df_tmp.rid = -df_tmp.rid
    df_tmp.loc[:, ['s','e']] = df_tmp.loc[:, ['e','s']].values
    df_tmp.loc[:, 'index'] = df_tmp['index'].max() - df_tmp.loc[:, 'index']
    df_tmp.loc[:, 'geometry'] = df_tmp.geometry.apply( lambda x: LineString(x.coords[::-1]) )
    df_tmp.loc[:, 'pids'] = df_tmp.pids.apply( lambda x: ";".join( x.split(';')[::-1] ) )
    df_tmp.sort_values(by='index', inplace=True)
    # gpd.GeoDataFrame(pd.concat( [df_edges.query(f"rid == {road_id} "), df_tmp] )).to_file('./test.geojson', driver="GeoJSON")

    if vis:
        from road_matching import get_panos_of_road_and_indentify_lane_type_by_id
        matching0 = get_panos_of_road_and_indentify_lane_type_by_id(-road_id, df_tmp, False)
        matching1 = get_panos_of_road_and_indentify_lane_type_by_id(road_id, df_edges, False)
        _, ax = map_visualize(matching0, scale =0.001)
        matching1.plot(column='level_0', legend=True, ax=ax, cmap='jet')
        matching0.plot(column='level_0', legend=True, ax=ax, cmap='jet')

    return df_tmp
Exemple #10
0
    def _plot_neighbor_rids_of_edge(self,
                                    eid,
                                    df_edges_unvisted,
                                    dis_buffer=25):
        """Plot the neighbor rids of the eid.

        Args:
            eid ([type]): [description]
            df_edges_unvisted ([type]): [description]
        """
        road_mask = gpd.GeoDataFrame({
            'eid':
            eid,
            'geometry':
            df_edges_unvisted.query(f'eid=={eid}').buffer(dis_buffer *
                                                          DIS_FACTOR)
        })
        tmp = gpd.sjoin(self.gdf_roads, road_mask, op='intersects')
        tmp.reset_index(inplace=True)

        fig, ax = map_visualize(tmp)
        tmp.plot(column='ID', ax=ax, legend=True)
        df_edges_unvisted.query(f'eid=={eid}').plot(ax=ax,
                                                    color='blue',
                                                    linestyle='--')

        return
def combine_rids(gdf_base, gdf_roads, gdf_panos, plot=True, logger=None):
    """Combining rids based on the amuzith similarity.

    Args:
        plot (bool, optional): [description]. Defaults to True.

    Returns:
        [type]: [description]
    """
    neg_dir_rids = set(gdf_panos[gdf_panos['revert']].RID.unique())
    df_topo, df_topo_prev = get_topo_from_gdf_pano(gdf_base, neg_dir_rids)

    res            = {}
    rid_2_start    = {}
    uf             = Pano_UnionFind(gdf_roads.index.tolist(), gdf_roads, gdf_panos)
    queue          = deque(gdf_roads.query('src != dst').index.tolist())  # 起点和终点都是一样的路段不适宜作为遍历的起始点
    visited        = set() # {(src, dst)}
    dulplicate_src = []
    
    while queue:
        cur = gdf_roads.loc[queue.popleft()]
        cur_pid = cur['src']

        if (cur_pid, cur['dst']) in visited:
            if logger is not None:
                logger.debug(f"skip {cur.name}")
            continue
        
        rids = bidirection_bfs(cur_pid, df_topo, df_topo_prev, visited, 0.7, False, logger)
        if not rids:
            continue

        for i in rids:
            if i in rid_2_start:
                if logger is not None:
                    logger.warning(f"{i} exist in rid_2_start")
            rid_2_start[i] = rid_2_start.get(i, set())
            rid_2_start[i].add(rids[0])
        
        if rids[0] not in res:
            res[rids[0]] = [rids]
        else:
            res[rids[0]].append(rids)
            dulplicate_src.append(rids[0])
            print(f"dulplicate: {rids[0]}")

        uf.connect_traj(rids)

        if logger is not None:
            logger.debug(f"visited {cur_pid}/{cur.name}, links: {rids}")

    if plot:
        fig, ax = map_visualize(gdf_roads, scale=.05)
        gdf_roads.merge(pd.DataFrame(visited, columns=['src', 'dst']), on=['src', 'dst']).plot(ax=ax)

    assert len(dulplicate_src) == 0, "check the logic of combine_rids to process"

    # return uf, res, rid_2_start
    return uf, df_topo, df_topo_prev
def create_crawl_point(road_one_way: gpd.GeoDataFrame,
                       geometry_type='point',
                       visualize=False):
    """Extract all the points of the road and arrange them according to the spatial position

    Args:
        road_one_way (gpd.GeoDataFrame): Road with one-way or the one side
        visualize (bool, optional): [description]. Defaults to False.

    Returns:
        [gpd.GeoDataFrame]: Road points in order
    """

    df_order_coords = []
    coords_lst = road_one_way.geometry.apply(lambda x: np.vstack(x.xy).T)
    for index, i in enumerate(coords_lst):
        for j in i:
            df_order_coords.append(j)

    df_order_coords = pd.DataFrame(df_order_coords, columns=['x', 'y'])

    df_order_coords.loc[:, 'dis'] = calculate_adj_points_dis(df_order_coords,
                                                             inplace=True)
    df_order_coords.query('dis > 0 ', inplace=True)
    df_order_coords['dis_cum'] = df_order_coords.dis.rolling(
        df_order_coords.shape[0], min_periods=1).sum()

    if geometry_type == 'point':
        geometry = df_order_coords.apply(lambda i: Point(i.x, i.y), axis=1)
    else:
        geometry = df_order_coords.apply(lambda x: LineString([(x.x, x.y),
                                                               (x.x1, x.y1)]),
                                         axis=1)
    df_order_coords = gpd.GeoDataFrame(df_order_coords, geometry=geometry)

    df_order_coords.reset_index(drop=True, inplace=True)
    df_order_coords.loc[:, 'id'] = df_order_coords.index
    # TODO coords values: start or end port
    df_order_coords.loc[:, 'coords'] = df_order_coords.apply(
        lambda x: bd_coord_to_mc(*ct.wgs84_to_bd09(x.x1, x.y1)), axis=1)

    if visualize:
        map_visualize(df_order_coords)

    # df_order_coords.to_file('./光侨路_南行_节点.geojson', driver="GeoJSON")
    return df_order_coords
def get_unvisited_point(panos, bbox=None, geom_wkt=None, buffer_dis=15, plot=True):
    osm_nodes = load_postgis('topo_osm_shenzhen_node', bbox=bbox, geom_wkt=geom_wkt)

    if panos is None or panos.shape[0]==0:
        return [ (i[0], i[1]) for i in  osm_nodes[['x','y']].values.tolist()]

    osm_nodes.loc[:, 'area'] = osm_nodes.to_crs(epsg=900913).buffer(buffer_dis).to_crs(epsg=4326)
    osm_nodes.reset_index(inplace=True)
    osm_nodes.set_geometry('area', inplace=True)

    visited = gpd.sjoin(left_df=osm_nodes, right_df=panos, op='contains')['index'].unique().tolist()
    res = osm_nodes.query( f"index not in {visited} " )
    
    if plot:
        map_visualize(res)

    return [ (i[0], i[1]) for i in  res[['x','y']].values.tolist()]
def query_pano_detail_by_coord(x, y, visualize=False):
    """
    query the nearby point by a special coordination
    @param: x,y
    @return: 
    """
    # x, y = bd_coord_to_mc(x, y)
    # # TODO memo
    # if memo.query( f"crawl_coord == {str(x)+','+str(y)}"):
    #     return memo.query( f"crawl_coord == {str(x)+','+str(y)}")[0]
    info = query_pano_ID_by_coord(x, y)

    if 'pano_id' in info:
        info, df = query_pano_detail(info)
        if visualize:
            map_visualize(df, 'y')
        return info, df, True
    return info, None, False
Exemple #15
0
    def _crawl_by_area(self, plot=True, queue_filter=True):
        start_time = time.time()
        queue = deque(self._get_unvisited_point())

        while queue:
            node = queue.popleft()
            ori_size = len(self.pano_dict)
            print(
                f"pano nums: {len(self.pano_dict)}, queue length: {len(queue)}, cur node: {node}"
            )

            res = query_pano(*node)
            if res is None:
                continue

            pid = res['pid']
            if self.dummy_pano is None:
                self.dummy_pano = pid
            self._bfs(pid, memo=self.pano_dict, max_layer=100)
            self.coord_2_pid[node[:2]] = pid
            if len(self.pano_dict) == ori_size:
                continue

            self.gdf_pano_node = self.pano_dict_to_gdf(self.pano_dict)
            self.gdf_pano_link = self.extract_gdf_roads_from_key_pano(
                self.gdf_pano_node)
            lst = self._get_unvisited_point(self.gdf_pano_link)
            # FIXME
            lst = [i for i in lst if i not in self.coord_2_pid]

            if queue_filter:
                lst = self._crawl_queue_filter(lst=lst,
                                               visited=self.coord_2_pid)
                queue_filter = False

            queue = deque(lst)

        end_time = time.time()
        logger.info(f"time cost: {end_time-start_time:.1f} s")

        if plot:
            map_visualize(self.gdf_pano_link)

        return
def bfs(node, df_topo, direction=True, visited=set(), plot=False, similar_threds=.7, logger=None):
    if node not in df_topo.index:
        return []
    
    queue, res = deque([node]), []
    internal_visited = set() # Avoid going backwards
    while queue:
        cur_pid = queue.popleft()
        if cur_pid not in df_topo.index:
            continue

        if logger is not None:
            info = df_topo.loc[cur_pid][['link','cos_sim', 'dist_prob_std','similarity']].reset_index()
            logger.debug(f"{cur_pid}, {'forword' if direction else 'backward'}:\n {info}")
        
        for nxt_pid, nxt in df_topo.loc[cur_pid].iterrows():
            connector = (cur_pid, nxt_pid) if direction else (nxt_pid, cur_pid)
            connector_revert = connector[::-1]
            if logger is not None:
                logger.debug(f"\t\tlink: {connector}, visited: {connector in visited}")
            
            if nxt['similarity'] < similar_threds or connector in visited or connector in internal_visited:
                continue
            
            if nxt['compressed_rid'] is not np.nan and nxt['compressed_rid'] not in res:
                if (nxt['compressed_rid'], nxt['compressed_rid']) not in visited:
                    res.append(nxt['compressed_rid'])
                    visited.add((nxt['compressed_rid'], nxt['compressed_rid']))
            if not nxt['link']:
                res.append(nxt['rid'])
            
            queue.append(nxt_pid)
            visited.add(connector)
            internal_visited.add(connector_revert)

            break
    
    if plot and len(res) > 0:
        map_visualize( gdf_roads.loc[res] )
    
    return res
def get_pano_imgs_of_road_by_name(road_name, df_edges=df_edges):
    """通过 道路名 查询,然后抓取panos

    Args:
        road_name ([type]): [description]
        df_edges ([gpd.GeoDataFrame], optional): [description]. Defaults to df_edges.
    """

    roads = df_edges.query(f"name == '{road_name}' ")
    map_visualize(roads)
    network = Digraph(edges=roads[['s', 'e']].values)

    result = network.combine_edges(roads)
    visited = set([])

    for _, road_ids in result:
        print(road_ids)
        visited = crawl_pano_imgs_by_roadid_batch(road_ids, df_edges,
                                                  road_name, visited)

    return
def get_panos_imgs_by_bbox(bbox=[113.92348,22.57034, 113.94372,22.5855], vis=True, with_folder=False):
    """给定一个区域,获取所有的panos

    Args:
        bbox (list, optional): [description]. Defaults to [113.92348,22.57034, 113.94372,22.5855].
        vis (bool, optional): [description]. Defaults to True.
        with_folder (bool, optional): [description]. Defaults to False.

    Returns:
        [type]: [description]
    """
    res = []
    features = get_features('line', bbox=bbox)
    if vis: map_visualize(features)

    for rid in tqdm(features.RID.unique(), desc='get_panos_imgs_by_bbox'):
        info, _ = traverse_panos_by_rid(rid, DB_panos, log=pano_API_log, all=False)
        res += info
    print( 'total number of pano imgs: ', len(res))
    
    if not with_folder:
        res = [ i.split('/')[-1] for  i in res]
    
    return res
def get_area_and_start_point():
    #! load crawl area
    area = gpd.read_file('../input/area_test.geojson')
    df_roads = gpd.read_file("../input/深圳市_osm路网_道路.geojson")
    df_nodes = gpd.read_file("../input/深圳市_osm路网_节点.geojson")

    roads = gpd.overlay(df_roads, area, how="intersection")
    nodes = gpd.overlay(df_nodes, area, how="intersection")

    if False:
        ax = map_visualize(roads, color='red', scale=0.1)
        nodes.plot(ax=ax, )
        ax.axis('off')

        ax = map_visualize(roads.set_geometry('start'), color='red', scale=0.1)
        ax.axis('off')

    roads.loc[:, 'start'] = roads.geometry.apply(
        lambda i: Point(i.xy[0][0], i.xy[1][0]))
    roads.loc[:, 'end'] = roads.geometry.apply(
        lambda i: Point(i.xy[0][-1], i.xy[1][-1]))
    roads.loc[:, 'start_bd_mc'] = roads.start.apply(
        lambda i: wgs_to_bd_mc(*i.coords[0]))
    return roads.start_bd_mc.values.tolist(), area.loc[0].geometry
    def get_traj(self, rid=None, pid=None, plot=False):
        assert rid is not None or pid is not None, 'check input'
        if rid is None:
            rid = self.gdf_panos.loc[pid].RID
        
        root = self.find(rid)
        if root not in self.trajs:
            return None

        if plot and self.gdf_roads is not None:
            roads = self.gdf_roads.loc[self.trajs[root]]
            roads.loc[:, 'order'] = range(roads.shape[0])
            fig, ax = map_visualize(roads, color='black')
            roads.plot(column='order', legend=True, ax=ax, linewidth=3)
        
        return self.trajs[root]
Exemple #21
0
    def plot_matching(self, rid, *args, **kwargs):
        """plot the matching panos and show its lanenum in a color theme map

        Args:
            rid ([type]): [description]

        Returns:
            [type]: [description]
        """
        df = self.save_rid_matching_df_to_file(rid)
        if df is None:
            print(
                f"plot rid matching error, for the geodataframe {rid} is None")

        df.loc[:, 'lane_num'] = df.loc[:, 'lane_num'].astype(str)
        _, ax = map_visualize(df, color='gray', scale=0.05, *args, **kwargs)
        df.plot(column='lane_num', ax=ax, legend=True)

        return df
Exemple #22
0
    def _get_unvisited_point(self,
                             gdf_roads: gpd.GeoDataFrame = None,
                             plot=False):
        if gdf_roads is None or gdf_roads.shape[0] == 0:
            return [(i[0], i[1])
                    for i in self.osm_node[['x', 'y']].values.tolist()]

        visited = set(
            gpd.sjoin(left_df=self.osm_node.query('not visited'),
                      right_df=gdf_roads,
                      op='intersects')['nid'].unique())
        self.osm_node.loc[:, 'visited'] = self.osm_node.apply(
            lambda x: x['visited'] or x['nid'] in visited, axis=1)
        res = self.osm_node.query('not visited')

        if plot:
            ax = map_visualize(res, color='red')

        return [(i[0], i[1]) for i in res[['x', 'y']].values.tolist()]
def pred_trajectory(gdf,
                    df_memo,
                    img_resize_factor=.5,
                    aerial_view=True,
                    combine_view=False,
                    with_lanes=True):
    # 预测轨迹节点,并生成鸟瞰图、移动拼接图
    res = {}
    res['gdf'] = gdf.merge(df_memo[['PID', 'DIR', 'lane_num', 'name', 'pred']],
                           on=['PID', 'DIR'])
    fn_lst = res['gdf'].apply(
        lambda x: os.path.join(PANO_FOLFER, f"{x['name']}"),
        axis=1).values.tolist()

    if combine_view:
        # TODO: add position; add debug info
        if with_lanes:
            img_lst = [
                draw_pred_lanes_on_img(lane_shape_predict(fn, df_memo),
                                       out_path=None) for fn in fn_lst
                if os.path.exists(fn)
            ]
        else:
            img_lst = [Image.open(fn) for fn in fn_lst if os.path.exists(fn)]

        print(img_lst)
        comb_img = combine_imgs(img_lst)

        x, y = comb_img.size
        comb_img = comb_img.resize(
            (int(img_resize_factor * x), int(img_resize_factor * y)))

        res['combine_view'] = comb_img

    if aerial_view:
        fig, ax = map_visualize(res['gdf'], color='gray')
        gdf_plot = res['gdf'].query('lane_num >= 2')
        gdf_plot.loc[:, 'lane_num'] = gdf_plot.loc[:, 'lane_num'].astype('str')
        gdf_plot.plot(column='lane_num', legend=True, categorical=False, ax=ax)
        res['aerial_view'] = fig
        plt.close()

    return res
def plot_node_connections(node, df_topo, *args, **kwargs):
    """plot node and it's connections

    Args:
        node (str): The node index

    Returns:
        [type]: [description]
    """
    adj_nodes = df_topo.loc[node]
    
    pids = adj_nodes.index.tolist()
    
    fig, ax = map_visualize( gdf_panos.loc[ pids+[node]], color='gray', *args, **kwargs )
    adj_nodes = gdf_panos.merge(adj_nodes, left_index=True, right_index=True).reset_index(drop=False)
    adj_nodes.loc[:, 'info'] = adj_nodes.apply(lambda x: f"{x['index']}, {x.similarity:.3f}",axis=1)
    adj_nodes.sort_values(by='similarity', ascending=False).plot(ax=ax, column='info', legend=True, )
    # adj_nodes.plot(ax=ax, column='similarity', legend=True)
    
    gdf_panos.loc[[node]].plot(ax=ax, marker='*', color='green', markersize=50)
    
    return adj_nodes    
def get_panos_of_road_and_indentify_lane_type_by_id(road_id,
                                                    df_edges,
                                                    vis=False,
                                                    save=False,
                                                    len_thres=50,
                                                    verbose=False):
    """在get_panos_of_road_by_id的基础上,针对匹配的panos进行分析;
    1. group_panos_by_road 获取基础的pano
    1. 获取links -> 构建grap; 
    1. LongestPath 获取最长的路径,但`这个不太科学`, # FIXME

    Args:
        road_id ([type]): [description]
        df_edges ([type]): [description]
        vis (bool, optional): [description]. Defaults to False.
        save (bool, optional): [description]. Defaults to False.
        len_thres (int, optional): [description]. Defaults to 50.

    Returns:
        mathcing panos: The matching panos in geodataframe
    """

    if verbose:
        print("\tget_panos_of_road_and_indentify_lane_type_by_id: ", road_id)
    matching = get_panos_of_road_by_id(road_id, df_edges, vis, save)
    if matching is None: return None

    connecters = DB_connectors.copy()
    att_lst = ['PID_start', 'PID_end', 'length']
    a = _get_links_by_pids(matching.PID_end.values.tolist(), connecters)
    b = DB_roads.query(
        f"PID_start in {a.PID_end.values.tolist()} and PID_start == PID_end"
    )[att_lst] if a is not None else None
    c = _get_links_by_pids(b.PID_end.values.tolist(),
                           connecters) if b is not None else None
    d = matching[att_lst]

    edges = pd.concat([a, c, d]).fillna(False)
    edges.reset_index(drop=True, inplace=True)
    edges.rename(columns={
        'PID_start': 'start',
        'PID_end': 'end'
    },
                 inplace=True)

    # obtain and sort origins
    origins = _get_road_origin_points(edges)
    origins = matching.query(f"PID_start in {origins}").PID_start.values

    main_road = []
    for origin in origins:
        sol = LongestPath(edges, origin)
        # ? 猜测 双向
        path = [ (sol.path[i+1], sol.path[i]) for i in range( len(sol.path)-1)] \
             + [ (sol.path[i], sol.path[i+1]) for i in range( len(sol.path)-1)]

        # TODO threding惯性
        if sol.length > len_thres:
            path = pd.DataFrame(path, columns=['start', 'end'])
            main_road.append(path)

            visited = path.apply(lambda x: x.start + ";" + x.end,
                                 axis=1).values.tolist()
            con = edges.apply(lambda x: x.start + ";" + x.end in visited,
                              axis=1)
            edges = edges[~con]

            if not vis: continue
            map_visualize(
                DB_roads.merge(path,
                               left_on=['PID_start', 'PID_end'],
                               right_on=['start', 'end']))

    if len(main_road) == 0: return None

    main_road = pd.concat(main_road)
    visited = main_road.apply(lambda x: x.start + ";" + x.end,
                              axis=1).values.tolist()
    con = matching.apply(lambda x: x.PID_start + ";" + x.PID_end in visited,
                         axis=1)

    matching.loc[~con, 'link'], matching.loc[con, 'link'] = 1, 0
    matching.loc[:, 'link'] = matching.loc[:, 'link'].astype(np.int)

    return matching.reset_index()
Exemple #26
0
    def get_pids_by_rid(self, rid, sumo_net, verbose=False, geo_plot=False):
        """get pids of a special road in a sumo net file

        Args:
            rid (int): the id of the road in the sumo net file
            sumo_net (Sumo_Net): the class of sumo net

        Returns:
            [lst]: the pids in order
        """
        assert isinstance(rid, int), f"Check the rid {rid} is availabel"
        if rid in self.pids_memo:
            return self.pids_memo[rid]
        # rid = 107586308, 存在和 `220885829`合并的情况; # 220885830 AddedRampe连续的情况
        pids = self.key_to_edge[rid]['points'] if rid > 0 else self.key_to_edge[-rid]['points'][::-1]
        # pids = osm_net.key_to_edge[rid]['points'] if rid > 0 else osm_net.key_to_edge[-rid]['points'][::-1]
        road_sumo = sumo_net.get_edge_df_by_rid(rid)
        
        if self.logger and verbose:
            attrs_show = ['id', 'from', 'to', 'numLanes', 'order']
            self.logger.info(road_sumo[attrs_show])
        
        if road_sumo.id.str.contains('Add').sum() == 0: 
            self.pids_memo[rid] = pids
            return pids

        insert_pids = {}
        for node1, node2 in road_sumo[['from', 'to']].values:
            node1 = int(node1) if node1.isdigit() else node1
            node2 = int(node2) if node2.isdigit() else node2

            if node1 not in pids:
                if node1 not in insert_pids:
                    insert_pids[node1] = {}
                insert_pids[node1]['next'] = node2
            
            if node2 not in pids:
                if node2 not in insert_pids:
                    insert_pids[node2] = {}
                insert_pids[node2]['prev'] = node1

        queue = deque( [(key, 
                         val['prev'] if 'prev' in val else '0', 
                         val['next'] if 'next' in val else '-1'
                         ) for key, val in insert_pids.items()] 
                      )

        while queue:
            node, prev, nxt = queue.popleft()
            prev = int(prev) if isinstance(prev, str) and prev.isdigit() else prev
            if nxt == '-1':
                nxt = pids[-1]
            else:
                nxt = int(nxt) if isinstance(nxt, str) and nxt.isdigit() else nxt

            prev_index = pids.index(prev) if prev in pids else 0
            nxt_index  = pids.index(nxt)  if nxt  in pids else len(pids) - 1

            for idx in range(prev_index, nxt_index):
                # print(f"intervals [{prev_index}, {nxt_index}], pids len {len(pids)}")
                flag = relation_bet_point_and_line(self.get_node_coords(node), 
                                                   self.get_node_coords(pids[idx]) + self.get_node_coords(pids[idx+1]))
                if 0 <= flag <= 1:
                    break
            
            if flag <= 1:
                pids.insert(idx+1, node)
            else:
                pids += [node]

        if geo_plot:
            lst = pids
            gdf_nodes = gpd.GeoDataFrame(geometry=[self.key_to_node[node]['geometry'] for node in lst])
            gdf_nodes.reset_index(inplace=True)

            fig, ax = map_visualize(gdf_nodes)
            gdf_nodes.plot( column='index', legend=True, ax=ax )
        
        self.pids_memo[rid] = pids
        
        return pids
def _matching_panos_path_to_network(road,
                                    DB_roads=DB_roads,
                                    vis=True,
                                    vis_step=False,
                                    save_fig=True,
                                    buffer_thres=0.00005,
                                    angel_thres=30):
    """Find the matching path of panos for a special road based on the frechet distance

    Args:
        road ([type]): [description]
        DB_roads ([type], optional): [description]. Defaults to DB_roads.
        vis (bool, optional): [description]. Defaults to True.
        vis_step (bool, optional): [description]. Defaults to False.
        save_fig (bool, optional): [description]. Defaults to True.
        buffer_thres (float, optional): [description]. Defaults to 0.00005.
        angel_thres (int, optional): [description]. Defaults to 30.

    Returns:
        [road_candidates: dataframe]: [description]
        [rid]: matching rid of osm road
    """
    # road = road_osm.iloc[0]; vis=True; vis_step=True; buffer_thres = 0.00005; angel_thres = 30; save_fig=True

    road_candidates = DB_roads[DB_roads.intersects(
        road.geometry.buffer(buffer_thres))].query('length > 0')
    if road_candidates.shape[0] <= 0:
        return None, None

    res_dis, res_ang = [], []
    for index, item in road_candidates.iterrows():
        if item.length == 0:
            res_dis.append(np.inf)
            res_ang.append(90)
            continue

        # 若是两条线几乎垂直,可以考虑忽略了
        angel = angle_bet_two_linestring_ignore_inte_point(item, road)
        res_ang.append(angel)

        if 90 - angel_thres < angel < 90 + angel_thres:
            res_dis.append(float('inf'))
        else:
            l0, l1 = cut_and_align(item.geometry, road.geometry)
            l0, l1 = line_interplation(l0), line_interplation(l1)
            dis, dp = frechet_distance_bet_polyline(l0, l1)
            res_dis.append(dis * 110 * 1000)

            if not vis_step:
                continue

            fig, ax = map_visualize(gpd.GeoSeries([road.geometry]),
                                    color='black',
                                    label='OSM road')
            gpd.GeoSeries([item.geometry]).plot(color='gray',
                                                label='Pano path',
                                                ax=ax)
            for line in [l0, l1]:
                gpd.GeoSeries([Point(x) for x in line.coords[:]]).plot(ax=ax)
            plt.title(f"frechet dis: {dis*110*1000:.2f}")
            plt.legend()

    # 汇总统计结果
    road_candidates.loc[:, 'angel'] = res_ang
    road_candidates.loc[:, 'frechet_dis'] = res_dis
    road_candidates.loc[:, 'osm_road_id'] = road.rid
    road_candidates.loc[:, 'osm_road_index'] = road.name
    road_candidates.loc[:, 'related_pos'] = road_candidates.geometry.apply(
        lambda x: get_related_position(x, road.geometry))
    road_candidates.sort_values(by='related_pos', inplace=True)

    for att in ["osm_road_index", "osm_road_id"]:
        road_candidates.loc[:, att] = road_candidates.loc[:,
                                                          att].astype(np.int)

    rid = road_candidates.loc[road_candidates.frechet_dis.idxmin()].RID

    if vis:
        fig, ax = map_visualize(road_candidates,
                                color='black',
                                label='Pano paths',
                                linestyle=':')
        for index, item in road_candidates.iterrows():
            ax.text(
                *item.geometry.centroid.coords[0],
                f"{item.frechet_dis:.0f}, {item.angel:.0f},\n {item.related_pos:.2f}",
                horizontalalignment='center',
                verticalalignment='center')

        gpd.GeoSeries([road.geometry]).plot(color='red',
                                            label="OSM road",
                                            ax=ax)
        road_candidates.query(f"RID=='{rid}'").plot(color='blue',
                                                    linestyle='--',
                                                    label="match pano",
                                                    ax=ax)
        plt.legend()

        if save_fig:
            plt.savefig(f'../log/match_process/{road.name}.jpg',
                        pad_inches=0.1,
                        bbox_inches='tight')

    return road_candidates, rid
    # pano_dict = {}
    # bfs_panos(pid = '09005700121709091541105409Y', pano_dict=pano_dict, bbox=PCL_BBOX)


    """ crawl_panos_by_area """
    # szu_geom = gpd.read_file('../cache/SZU_geom.geojson').iloc[0].geometry
    # pano_dict = crawl_panos_by_area(geom = szu_geom)
    pano_dict = crawl_panos_by_area(bbox=LXD_BBOX)
    # key_pano_dict = crawl_panos_by_area(box(*PCL_BBOX))


    """ extract data from key panos """
    gdf_key_panos = pano_dict_to_gdf(pano_dict)
    gdf_roads = extract_gdf_roads_from_key_pano(pano_dict)
    gdf_panos = extract_gdf_panos_from_key_pano(pano_dict, update_dir=True)
    map_visualize( gdf_key_panos )


    """ helper """
    saver.save(pano_dict, '../cache/pano_dict_lxd.pkl')
    # gdf_to_postgis(gdf_roads, 'tmp_roads')


    """ SZU check """
    pano_dict = saver.read('../cache/pano_dict_szu.pkl')

# %%

# TODO check pano


if __name__ == '__main__':
    from utils.geo_plot_helper import map_visualize
    from db.db_process import update_lane_num_in_DB
    # df = gpd.GeoDataFrame([{ 'geometry': bbox, 'index':0 }])

    import geopandas as gpd
    futian_area = gpd.read_file(
        '../../cache/福田路网区域.geojson').iloc[0].geometry.wkt
    res = get_features(feature='line', geom=futian_area)
    res_road = get_features(feature='topo_osm_shenzhen_edge', geom=futian_area)

    res = get_features(feature='line',
                       bbox=[113.929807, 22.573702, 113.937680, 22.578734])
    map_visualize(res)
    res.head(2).to_json()

    area = gpd.read_file(
        '/home/pcl/Data/minio_server/input/Shenzhen_boundary_district_level_wgs.geojson'
    )
    area = area.query("name =='龙华区'")
    tmp = area.iloc[0].geometry

    lines = get_features('line', geom=tmp)
    lines.lane_num.value_counts()

    points = get_features('point', geom=tmp)
    # lines.fillna(3, inplace=True)

    lines.to_file('./lines_longhua.geojson', driver="GeoJSON")
                                         axis=1)
    df_order_coords = gpd.GeoDataFrame(df_order_coords, geometry=geometry)

    df_order_coords.reset_index(drop=True, inplace=True)
    df_order_coords.loc[:, 'id'] = df_order_coords.index
    # TODO coords values: start or end port
    df_order_coords.loc[:, 'coords'] = df_order_coords.apply(
        lambda x: bd_coord_to_mc(*ct.wgs84_to_bd09(x.x1, x.y1)), axis=1)

    if visualize:
        map_visualize(df_order_coords)

    # df_order_coords.to_file('./光侨路_南行_节点.geojson', driver="GeoJSON")
    return df_order_coords


if __name__ == '__main__':

    df_roads = gpd.read_file(
        '/home/pcl/traffic/RoadNetworkCreator_by_View/input/光侨路.geojson')
    df_roads.query("start=='12685799.40,2586251.61' ")

    points, graph, zero_indegree_points = extract_roads_info(df_roads)
    res, df = traverse_road_consider_reverse_edge('12685054.46,2591594.75',
                                                  graph, df_roads)
    df_roads.query("end=='12685799.40,2586251.61' ")

    map_visualize(df, 's')
    df
    pass