def angle_3_lignes(ligne_depart, lignes_adj, noeud,geom_noeud_central, type_noeud, df_lignes) : """ angles 3 lignes qui se separent en entree : ligne_depart : sdtring : id_ign de la igne qui va separer lignes_adj : geodf des lignes qui se separentde la ligne de depart noeud : integer : numero du noeud central geom_noeud_central : wkt du point central de separation type_noeud : type du noeud centrale par rapport à la ligne de depart : 'source' ou 'target' df_lignes : df de l'ensemble des lignes du transparent en sortie : lgn_cote_1 : df de la ligne qui se separe de la ligne etudie lgn_cote_2 : df de l'autre ligne qui se separe angle_1 : float : angle entre la ligne de depart et la 1er des lignes_adj angle_2 : float : angle entre la ligne de depart et la 2eme des lignes_adj angle_3 : l'ecart entre les 2 lignes qui se separent """ #noeud partage = noeud, dc coord_noeud_partage= coord_noeud_partage=list(loads(geom_noeud_central).coords)[0] lgn_cote_1=lignes_adj.iloc[0] lgn_cote_2=lignes_adj.iloc[1] #coord noeud non partage lignes de depart : c'est le 2eme ou avant dernier point dans la liste des points, selon le type_noeud coord_lgn_dep_pt1=([coord for coord in df_lignes.loc[ligne_depart].geom[0].coords][1] if type_noeud=='source' else [coord for coord in df_lignes.loc[ligne_depart].geom[0].coords][-2]) # trouver type noeud pour ligne fin et en deduire la coord du noeud suivant sur la ligne: type_noeud_comp_lgn1='source' if lgn_cote_1['source']==noeud else 'target' coord_lgn1_fin_pt2=([coord for coord in lgn_cote_1.geom[0].coords][1] if type_noeud_comp_lgn1=='source' else [coord for coord in lgn_cote_1.geom[0].coords][-2]) type_noeud_comp_lgn2='source' if lgn_cote_2['source']==noeud else 'target' coord_lgn2_fin_pt2=([coord for coord in lgn_cote_2.geom[0].coords][1] if type_noeud_comp_lgn2=='source' else [coord for coord in lgn_cote_2.geom[0].coords][-2]) #angle entre les 2 lignes : angle_1=Outils.angle_entre_2_ligne(coord_noeud_partage, coord_lgn_dep_pt1, coord_lgn1_fin_pt2) angle_2=Outils.angle_entre_2_ligne(coord_noeud_partage, coord_lgn_dep_pt1, coord_lgn2_fin_pt2) angle_3=360-(angle_1+angle_2) return lgn_cote_1, lgn_cote_2, angle_1,angle_2,angle_3
def tronc_tch(ids, df_lignes) : """ obtenir une df des troncon touches par une ligne avec l'angle entre les lignes, le numero, le codevoie_d attention, la geom doit etre de type multilinestring en entree : ids : tuple de string de id_ign df_lignes : données issues de identifier_rd_pt() avec id_ign en index en sortie : df_tronc_tch : df avec les attributs precites """ if len(ids)==1 : #une seule lignes dans le troncon df_ids=df_lignes.loc[ids].copy() noeuds = [df_ids.source,df_ids.target] list_ids_tch= df_lignes.loc[((df_lignes.target.isin(noeuds)) | (df_lignes.source.isin(noeuds))) & (~df_lignes.index.isin(ids))].index.tolist() list_carac_tch=[(a,b) for a,b in zip(list_ids_tch,[('source',df_lignes.loc[a].source) if df_lignes.loc[a].source in noeuds else ('target',df_lignes.loc[a].target) for a in list_ids_tch])] list_carac_fin=[(a[0][0],a[0][1][0],a[0][1][1], a[1]) for a in zip(list_carac_tch,['source' if b[1]==df_lignes.loc[ids].source else 'target' for a,b in list_carac_tch])] df_tronc_tch=pd.DataFrame.from_records(list_carac_fin, columns=['id_ign', 'type_noeud_lgn', 'id_noeud_lgn', 'type_noeud_src']) #calcul des coordonnées des points df_tronc_tch['coord_lgn_base']=df_tronc_tch.apply(lambda x : [df_ids.geom[0].coords[i] for i in range(len(df_ids.geom[0].coords))][1] if x['type_noeud_src']=='source' else [df_ids.geom[0].coords[i] for i in range(len(df_ids.geom[0].coords))][-2],axis=1) df_tronc_tch['coord_lgn_comp']=df_tronc_tch.apply(lambda x : [df_lignes.loc[x['id_ign']].geom[0].coords[i] for i in range(len(df_lignes.loc[x['id_ign']].geom[0].coords))][1] if x['type_noeud_lgn']=='source' else [df_lignes.loc[x['id_ign']].geom[0].coords[i] for i in range(len(df_lignes.loc[x['id_ign']].geom[0].coords))][-2],axis=1) df_tronc_tch['coord_noued_centr']=df_tronc_tch.apply(lambda x : [df_lignes.loc[x['id_ign']].geom[0].coords[i] for i in range(len(df_lignes.loc[x['id_ign']].geom[0].coords))][0] if x['type_noeud_lgn']=='source' else [df_lignes.loc[x['id_ign']].geom[0].coords[i] for i in range(len(df_lignes.loc[x['id_ign']].geom[0].coords))][-1],axis=1) #angle df_tronc_tch['angle']=df_tronc_tch.apply(lambda x : Outils.angle_entre_2_ligne(x['coord_noued_centr'],x['coord_lgn_comp'], x['coord_lgn_base']),axis=1) df_tronc_tch=df_tronc_tch.merge(df_lignes[['numero','nom_1_d',df_lignes.geometry.name]], left_on='id_ign', right_index=True) df_tronc_tch['longueur']=df_tronc_tch[df_lignes.geometry.name].apply(lambda x : x.length) else : df_ids=df_lignes.loc[list(ids)].copy() noeuds=[k for k,v in Counter(df_ids.source.tolist()+df_ids.target.tolist()).items() if v==1] #liste des noeuds uniques geom_noeuds=[loads(k).coords[0] for k,v in Counter(df_ids.src_geom.tolist()+df_ids.tgt_geom.tolist()).items() if v==1] #liste des geoms uniques geom_ligne=linemerge(unary_union(df_ids.geom.tolist())) #agregation des lignes pt_source=tuple([round(a,8) for a in geom_ligne.coords[0]]) #calculdes coordonées deb et fin de la lignes agregee pt_target=tuple([round(a,8) for a in geom_ligne.coords[-1]]) df_noeud=pd.DataFrame(zip(noeuds,geom_noeuds), columns=['id_noeud', 'geom_noeud']) df_noeud['type_noeud']=df_noeud.apply(lambda x : 'target' if x['geom_noeud']==pt_target else 'source',axis=1) #affectation du type de noeud df_noeud.set_index('id_noeud',inplace=True) list_ids_tch= df_lignes.loc[((df_lignes.target.isin(noeuds)) | (df_lignes.source.isin(noeuds))) & (~df_lignes.index.isin(ids))].index.tolist() list_carac_tch=[(a,b) for a,b in zip(list_ids_tch,[('source',df_lignes.loc[a].source) if df_lignes.loc[a].source in noeuds else ('target',df_lignes.loc[a].target) for a in list_ids_tch])] list_carac_fin=[(a[0][0],a[0][1][0],a[0][1][1], a[1]) for a in zip(list_carac_tch,['source' if df_noeud.loc[b[1]].type_noeud=='source' else 'target' for a,b in list_carac_tch])] df_tronc_tch=pd.DataFrame.from_records(list_carac_fin, columns=['id_ign', 'type_noeud_lgn', 'id_noeud_lgn', 'type_noeud_src']) #calcul des coordonnées des points df_tronc_tch['coord_lgn_base']=df_tronc_tch.apply(lambda x : geom_ligne.coords[1][1] if x['type_noeud_src']=='source' else geom_ligne.coords[1][-2],axis=1) df_tronc_tch['coord_lgn_comp']=df_tronc_tch.apply(lambda x : [df_lignes.loc[x['id_ign']].geom[0].coords[i] for i in range(len(df_lignes.loc[x['id_ign']].geom[0].coords))][1] if x['type_noeud_lgn']=='source' else [df_lignes.loc[x['id_ign']].geom[0].coords[i] for i in range(len(df_lignes.loc[x['id_ign']].geom[0].coords))][-2],axis=1) df_tronc_tch['coord_noued_centr']=df_tronc_tch.apply(lambda x : [df_lignes.loc[x['id_ign']].geom[0].coords[i] for i in range(len(df_lignes.loc[x['id_ign']].geom[0].coords))][0] if x['type_noeud_lgn']=='source' else [df_lignes.loc[x['id_ign']].geom[0].coords[i] for i in range(len(df_lignes.loc[x['id_ign']].geom[0].coords))][-1],axis=1) #angle df_tronc_tch['angle']=df_tronc_tch.apply(lambda x : Outils.angle_entre_2_ligne(x['coord_noued_centr'],x['coord_lgn_comp'], x['coord_lgn_base']),axis=1) #df_tronc_tch=df_tronc_tch.merge(df_lignes[['numero','nom_1_d']], left_on='id_ign', right_index=True) #ce qui suit n'est pas verifie, si besoin reprendre la ligne commentaire ci-dessus, mais qui ne permet pas d'avoir la geom et longueur df_tronc_tch=df_tronc_tch.merge(df_lignes[['numero','nom_1_d',df_lignes.geometry.name]], left_on='id_ign', right_index=True) df_tronc_tch['longueur']=df_tronc_tch[df_lignes.geometry.name].apply(lambda x : x.length) return df_tronc_tch
def recup_troncon_elementaire(id_ign_ligne, df, ligne_traite_troncon=[]): """ Fonction generatrice Recuperer les lignes d'un troncon a partir d'une ligne source gere les cas simple (ligne qui se suivent), les voies à 2 lignes, les 3 lignes qui se touchent en entree : id d'une ligne -> str liste des ligne traitees dans le cadre de ce troncon elementaire -> liste de str en sortie : id de la ligne suivante -> str """ #donnees de la ligne df_ligne = df.loc[id_ign_ligne] #print(df_ligne) nature = df_ligne.loc['nature'] #print('ligne_traite_troncon : ',ligne_traite_troncon) ligne_traite_troncon.append(id_ign_ligne) #yield id_ign_ligne liste_ligne_suivantes = [] for key, value in { 'nb_intrsct_src': ['source', 'src_geom'], 'nb_intrsct_tgt': ['target', 'tgt_geom'] }.items(): #print(id_ign_ligne,key, value) # cas simple de la ligne qui en touche qu'uen seule autre du cote source if df_ligne.loc[key] == 2: #print (f' cas = 2 ; src : avant test isin : {datetime.now()}, ligne : {id_ign_ligne} ') #print(id_ign_ligne,key, value) df_touches_source = df.loc[( ~df.index.isin(ligne_traite_troncon) ) & ( (df['source'] == df_ligne[value[0]]) | (df['target'] == df_ligne[value[0]]) )] # recuperer le troncon qui ouche le point d'origine et qui n'est pas deja traite #print (f' cas = 2 ; src : apres test isin : {datetime.now()}') if len( df_touches_source ) > 0: # car la seule voie touchee peut déjà etre dans les lignes traitees id_ign_suivant = df_touches_source.index.tolist()[0] liste_ligne_suivantes.append(id_ign_suivant) #print (f'fin traitement cas = 2 ; src : apres test isin : {datetime.now()}') ligne_traite_troncon.append( id_ign_suivant) #liste des lignes deja traitees #yield from recup_troncon_elementaire(id_ign_suivant, ligne_traite_troncon) #on boucle pour chercher la suivante yield id_ign_suivant elif df_ligne.loc[ key] >= 3: # cas plus complexe d'une ligne a un carrefour. soit c'est la meme voie qui se divise, soit ce sont d'autre voie qui touche #print (f' cas = 3 ; src : avant test isin : {datetime.now()}') df_touches_source = df.loc[ (~df.index.isin(ligne_traite_troncon)) & ((df['source'] == df_ligne[value[0]]) | (df['target'] == df_ligne[value[0]]) )] # recuperer le troncon qui ouche le point d'origine liste_ligne_touchees = df_touches_source.index.tolist() #print (f' cas = 3 ; src : apres test isin : {datetime.now()}') #gestion des bretelles et des rond points : si la ligne qui est traitée est dessus et que plusieurs voies en partent : on ne traite pas la ligne, elle sera traitee avec les voies qui arrivent sur le rd point if nature == 'Bretelle' or df_touches_source['nature'].all( ) == 'Bretelle': #comme ça les bretelles sont séparrées des sections courantes, si on dispose de données de ccomptage dessus (type dira) continue elif nature == 'Rd_pt' and df_ligne['nb_rte_rdpt'] > 1: ligne_traite_troncon, liste_ligne_suivantes = [], [] break if len(liste_ligne_touchees ) > 0: # si les voies touchees n'on pas ete traiees if ( (df_ligne.loc['numero'] == df_touches_source['numero']).all() == 1 and (df_ligne.loc['numero'] != 'NC') ): # pour les voies hors voies communales si elles ont le mm nom on prend toutes les lignes, pour les voies communales dont les nom_voie_g sont equivalent c'est pareil #gestion des rd points if df_touches_source['nature'].any( ) == 'Rd_pt': #si une des lignes touchées est un rd point on prend toutes les autres du m^me rd point id_rdpt = df_touches_source.iloc[0][ 'id_rdpt'] #recuperer l'id du rd pt nb_rte_rdpt = df_touches_source.iloc[0][ 'nb_rte_rdpt'] #recuperer le nb de route qui croise le rd point liste_ligne_touchees += df.loc[( df['id_rdpt'] == id_rdpt ) & ( ~df.index.isin(liste_ligne_touchees) )].index.tolist( ) #recuperer les lignes de cet id_drpt non deja recuperee #print(f'ligne{id_ign_ligne} rd point {liste_ligne_touchees}, nb rroute rd pt {nb_rte_rdpt}') if nb_rte_rdpt > 1: #si le rd point concentre plusieurs routes différentes, on stocke kes voies du rond point mais on ne traite pas les autres voies du mm nom qui en sortent for id_ign_suivant in liste_ligne_touchees: ligne_traite_troncon.append(id_ign_suivant) yield id_ign_suivant else: # a l'inverse, si le rond point ne traite qu'une seule route, on associe le rd pt + les voies qui en sortent au mm troncon for id_ign_suivant in liste_ligne_touchees: liste_ligne_suivantes.append(id_ign_suivant) ligne_traite_troncon.append(id_ign_suivant) yield id_ign_suivant else: for id_ign_suivant in liste_ligne_touchees: #print (f'fin traitement cas = 3 mm numero ; src : apres test isin : {datetime.now()}') liste_ligne_suivantes.append(id_ign_suivant) ligne_traite_troncon.append(id_ign_suivant) #yield from recup_troncon_elementaire(id_ign_suivant, ligne_traite_troncon) yield id_ign_suivant elif ((df_ligne.loc['codevoie_d'] == df_touches_source['codevoie_d']).all() == 1 and (df_ligne.loc['numero'] == 'NC') and df_touches_source['numero'].all() == 'NC'): #si les voies qui se croisent sont les memes if df_touches_source['nature'].any( ) == 'Rd_pt': #si une des lignes touchées est un rd point on prend toutes les autres du m^me rd point id_rdpt = df_touches_source.iloc[0][ 'id_rdpt'] #recuperer l'id du rd pt liste_ligne_touchees += df.loc[( df['id_rdpt'] == id_rdpt ) & ( ~df.index.isin(liste_ligne_touchees) )].index.tolist( ) #recuperer les lignes de cet id_drpt non deja recuperee #print(f'ligne{id_ign_ligne} rd point {liste_ligne_touchees}, nb rroute rd pt {nb_rte_rdpt}') for id_ign_suivant in liste_ligne_touchees: liste_ligne_suivantes.append(id_ign_suivant) ligne_traite_troncon.append(id_ign_suivant) yield id_ign_suivant else: for id_ign_suivant in liste_ligne_touchees: #print (f'fin traitement cas = 3 mm numero ; src : apres test isin : {datetime.now()}') liste_ligne_suivantes.append(id_ign_suivant) ligne_traite_troncon.append(id_ign_suivant) #yield from recup_troncon_elementaire(id_ign_suivant, ligne_traite_troncon) yield id_ign_suivant elif ( df_ligne.loc['numero'] == 'NC' and len( set(df_touches_source['codevoie_d'].values.tolist( ))) == 2 and 'NR' in df_touches_source['codevoie_d'].values.tolist() and (df_touches_source['numero'] == 'NC').all() and df_ligne.loc['codevoie_d'] in df_touches_source['codevoie_d'].values.tolist() ): #si les voies croisés ont un nom pour ue d'entre elle et l'autre non df_touches_source = df_touches_source.loc[ df_touches_source['codevoie_d'] == df_ligne[ 'codevoie_d']] #on limite le df touche sources aux voies qui ont le même nom liste_ligne_touchees = df_touches_source.index.tolist() if df_touches_source['nature'].any( ) == 'Rd_pt': #si une des lignes touchées est un rd point on prend toutes les autres du m^me rd point id_rdpt = df_touches_source.iloc[0][ 'id_rdpt'] #recuperer l'id du rd pt liste_ligne_touchees += df.loc[( df['id_rdpt'] == id_rdpt ) & ( ~df.index.isin(liste_ligne_touchees) )].index.tolist( ) #recuperer les lignes de cet id_drpt non deja recuperee #print(f'ligne{id_ign_ligne} rd point {liste_ligne_touchees}, nb rroute rd pt {nb_rte_rdpt}') for id_ign_suivant in liste_ligne_touchees: #liste_ligne_suivantes.append(id_ign_suivant) ligne_traite_troncon.append(id_ign_suivant) yield id_ign_suivant else: for id_ign_suivant in liste_ligne_touchees: #print (f'fin traitement cas = 3 mm numero ; src : apres test isin : {datetime.now()}') liste_ligne_suivantes.append(id_ign_suivant) ligne_traite_troncon.append(id_ign_suivant) #yield from recup_troncon_elementaire(id_ign_suivant, ligne_traite_troncon) yield id_ign_suivant elif ( df_ligne.loc['numero'] == 'NC' and (df_touches_source['nature'] == 'Rd_pt').all() and df_touches_source['assigne_rdpt'].all() == False ): #si on touche un rond point dont on ne peut pas affecter le nom, on va lui affecter un id arbitraire, mais pas au lignes suivantes id_rdpt = df_touches_source.iloc[0]['id_rdpt'] liste_ligne_touchees += df.loc[ (df['id_rdpt'] == id_rdpt) & (~df.index.isin(liste_ligne_touchees))].index.tolist() for id_ign_suivant in liste_ligne_touchees: #liste_ligne_suivantes.append(id_ign_suivant) ligne_traite_troncon.append(id_ign_suivant) yield id_ign_suivant else: #si toute les voies n'ont pas le même nom if nature in ['Autoroute', 'Quasi-autoroute']: df_ligne_autre = df_touches_source.loc[ df_touches_source['numero'] != df_ligne['numero']] if len(df_touches_source) - len( df_ligne_autre ) > 0: #sinon ce veut dire que le troncon suivant est deja traite df_ligne_pt_avant_src = df_ligne['geom'][0].coords[ 1] #point avant le point target coord_source_arrondi = [ round(i, 1) for i in list( loads(df_ligne[value[1]]).coords)[0] ] #coordonnees du point target #trouver le point de df_ligne autre juste aprs le point source coord_ligne_arrondi = [ [round(coord[0], 1), round(coord[1], 1)] for coord in list(( df_ligne_autre.geometry.iloc[0])[0].coords) ] #(df_ligne_autre.geometry.iloc[0]) la geometryde la 1ere ligne pt_suivant_src_ligne_autre = coord_ligne_arrondi[ -2] if coord_ligne_arrondi[ -1] == coord_source_arrondi else coord_ligne_arrondi[ 1] #recuperer l'angle angle = Outils.angle_entre_2_ligne( coord_source_arrondi, pt_suivant_src_ligne_autre, df_ligne_pt_avant_src) #si l'angle estdans les 90°, on ignor et on continue sur la l'autre ligne if 55 < angle < 135: id_ign_suivant = df_touches_source.loc[ ~df.id.isin(df_ligne_autre.id )].index.values.tolist()[0] liste_ligne_suivantes.append(id_ign_suivant) #print (f'fin traitement cas = 3 ; src : apres test isin : {datetime.now()}') ligne_traite_troncon.append(id_ign_suivant) yield id_ign_suivant #yield from recup_troncon_elementaire(id_ign_suivant, ligne_traite_troncon) #print(f'ligne : {id_ign_ligne}, liste a traiter : {liste_ligne_suivantes}' ) for ligne_a_traiter in liste_ligne_suivantes: yield from recup_troncon_elementaire(ligne_a_traiter, df, ligne_traite_troncon)