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
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
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
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()
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
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
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]
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
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()
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