Example #1
0
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 
Example #2
0
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)