import numpy as np
from scipy.spatial import Voronoi

import matplotlib as mpl
import matplotlib.pyplot as plt
import pickle
import time
import shutil


def dirP(obj,nmax=10):
    """
    Description :    Gives all the attributes and values of an object
    Input :* Obj : the object you want to explore
           * nmax (optional):  is the number of elements you want to print from the attributes
    Output: None
    """
    for name in dir(obj):
        if(name[0]!='_'):
            ok=0
            val=eval('obj.'+name)
            if type(val) is int : ok=1
            else :
                try:
                    if str(val)[0]!='<': ok=1
                except BaseException:
                    print(name, " Methode locale")
            if ok:
                if type(val) is list :
                    print(name, (20-len(str(name)))*' ','is a list of size :', len(val),end='  ')
                    if len(val)<nmax : print(val)
                    else           :                         print(',',val[0:nmax] , '\n(',nmax,' first elements)')
                elif type(val) is np.ndarray :
                    print(name, (20-len(str(name)))*' ','is a list of size :', val.shape, end='  ')
                    if np.prod( val.shape )<nmax : print(val)
                    else : print(',')

                else :
                    print(name, (20-len(str(name)))*' ',val)

#########################
def seg_intersect(a1,a2, b1,b2) :
    da = a2-a1
    db = b2-b1
    dp = a1-b1
    dap = perp(da)
    denom = np.dot( dap, db)
    num = np.dot( dap, dp )
    return (num / denom.astype(float))*db + b1

def perp( a ) :
    b = np.empty_like(a)
    b[0] = -a[1]
    b[1] = a[0]
    return b

def ccw(A,B,C):
    return (C[1]-A[1]) * (B[0]-A[0]) > (B[1]-A[1]) * (C[0]-A[0])

def intersect(A,B,C,D):
    return ccw(A,C,D) != ccw(B,C,D) and ccw(A,B,C) != ccw(A,B,D)

def length(XY):
    return np.sqrt((np.roll(XY[:,0],-1)-XY[:,0])**2+(np.roll(XY[:,1],-1)-XY[:,1])**2)

def linemaison(coord1,coord2):
    l=int(max(abs(coord1[0]-coord2[0]),abs(coord1[1]-coord2[1])))+1
    X= np.zeros(l,dtype=np.int32)
    Y= np.zeros(l,dtype=np.int32)
    for i in range(l):
        X[i]=round(coord1[0]+(i/(l-1))*(coord2[0]-coord1[0]))
        Y[i]=round(coord1[1]+(i/(l-1))*(coord2[1]-coord1[1]))
    return X,Y

def curvature(XY):
    # Calcul de la courbure comme le rapport entre la différence de deux angles/pentes qui se suivent
    # sur la longueur parcourue de la courbe
    return angle(XY[:,0],XY[:,1])/length(XY)

def angle(x,y):
    Pente=np.arctan2((np.roll(y,-1)-y),( np.roll(x,-1)-x)) ## Angle with 0
    Ang=Pente-np.roll(Pente,1)  #Difference of angle
    Ang[Ang<-np.pi]+= 2*np.pi # Modulo
    Ang[Ang> np.pi]+=-2*np.pi # Modulo
    return (180/np.pi)*Ang

def dist(XY):
    return np.sum(np.sqrt( (XY[:-1,0]-XY[1 :,0])**2 +
                           (XY[:-1,1]-XY[1 :,1])**2 ))

#########################

################################################################################
################## IMAGE OPERATIONS ############################################
def reduceIMGsize(IMG):
    '''
    depreciated, too many bugs
    '''
    bordersize=0
    index=0
    while sum(IMG[index,:])==0: index+=1
    ymin=max(0,index-bordersize)

    index=len(IMG[:,0])-1
    while sum(IMG[index,:])==0: index-=1
    ymax=min(index-bordersize,   len(IMG[:,0])-1)

    index=0
    while sum(IMG[:,index])==0: index+=1
    xmin=max(0,index-bordersize)

    index=len(IMG[0,:])-1
    while sum(IMG[:,index])==0: index-=1
    xmax=min(len(IMG[0,:])-bordersize,index+1)
    return(xmin,xmax,ymin,ymax)

################################################################################
################### ARC CREATION ###############################################
################################################################################
def Voronoi_Clean(XY,IMG,p):
    """
    DESCRIPTION :
    	_Takes all the points from every contour, and generate every segments of the voronoi
    	diagram. It create points at mid-range between two contours, but also some useless one.
    	_The program set all the generated points outside of the figure to [0,0]
    	_It then suppress all segments which are linked to a point not in the figure (thanks to IMG)
    	_Then it suppress all segments not linked to 2 different contours
      _Then it reorganise information
    INPUT :
        * XY : All the coordinates of the contour points, with their label
        * IMG : Matrix of values =0 if not on the gorgonian !=O if on gorgonian
    OUTPUT :
        * Vertices all usefull points positions generated by the Voronoi diagram
        * Segments all association of points we keep
        * Nconect : number of points having the connectivity of Nconect label.
    WHAT NEED TO BE UPGRADED :
        * There is no real needs, although the is badly coded. It works.
    Coded by <NAME>. Last update 03/03/2017
    """
    t=time.time()
    print('Completing Voronoi Calculation...',end='')
    vorSkel=Voronoi(XY[:,0:2])

    #plt.figure('Hop')
    #plt.imshow(IMG.binary.T,cmap='binary')
    #plt.plot(vorSkel.vertices[:,0],vorSkel.Vertices[:,1],'*',c='k')
    #voronoi_plot_2d(vorSkel)
    #plt.show()
    print('Done, t=',time.time()-t)
    # vorSkel.vertices       All the points created
    # vorSkel.ridge_vertices All the segments created of vertices
    # vorSkel.ridge_points   Link between label of original points in voronoi and real one
    print('Introduced', len(vorSkel.ridge_vertices),'Ridges')
    t=time.time()
    print('Removing infinity/out of structure Ridges...',end='')

    #Vertices Cleaning : detect all potentially good points
    supprpts={}                                         # Dictionnary : if the point is associated to true, it will be suppressed.
    supprpts[-1]=True                                   # Suppress label for all points at infinity

    for i in range(len(vorSkel.vertices[:,0])):                 # We check every pointd
       if (0<vorSkel.vertices[i,0]<IMG.X and 0<vorSkel.vertices[i,1]<IMG.Y):
           if IMG.binary[int(vorSkel.vertices[i,0]),int(vorSkel.vertices[i,1])]==0:# If they are not on the structure
               supprpts[i]=True                            # We will delete them
       else:
           supprpts[i]=True
    # Creation of segments with only points on the structure
    nsegok=0 								# Number of segment "OK" I.E without values from supprpts
    for i, item in enumerate(vorSkel.ridge_vertices):  			# For every segment
        if not (supprpts.get(item[0],False) or supprpts.get(item[1],False)) : # If the first point will not be suppr
                nsegok+=1      					# We count this segment as kept


    Segments=np.zeros((nsegok,4))	# On fill Segments of : [IndexVertice1|IndexVertice2|IndexPoint1|IndexPoint2]
    index=0 								# Counter
    for i, item in enumerate(vorSkel.ridge_vertices): 			# We now add every segments, checking same conditions
        if not supprpts.get(item[0],False):
            if not supprpts.get(item[1],False):
                Segments[index,0:2]=item 			# The Vertices of the segment
                Segments[index,2:4]=vorSkel.ridge_points[i]  		# The points (Contour) linked to the segment
                index+=1

    print('Done, t=',time.time()-t)
    print('kept', nsegok,'Ridges')

    t=time.time()
    print('Removing Ridges only linked to one contours...',end='')
    # Segments cleaning : only the one created with two different labels contours
    nsegok=0 								# Number of segments associated to 2 different contours
    for i in range(len(Segments[:,0])): 			# For Every segments
        if XY[np.int(Segments[i,2]),3] != XY[np.int(Segments[i,3]),3]: #if the segment is created by 2 different contours
            nsegok+=1                                   # We count this segment as kept

    Keptseg=np.zeros((nsegok,4)) 						# We will only keep these segments
    item=0                          					# Position in keptseg
    for i in range(len(Segments[:,0])): 				# For every segments
        if XY[np.int(Segments[i,2]),3] != XY[np.int(Segments[i,3]),3]: # If it satisfy our previous condition
            Keptseg[item,0:2]=Segments[i,0:2]                   #We add it to the segment
            Keptseg[item,2  ]=XY[np.int(Segments[i,2]),2]
            Keptseg[item,3  ]=XY[np.int(Segments[i,3]),2]
            item+=1


    #Vertices cleaning
    Vertices2=np.zeros((len(vorSkel.vertices),4))       # |X|Y|Connectivity for each point | Label
    Vertices2[:,0:2]=vorSkel.vertices                   # We copy X and Y
    for i in range(len(Keptseg)):               # for each segment
        Vertices2[np.int(Keptseg[i,0]),2]+=1    # we add 1 in connectivity for every point taht compose him
        Vertices2[np.int(Keptseg[i,1]),2]+=1    # Same
    print('Done. t=',time.time()-t )

    t=time.time()
    print('Reattribution of labels...',end='')
    #We associate a label for every kept Vertice
    label=0
    for i in range(len(Vertices2)):
        if Vertices2[i,2]>=1:
            Vertices2[i,3]=label
            label+=1

    #We calculate the number of point having a certain connectivity
    i=0
    while (len(Vertices2[Vertices2[:,2]==i]) or i<3 ):  # double condition so we don't skip points if there is no dead end
        Nconect=np.zeros(i) 					# We now know the maximal connectivity
        i+=1
    Nconect=np.zeros(i)
    i=0
    while (len(Vertices2[Vertices2[:,2]==i]) or i<3 ):
        Nconect[i]=len(Vertices2[Vertices2[:,2]==i])    # We count the number of points with this connectivity
        i+=1


    VerticesKept=np.zeros((np.int(np.sum(Nconect[1::])),5)) # We recreate a vector with only the pooints we keep
    index=0
    for i in range(len(Vertices2)): 						# We look at every points
        if Vertices2[i,2]>0:        						# if we can keep it
            VerticesKept[index,0:4]=Vertices2[i,:] 			# We add it
            index+=1


    # Reattribution des labels
    Segments=1.0*Keptseg 							# We change all the lagbels
    for i in range(len(Segments[:,0])):				# For every segments
        Segments[i,0]=Vertices2[int(Keptseg[i,0]),3] 		# We give them the new label
        Segments[i,1]=Vertices2[int(Keptseg[i,1]),3]


    Vertices=np.zeros(( len(VerticesKept) , 4 )) #On renomme Vertices
    Vertices[:,0:3]=VerticesKept[:,0:3]
    Vertices[:,3  ]=VerticesKept[:,4]
    print('Done. t=',time.time()-t)

    #### TERMINAL PRINT ###################################################
    print("Finished with :",len(Vertices),'points et',len(Segments) ,'segments')
    print("number of point :")
    for i in range(1,len(Nconect)):
        print(int(Nconect[i]), 'of connectivity', i)

    """
    DESCRIPTION :
    	*This function creates arcs (associations of segments), by looking at all the association of segments
    	between 2 points of connectivity different of 2
    INPUT :
		* Vertices : array 		[X|Y] of every points
		* Segments : array    	All the 2 associations of points
		* Nconect  : list
		* Kmin 	   : float
		* IMG_DIST : 2D-Array 	with the distance to the closest border
    OUTPUT :
        * Arc 	   : List of list of Vertices
    WHAT NEED TO BE UPGRADED :
        * Dictionnary could help a lot
        * The system not to do the same arc twice also
    Coded by <NAME>. Last update 03/03/2017
    """
    ######### Get parameters values ##################
    Kmin=p.get('Kmin', 1.1)

    ##################################################

    print('Arc Creation...',end='')
    t=time.time()
    Noeuds   = np.zeros((len(Vertices[Vertices[:,2]>2]),2+len(Nconect)))   # Useless, but needed to generate Ptsdepart (badly coded)
    Arcs     = []                                                          # All the arcs
    PtsAssoc=np.zeros((len(Vertices[:,0]),len(Nconect)-1))-1               # All the points connected to the point
    Ptsdepart=0*Noeuds[:,0:len(Nconect)]      #Ensemble des points ayant une connectivité != reste 4 2, desquels on va reconstruire les arcs

    #At this time, I didn't know dictionnary
    for i in range(len(Segments[:,0])): # For every segments
        for j in range(2):              # We look at both points
            ok=0
            index=0
            while ok==0: 				# Yes the structure is weird but work
                if PtsAssoc[int(Segments[i,j]),index]==-1:             # if the case is free
                    PtsAssoc[int(Segments[i,j]),index]=Segments[i,1-j] #It place the coordinate of the other points
                    ok=1
                else: index+=1 # if the case is full we go to the next one


    #All the starting points
    wherepts=np.zeros((len(PtsAssoc[:,0]),2))
    index=0
    sumpts=0
    for i in range(len(PtsAssoc[:,0])): 				#We look at every points
        if PtsAssoc[i,2]!=-1:							#if their connectivity is different of 2
            Ptsdepart[index,0]=i 						#We add its label
            Ptsdepart[index,1::]=PtsAssoc[i,:] 			#We copy every points linked to it

            wherepts[i,0]=sumpts                  		#So we know at what point correspond what arc
            wherepts[i,1]=sumpts+Vertices[i,2]-1 #
            sumpts+=Vertices[i,2]

            index+=1


    #Creation des arcs
    numarcsuppr=0
    debutfin=np.zeros((len(Ptsdepart[Ptsdepart!=0])-len(Ptsdepart[:,0]),2)) #WIll contains every first and last point
    index=0
    for i in range(len(Ptsdepart[:,0])-1): 									#For each crossing
        pts=Ptsdepart[i,:]
        for j in range(1,len(pts[pts!=-1])): 								#For each point linked to it
            Ok=1
            #print(index,len(debutfin),i,len(Ptsdepart[:,0]))
            debutfin[index,0]=Ptsdepart[i,0] 								# We note the first point

            liste=[int(Ptsdepart[i,0])]      # We add the first point to the list
            actualpt=Ptsdepart[i,j]     	 # The point after (the one we are actually in fact)
            prvspt=Ptsdepart[i,0]       	 # The point before(the first one for the moment)
            while Ok:                   	 # While the point is not an end
                liste.append(int(actualpt))  #We add it

                if Vertices[int(actualpt),2]==2: #if the arc goes on
                    nextpt=PtsAssoc[int(actualpt)][0:2] #We find the next one
                    temp=actualpt                       #on a weird way BECAUSE I CODED IT VERY BAAAAAAD
                    actualpt=nextpt[nextpt!=prvspt][0]  #here it is
                    prvspt=temp                     # We refresh the previous point
                else:                               #If the point we are in is a crossroad or a dead end
                    Ok=0                            #We won't go further
                    debutfin[index,1]=actualpt      #We note this point in debutfin
                    index+=1                        #We will be on the next arc label
                    #WE NOW CHECK IF WE CAN KEEP IT !
                    dfselect=debutfin[int(wherepts[int(liste[-1]),0]):int(wherepts[int(liste[-1]),1])+1,1] #Comparaison entre les elements de fin et debut
                    if liste[0] not in dfselect: #if the arc is not already existing
                        if Vertices[int(actualpt),2]==1: #If last point is a dead end (and because of the splitsegment an artefact)
                            X0=Vertices[int(liste[ 0]) ,0]; Y0=Vertices[int(liste[ 0]) ,1]
                            X1=Vertices[int(liste[-1]) ,0]; Y1=Vertices[int(liste[-1]) ,1]
                            D=max(IMG.dist[int(X0),int(Y0)],IMG.dist[int(X1),int(Y1)]) #We check distances between ends of the arc
                                                                                       #And also the distance of theses point to the exterior
                            if np.sqrt( (X0-X1)**2 + (Y0-Y1)**2 ) > Kmin*D:               #if the arc is bg enough
                                Arcs.append(liste)                                        #We add it to the list
                            else:
                                numarcsuppr+=1
                        else:
                            Arcs.append(liste)

    print('Done. time=', time.time()-t)

    print('We created', len(Arcs), 'Arcs')
    print('We aborted the generation of', numarcsuppr, '"False" arcs')

    """
    DESCRIPTION :
    because of the splitting, some segments where not conserved during the arc creation
	in consequence some crossroads are not true crossroads, and some arcs should get a fusion.
	That's what we do here !
    INPUT :
    	*Arcs . We don't need anything else
    OUTPUT :
     * Arcs . But proper !
    WHAT NEED TO BE UPGRADED :
	* I think it's ok here
     * We could do a fusion of this and AssembleVoies
    Coded by <NAME>. Last update 03/03/2017
    """
    t=time.time()
    print('Arcs Regroupment...',end='')
    zoup=len(Arcs)
    #Get for every end-points the arcs connected to
    ArcsFirstlast=np.zeros((len(Arcs),2),dtype=np.int32)
    for i,elements in enumerate(Arcs):
        ArcsFirstlast[i,0:2]=[elements[0],elements[-1]]
    Ptsconnected={}
    for i,elements in enumerate(ArcsFirstlast):
        Dict1=Ptsconnected.get(elements[0], [])
        Dict2=Ptsconnected.get(elements[1], [])
        Ptsconnected[elements[0]]=Dict1+[i]
        Ptsconnected[elements[1]]=Dict2+[i]

    #Creation of the links 2 per 2
    Links=[]
    for pt,arcs in Ptsconnected.items():
        if len(arcs)==2:
            Links+=[[arcs[0],arcs[1]]]

    VoiesArcs=[] #arc 1, arc2...
    ArcsTrueConnected={}
    Arcsnumconnect={}
    for elements in Links:
        Dict1=ArcsTrueConnected.get(elements[0], [])
        Dict2=ArcsTrueConnected.get(elements[1], [])
        Dict3=Arcsnumconnect.get(elements[0], 0)
        Dict4=Arcsnumconnect.get(elements[1], 0)
        ArcsTrueConnected[elements[0]]=Dict1+[elements[1]]
        ArcsTrueConnected[elements[1]]=Dict2+[elements[0]]
        Arcsnumconnect[elements[0]]=Dict3+1
        Arcsnumconnect[elements[1]]=Dict4+1

    # Create streets
    dontbeginwithit={}
    for i in ArcsTrueConnected.keys(): #Pour tous les arcs
        Dict1=Arcsnumconnect.get(i, 0)
        Dict2=dontbeginwithit.get(i, False)
        if Dict1==1 and Dict2==False: #Si ils ne sont connecté qu'une fois, et pas encore utilisé
            Ok=0
            actualarcs=i
            nextarc=ArcsTrueConnected[i][0]
            ActualVoies=[i]
            while Ok==0:
                ActualVoies+=[nextarc]
                if len(ArcsTrueConnected[nextarc])==1:                               #Si le prochain arc est un bout
                    dontbeginwithit[ArcsTrueConnected[nextarc][0]]=True              #On empeche de pouvoir repartir avec
                    Ok=1
                    VoiesArcs+=[ActualVoies]
                else:
                    previous=actualarcs
                    actualarcs=nextarc
                    choice=ArcsTrueConnected[nextarc][:]
                    nextarc=list(set(choice+[previous])-set([previous]))[0]

    VoiesPts=[]
    for ArcAsso in VoiesArcs: #Pour chaque association
        First =ArcsFirstlast[ArcAsso[0]]
        Second=ArcsFirstlast[ArcAsso[1]]
        pts=Arcs[ArcAsso[0]]

        if First[1] in Second:
            ActualVoie=pts[:]
        if First[0] in Second:
            ActualVoie= pts[::-1]

        for Arc in ArcAsso[1:]:
            pts=[Arcs[Arc]][0]
            if pts[0]==ActualVoie[-1]:
                ActualVoie+=pts[1:]
            elif pts[-1]==ActualVoie[-1]:
                pts=pts[::-1]
                ActualVoie+=pts[1:]
        VoiesPts+=[ActualVoie]

    numsup=0
    for ArcAsso in VoiesArcs: #Pour chaque association
        for Arc in ArcAsso:
            Arcs[Arc]=[]
            numsup+=1

    Arcs+=VoiesPts
    Arcs2=[a for a in Arcs if len(a)!=0]

    print('Done. t=',time.time()-t)
    print('On a regroupé', zoup,'arcs en',len(Arcs2))

    return Vertices, Arcs2    ,Segments

def Arcs_nettoyage(B):
    B.sort(key=len)                                            # We sort it with the number of points (useless)
    for i,b in enumerate(B):
        if b[0]>b[-1]: B[i]=B[i][::-1]                         #Smallest elemnt first
    dic={}                                                    #List containing first element
    kept=[]                                                    #List of kept indexes
    for i,b in enumerate(B):                                   #Only keeping first list having the same first point
        if not dic.get(str(b[0])+' '+str(b[-1]),False):
            dic[str(b[0])+' '+str(b[-1])]=True
            kept.append(i)
    return np.array(B)[kept]

def removeuselesspoints(XY,delta):
    X=XY[:,0]
    Y=XY[:,1]
    Xkept=X[0:2]
    Ykept=Y[0:2]
    for x,y in zip(X[2:-1],Y[2:-1]):
        m = (Ykept[-1]-Ykept[-2])/(Xkept[-1]-Xkept[-2])
        p = Y[-1]-m*X[-1]
        if abs(m* x +  y +p)/np.sqrt(1 +m**2 ) > delta:
            Xkept=np.hstack((Xkept,x))
            Ykept=np.hstack((Ykept,y))
    Xkept=np.hstack((Xkept,X[-1]))
    Ykept=np.hstack((Ykept,Y[-1]))
    return(np.column_stack((Xkept,Ykept)))

def UpgradeArcsVoies(IMG,AllArcs,AllVoies):
    '''
    When Ways are defined, we can have the correct shape of the arc without soap effect
    '''
    print('Better points Arcs')
    for A in AllArcs.list:
        A.XYasVoies=np.zeros((len(A.XYNoPlace)+2,2))
        A.XYasVoies[1:-1,:]=A.XYNoPlace
        if not A.IsInaPlace:
            ### Premier point
            if A.FirstLink == ['Extremity']:### Si c'est une extremité
                if AllVoies.list[A.Usedinvoie].Arc[0]==A.index: A.XYasVoies[0,:] = AllVoies.list[A.Usedinvoie].XY[0,:]
                else:                                           A.XYasVoies[0,:] = AllVoies.list[A.Usedinvoie].XY[-1,:]


            else:### Si c'est un lien
                if (A.FirstLink[1]=='first' or A.FirstLink[1]=='First'): A.XYasVoies[0,:]=( A.XYNoPlace[0,:] + AllArcs.list[A.FirstLink[0]].XYNoPlace[ 0,:] )/2
                else:                                                    A.XYasVoies[0,:]=( A.XYNoPlace[0,:] + AllArcs.list[A.FirstLink[0]].XYNoPlace[-1,:] )/2

            ### Dernier point
            if A.LastLink == ['Extremity']:### Si c'est une extremité
                if AllVoies.list[A.Usedinvoie].Arc[0]==A.index:
                    if    (np.sqrt( ( AllVoies.list[A.Usedinvoie].XY[-1,0]-A.XYasVoies[-2,0]  )**2 +
                                    ( AllVoies.list[A.Usedinvoie].XY[-1,1]-A.XYasVoies[-2,1]  )**2 )
                        <  np.sqrt( ( AllVoies.list[A.Usedinvoie].XY[0,0] -A.XYasVoies[-2,0]  )**2 +
                                    ( AllVoies.list[A.Usedinvoie].XY[0,1] -A.XYasVoies[-2,1]  )**2 ) ):
                        A.XYasVoies[-1,:] = AllVoies.list[A.Usedinvoie].XY[-1,:]
                    else :A.XYasVoies[-1,:] = AllVoies.list[A.Usedinvoie].XY[ 0,:]
                else:     A.XYasVoies[-1,:] = AllVoies.list[A.Usedinvoie].XY[-1,:]


            else:### Si c'est un lien
                if (A.LastLink[1]=='first' or A.LastLink[1]=='First'): A.XYasVoies[-1,:]=(A.XYNoPlace[-1,:]+AllArcs.list[A.LastLink[0]].XYNoPlace[ 0,:])/2
                else:                                                  A.XYasVoies[-1,:]=(A.XYNoPlace[-1,:]+AllArcs.list[A.LastLink[0]].XYNoPlace[-1,:])/2

            A.XYasVoiesLight=removeuselesspoints(A.XYasVoies,IMG.X/100)
            A.Angle= np.arctan2(np.abs(A.XYasVoies[-1,1]-
                                          A.XYasVoies[0 ,1] ),
                                   np.abs(A.XYasVoies[-1,0]-
                                          A.XYasVoies[0 ,0]))
    print('Simpler points Voies')
    print(AllVoies)
    for j,V in enumerate(AllVoies.list):

            V.Vertices2 = np.vstack((a for a in [ AllArcs.list[V.Arc[i]].XYasVoies[::V.lecture[i]] for i,elem in enumerate(V.Arc)]))
    return AllArcs,AllVoies

###############################################################################
##################### LINK CREATION ###########################################
###############################################################################
def PreparePlaces(Arcs,p):
    '''
    We look at all the arcs, and create what will be their connections :
    1) We get all the extremities of every Arcs as label points. All of them are Keys in RoughPlace, their elements are the (arcs and side) connected
    2) For Every Arcs, we check if it's in a place. We connect both sides
    3) For Every Places created
    '''

    ### 1)
    ### we create the "Rough Places" : With all the Arcs which arrive to one of the place
    ### Link contains all the Rough Places belonging to the other
    RoughPlace={}
    Link=[]
    for i,Arc in enumerate(Arcs.list):

        D0=RoughPlace.get(Arc.First, []);D0+=[[i,'first']];RoughPlace[Arc.First]=D0
        D1=RoughPlace.get(Arc.Last , []);D1+=[[i,'last']] ;RoughPlace[Arc.Last ]=D1

        if Arc.IsInaPlace:
            Link+=[[Arc.First,Arc.Last]]

    ### 2)
    ### BiggerPlace : contains all the surrounding roughplaces linked
    BiggerPlace={}
    for L in Link:
        D0=BiggerPlace.get(L[0],[]);          D0+=[L[1]]       ;BiggerPlace[L[0]]=D0
        D1=BiggerPlace.get(L[1],[]);          D1+=[L[0]]       ;BiggerPlace[L[1]]=D1

    ### Placeused : if the roughplace has already been used in a Place
    PlacesArcs=RoughPlace.copy()
    PlacesCenters={}
    Explored={}

    ### Reproductive method
    for P in RoughPlace.keys(): #For every Places
        PlacesCenters[P]=[P]+BiggerPlace.get(P,[])                              #They contains themselves

    stay=True
    while stay:                                                                 #While We have still some place to make grow
        stay=False
        #print('First turn')
        #input()
        for P in PlacesCenters.keys():                                          #For everyplaces
            if (len(PlacesCenters[P])>1 and Explored.get(P,False)==False):              # If there is still some work to do
                #print(P,'##########')
                #print('La place',PlacesCenters[P])

                count=len(PlacesCenters[P])
                A=np.copy(PlacesCenters[P])
                for P2 in A:
                    if P2!=P:
                        PlacesCenters[P]+=PlacesCenters[P2]
                        #print(P2,PlacesCenters[P2])
                PlacesCenters[P]=list(set(PlacesCenters[P]))
                #print('Now',PlacesCenters[P])
                if len(PlacesCenters[P])==count:Explored[P]=True;#print('Finished!')
                else:stay=True
                #input()

    NewPlacesCenters={}
    NewPlacesArcs={}
    index=0
    alreadycopied={}
    for P in PlacesCenters.keys(): # For every Places
        if not alreadycopied.get(P,False): # If it hasn't been used
            NewPlacesCenters[index]=PlacesCenters[P]

            PArcs=[]
            for P2 in NewPlacesCenters[index]:
                alreadycopied[P2]=True
                PArcs+=PlacesArcs[P2]
            NewPlacesArcs[index]=PArcs
            index+=1

    return NewPlacesArcs,NewPlacesCenters

def prepareCriteria(IMG,P,AllArcs):
    '''
    Dictionnary of the criteria for each place
    '''
    P.Criteria= {}
    P.Criteria['D1']            = [None]*len(P.Potentiallink)
    P.Criteria['DCenter']       = [None]*len(P.Potentiallink)

    P.Criteria['inLen']         = [None]*len(P.Potentiallink)
    P.Criteria['inMinD']        = [None]*len(P.Potentiallink)
    P.Criteria['inVarD']        = [None]*len(P.Potentiallink)
    P.Criteria['inDintegrale']  = [None]*len(P.Potentiallink)
    P.Criteria['Ang12']         = [None]*len(P.Potentiallink)

    P.Criteria['Outlen']        = [None]*len(P.Potentiallink)
    P.Criteria['OutDintegrale'] = [None]*len(P.Potentiallink)

    P.Criteria['Ang1']          = [None]*len(P.Potentiallink)
    P.Criteria['Ang2']          = [None]*len(P.Potentiallink)

    P.Criteria['Rarc1']         = [None]*len(P.Potentiallink)
    P.Criteria['Rarc2']         = [None]*len(P.Potentiallink)

    P.Criteria['D1']            = [None]*len(P.Potentiallink)
    P.Criteria['D2']            = [None]*len(P.Potentiallink)

    for j,pl in enumerate(P.Potentiallink):
        # print('numéro de la place :'')
        ang1l,ang2l,ang12 = chooseptangle(pl,AllArcs)
        rr,cc=linemaison([int(pl[2][0]),int(pl[2][1])],[int(pl[5][0]),int(pl[5][1])])

        pt1,pt2=P.mulLen[j][0][0],P.mulLen[j][0][1]
        rr2,cc2=linemaison([int(pt1[0]),int(pt1[1])],[int(pt2[0]),int(pt2[1])])


        # CRITERE 0 : LA PLACE, LES TAILLES
        P.Criteria['D1'][j]             = IMG.dist[int(pl[2][0]),int(pl[2][1])]
        P.Criteria['D2'][j]             = IMG.dist[int(pl[5][0]),int(pl[5][1])]
        P.Criteria['DCenter'][j]       = np.amax([ IMG.dist[int(X[0]),int(X[1])] for X in P.XY ])
        P.Criteria['Rarc1'][j]          = AllArcs.list[pl[0]].Rmin
        P.Criteria['Rarc2'][j]          = AllArcs.list[pl[3]].Rmin

        # CRITERE 1 : LA COURBE DE REPARTITION DES DISTANCES INTERNES A LA PLACE
        P.Criteria['inLen'][j]         =  np.sqrt( (pl[2][0]-pl[5][0] )**2 + (pl[2][1]-pl[5][1] )**2 )

        P.Criteria['inMinD'][j]        =np.amin(IMG.dist[rr,cc])
        P.Criteria['inVarD'][j]        =np.amax(IMG.dist[rr,cc])-np.amin(IMG.dist[rr,cc])
        P.Criteria['inDintegrale'][j]  =np.sum(IMG.dist[rr,cc])

        # CRITERE 2 : LES ANGLES FORMEES
        P.Criteria['Ang12'][j]         =ang12
        P.Criteria['Ang1'][j]          =ang1l
        P.Criteria['Ang2'][j]          =ang2l

        # CRITERE 3 : LA LONGUEUR QUI SORT DE LA PLACE
        # VALEUR DE BASE
        # VALEUR INTEGREE
        P.Criteria['Outlen']       [j]= np.sqrt((pt2[0]-pt1[0] )**2 + (pt2[1]-pt1[1] )**2 )
        P.Criteria['OutDintegrale'][j]= np.sum(IMG.dist[rr2,cc2])
    return( P.Criteria)

def PrepareScore(IMG,AllArcs,AllPlaces,p):
    for i,Place in enumerate(AllPlaces.list):#For each place with more than one arc
        if len(Place.Arcs)>1:
            problem=False
            index=0
            AllPlaces.list[i].mulLen        = [] #Lengths over the place
            AllPlaces.list[i].Potentiallink = [] #Geometric characteristics
            AllPlaces.list[i].Potentialscore= [] #Interior ability to go inside a place

            # WE ADD THE DIFFERENTS ELEMENTS, COMPARING ALL THE DIFFERENT POSSIBILITIES
            for j,Arc in enumerate(Place.Arcs):
                for k,Arc2 in enumerate(Place.Arcs[j+1:]) :
                    # potentiallink : |Arc1Label|Arc1Extremity|Arc1Pt|Arc2Label|Arc2Extremity|Arc2Pt|

                    # FIRST ARC
                    LIST=[];
                    LIST.append( Arc [0] )
                    LIST.append( Arc [1] )
                    if p.get('refereepoint',False):
                        if Arc [1]=='first': LIST.append( [AllArcs.list[Arc [0]].FirstReferee[0], AllArcs.list[Arc [0]].FirstReferee[1]] )
                        else               : LIST.append( [AllArcs.list[Arc [0]].LastReferee [0], AllArcs.list[Arc [0]].LastReferee [1]] )
                    else:
                        if Arc [1]=='first': LIST.append( [AllArcs.list[Arc [0]].XYNoPlace[ 0,0], AllArcs.list[Arc [0]].XYNoPlace[ 0,1]] )
                        else               : LIST.append( [AllArcs.list[Arc [0]].XYNoPlace[-1,0], AllArcs.list[Arc [0]].XYNoPlace[-1,1]] )

                    # SECOND ARC
                    LIST.append( Arc2[0] )
                    LIST.append( Arc2[1] )
                    if p.get('refereepoint',False):
                        if Arc2[1]=='first': LIST.append( [AllArcs.list[Arc2[0]].FirstReferee[0], AllArcs.list[Arc2[0]].FirstReferee[1]] )
                        else               : LIST.append( [AllArcs.list[Arc2[0]].LastReferee [0], AllArcs.list[Arc2[0]].LastReferee [1]] )
                    else:
                        if Arc2[1]=='first': LIST.append( [AllArcs.list[Arc2[0]].XYNoPlace[ 0,0], AllArcs.list[Arc2[0]].XYNoPlace[ 0,1]] )
                        else :               LIST.append( [AllArcs.list[Arc2[0]].XYNoPlace[-1,0], AllArcs.list[Arc2[0]].XYNoPlace[-1,1]] )
                    #print(LIST)
                    #print(i,j,k,LIST)
                    if (LIST[2][0]!=LIST[5][0] and LIST[2][1]!=LIST[5][1]):
                        rr,cc=linemaison([int(LIST[2][0]),
                                          int(LIST[2][1])],
                                         [int(LIST[5][0]),
                                          int(LIST[5][1])])
                        score =  min(IMG.dist[rr,cc])
                    else : score=0

                    index+=1
                    if score!=0:
                        AllPlaces.list[i].mulLen        .append(lengthprolongation(LIST[2],LIST[5],IMG,p.get('delta',0)))
                        AllPlaces.list[i].Potentialscore.append(score)
                        AllPlaces.list[i].Potentiallink .append(LIST)

            ### Creation du dictionnaire des criteres
            Place.Criteria=prepareCriteria(IMG,Place,AllArcs)
    return(AllPlaces)

def lengthprolongation(pt1,pt2,IMG,delta):
    mulLen=[]

    pt01=np.array([pt1[0],pt1[1]])
    pt02=np.array([pt2[0],pt2[1]])
    #print(pt01,pt02)
    D1=IMG.dist[int(pt01[0]),int(pt01[1])]
    D2=IMG.dist[int(pt02[0]),int(pt02[1])]

    if delta:
        L1= [pt01,
             pt01+np.array(-D1/delta,-D1/delta),
             pt01+np.array(-D1/delta,+D1/delta),
             pt01+np.array(+D1/delta,-D1/delta),
             pt01+np.array(+D1/delta,+D1/delta)]
        L2= [pt02,
             pt02+np.array(-D2/delta,-D2/delta),
             pt02+np.array(-D2/delta,+D2/delta),
             pt02+np.array(+D2/delta,-D2/delta),
             pt02+np.array(+D2/delta,+D2/delta)]
    else :
        L1=[pt01]
        L2=[pt02]

    for pt1 in L1:
        for pt2 in L2:
            try :
                D1=IMG.dist[int(pt1[0]),int(pt1[1])]
                D2=IMG.dist[int(pt2[0]),int(pt2[1])]
                L =np.sqrt( (pt1[0]-pt2[0])**2+  (pt1[1]-pt2[1])**2 )

                Disttot1=np.copy(D1)
                Disttot2=np.copy(D2)
                pre1=np.copy(pt1)
                pre2=np.copy(pt2)

                while 1:
                    pre1=pt1-(pt2-pt1)*Disttot1/L
                    newdist=IMG.dist[int(pre1[0]),int(pre1[1])]
                    Disttot1+=newdist
                    if newdist==0: break
                while 2:
                    pre2=pt2+(pt2-pt1)*Disttot2/L
                    newdist=IMG.dist[int(pre2[0]),int(pre2[1])]
                    Disttot2+=newdist
                    if newdist==0: break
                mulLen.append([pre1,pre2])
            except BaseException:
                mulLen.append([pt1,pt2])
                print('MultilenMarchePas')
    return mulLen

def LinkByScore(IMG,AllArcs,AllPlaces,p):
    Al = AllArcs.list
    Pl = AllPlaces.list
    crit=p['crit']
    for i,P in enumerate(AllPlaces.list):#For each place with more than one arc
        Plk=P.Potentiallink
        if len(P.Potentiallink)>=1:


            ### Print of criterias
            '''
            for j,key  in enumerate(['D1','D2','DCenter','Rarc1','Rarc2',
                                     'inLen','inMinD','inVarD','inDintegrale',
                                     'Outlen','OutDintegrale',
                                     'Ang1','Ang2','Ang12']):
                if j in [0,5,9,11]: print('-'*15+(1+len(P.Criteria[key]))*'-'*6)
                print(key+ (15-len(key))*' ',end='')
                for p in P.Criteria[key]:
                    print(np.round(p,3),(6-len(str(np.round(p,3))))*' ',end='')
                print('')
            print('Place number :',i)
            print('Number of arcs :',len(P.Arcs))
            print('Number of valid associations :',len(P.Potentiallink))
            '''


            ############### CREATION DU SCORE ######################################
            #if p['ScoreMode'] == '+' : score = np.sum(np.array([ np.array(P.Criteria[key])*val for key,val in p['coeffs'].items()]).reshape(-1,len(P.Potentiallink)),axis=1)
            #if p['ScoreMode'] == '*' : score = np.prod(np.array([ np.array(P.Criteria[key])**val for key,val in p['coeffs'].items()]).reshape(-1,len(P.Potentiallink)),axis=1)
            #print(np.array(P.Criteria['Outlen']))

            #print(crit)
            score , Plk = zip(*sorted(zip( np.array(P.Criteria[crit]), Plk )))
            score=score[::-1]
            Plk=Plk[::-1]


            # We scan the list, add the links we wants
            if  Plk[0][1]=='first': Al[ Plk[0][0] ].FirstLink=Plk[0][3:5]
            else                  : Al[ Plk[0][0] ]. LastLink=Plk[0][3:5]
            if  Plk[0][4]=='first': Al[ Plk[0][3] ].FirstLink=Plk[0][0:2]
            else                  : Al[ Plk[0][3] ]. LastLink=Plk[0][0:2]
            P.Links.append([Plk[0][0],Plk[0][3],Plk[0][1],Plk[0][4]])

            # We check for every Arcs, if it has no Link on the side we want, we add an extremity
            for j,Arc in enumerate(P.Arcs) :
                if ( Arc[1]=='first'  and len(Al[Arc[0]].FirstLink)==1 ):P.Extremities.append([Arc[0],'First'])
                if ( Arc[1]=='last'   and len(Al[Arc[0]].LastLink) ==1 ):P.Extremities.append([Arc[0],'Last'])
    return AllArcs,AllPlaces

def chooseptangle(pl,AllArcs):
    if pl[1].lower()=='first':
        pt1 = AllArcs.list[pl[0]].FirstReferee
        pt2 = AllArcs.list[pl[0]].LastXY
    else :
        pt1 = AllArcs.list[pl[0]].FirstXY
        pt2 = AllArcs.list[pl[0]].LastReferee

    if pl[4].lower()=='first':
        pt3 = AllArcs.list[pl[3]].FirstReferee
        pt4 = AllArcs.list[pl[3]].LastXY
    else :
        pt3 = AllArcs.list[pl[3]].FirstXY
        pt4 = AllArcs.list[pl[3]].LastReferee
    ang1 =np.abs((np.arctan2(pt2[1] - pt1[1], pt2[0] - pt1[0]) - np.arctan2(pt3[1] - pt2[1], pt3[0] - pt2[0]))%np.pi) # droite1-link
    ang2 =np.abs((np.arctan2(pt4[1] - pt3[1], pt4[0] - pt4[0]) - np.arctan2(pt3[1] - pt2[1], pt3[0] - pt2[0]))%np.pi) # droite2-link
    ang3 =np.abs((np.arctan2(pt4[1] - pt3[1], pt4[0] - pt3[0]) - np.arctan2(pt2[1] - pt1[1], pt2[0] - pt1[0]))%np.pi) # droite1-droite2
    return ang1,ang2,ang3




























###############################################################################
##################### CHECKS OF THE RESULTS ###################################
###############################################################################

def AllCheckings(IMG,AllContours,AllArcs,AllPlaces,AllVoies,p,k=False):
    if not k : k=input('What do you want to check ?\n 0 : image binarisation \n 1 : are contours artefacts \n 2 : what points are in arcs \n 3 : what places are together \n 4 : what Ways are created\n')
    import matplotlib.pylab as pl
    from matplotlib.collections import LineCollection
    import random
    if k=='0':
        plt.figure("Checking Image",figsize=(10,10))
        plt.title('Binary image')
        plt.imshow(IMG.binary,cmap='binary')
        plt.axis('scaled')
        plt.show()



    if k=='1':
        plt.figure("Checking artefacts",figsize=(10,10))
        ax=plt.gca()
        for C in AllContours.list:
            if C.artefact:
                plt.plot(C.X,C.Y,'*',color='red')
                Pol=mpl.patches.Polygon(C.XY,color='red')
                ax.add_patch(Pol)
                print('ARTEFACT',np.mean(C.XY[:,0]),np.mean(C.XY[:,1]))
            elif C.isexterior:
                plt.plot(C.X,C.Y,c='k')
            else:
                Pol=mpl.patches.Polygon(C.XY,color='blue')
                ax.add_patch(Pol)
        plt.show()


    if k=='2':
        Lines_Arcs=[]

        for A in AllArcs.list:
            Lines_Arcs+=list(zip(list(zip(A.XY[0:-1,0],A.XY[0:-1,1]))
                                ,list(zip(A.XY[1:  ,0],A.XY[1:  ,1]))))

        plt.figure("Checking artefacts",figsize=(10,10))
        ax=plt.gca()
        ax.add_collection(LineCollection(Lines_Arcs,color='k',linewidth=2))

        colormax  = pl.cm.jet( np.linspace(0,1,1+AllContours.ncontours ) )
        for i,C in enumerate(AllContours.list):
            if C.isexterior:
                plt.plot(C.X,C.Y,c='k')
            else:
                Pol=mpl.patches.Polygon(C.XY,color=colormax[int(random.random()*AllContours.ncontours),:])
                ax.add_patch(Pol)
        plt.xlim([0,IMG.X])
        plt.ylim([0,IMG.Y])
        plt.show()

    if k=='3':
        fx=p.get('fx',10)
        fy=p.get('fy',10)

        plt.figure('ArcsPlaces',figsize=(fx,fy))
        plt.imshow(IMG.binary.T,cmap='binary')
        axes = plt.gca()
        '''
        Lines_Arcs=[]
        for A in AllArcs.list:
            Lines_Arcs+=list(zip(list(zip(A.XY[0:-1,0],A.XY[0:-1,1]))
                                ,list(zip(A.XY[1:  ,0],A.XY[1:  ,1]))))
        axes.add_collection(LineCollection(Lines_Arcs,color='k',linewidth=1))
        '''
        colormax  = pl.cm.jet( np.linspace(0,1,1+len(AllPlaces.list)) )
        for i,Place in enumerate(AllPlaces.list):
            for j in range(len(Place.Centers)):
                plt.plot(Place.XY[j,0],Place.XY[j,1],'*',c='k')
                Pol=mpl.patches.Circle((Place.XY[j,0],Place.XY[j,1]),Place.Radius[j]  ,color=colormax[i,:]  )
                axes.add_patch(Pol)
            for arc in Place.ArcsInside:
                plt.plot(AllArcs.list[arc].XY[:,0],AllArcs.list[arc].XY[:,1],color='r')

        plt.axis('scaled')
        plt.show()

    if k=='4':

        fx=p.get('fx',10)
        fy=p.get('fy',10)
        plt.figure('Voies',figsize=(fx,fy))
        axes = plt.gca()
        colormax  = pl.cm.jet( np.linspace(0,1,1+len(AllVoies.list)) )
        for i,Voies in enumerate(AllVoies.list):
            plt.plot(Voies.XY[:,0],Voies.XY[:,1],color=colormax[i,:])
            #for A in Voies.Arc:
            #    plt.plot(AllArcs.list[A].XY[:,0],AllArcs.list[A].XY[:,1],color=colormax[i,:])
            #if len(Voies.XY[:,0]==1):
            #    plt.plot(Voies.XY[:,0],Voies.XY[:,1],'*',color=colormax[i,:])
            #axes.annotate(i,xy=(np.mean( Voies.XY[:,0]),np.mean(Voies.XY[:,1] )), xycoords='data',color=colormax[i,: ])

        for i,C in enumerate(AllContours.list):
            if C.isexterior:
                plt.plot(C.X,C.Y,c='k')
            else:
                Pol=mpl.patches.Polygon(C.XY,color=(0.9,0.9,0.9))
                axes.add_patch(Pol)

        plt.axis('scaled')
        plt.show()

import numpy as np
from scipy.spatial import Voronoi

import matplotlib as mpl
import matplotlib.pyplot as plt
import pickle
import time
import shutil


def dirP(obj,nmax=10):
    """
    Description :    Gives all the attributes and values of an object
    Input :* Obj : the object you want to explore
           * nmax (optional):  is the number of elements you want to print from the attributes
    Output: None
    """
    for name in dir(obj):
        if(name[0]!='_'):
            ok=0
            val=eval('obj.'+name)
            if type(val) is int : ok=1
            else :
                try:
                    if str(val)[0]!='<': ok=1
                except BaseException:
                    print(name, " Methode locale")
            if ok:
                if type(val) is list :
                    print(name, (20-len(str(name)))*' ','is a list of size :', len(val),end='  ')
                    if len(val)<nmax : print(val)
                    else           :                         print(',',val[0:nmax] , '\n(',nmax,' first elements)')
                elif type(val) is np.ndarray :
                    print(name, (20-len(str(name)))*' ','is a list of size :', val.shape, end='  ')
                    if np.prod( val.shape )<nmax : print(val)
                    else : print(',')

                else :
                    print(name, (20-len(str(name)))*' ',val)

#########################
def seg_intersect(a1,a2, b1,b2) :
    da = a2-a1
    db = b2-b1
    dp = a1-b1
    dap = perp(da)
    denom = np.dot( dap, db)
    num = np.dot( dap, dp )
    return (num / denom.astype(float))*db + b1

def perp( a ) :
    b = np.empty_like(a)
    b[0] = -a[1]
    b[1] = a[0]
    return b

def ccw(A,B,C):
    return (C[1]-A[1]) * (B[0]-A[0]) > (B[1]-A[1]) * (C[0]-A[0])

def intersect(A,B,C,D):
    return ccw(A,C,D) != ccw(B,C,D) and ccw(A,B,C) != ccw(A,B,D)

def length(XY):
    return np.sqrt((np.roll(XY[:,0],-1)-XY[:,0])**2+(np.roll(XY[:,1],-1)-XY[:,1])**2)

def linemaison(coord1,coord2):
    l=int(max(abs(coord1[0]-coord2[0]),abs(coord1[1]-coord2[1])))+1
    X= np.zeros(l,dtype=np.int32)
    Y= np.zeros(l,dtype=np.int32)
    for i in range(l):
        X[i]=round(coord1[0]+(i/(l-1))*(coord2[0]-coord1[0]))
        Y[i]=round(coord1[1]+(i/(l-1))*(coord2[1]-coord1[1]))
    return X,Y

def curvature(XY):
    # Calcul de la courbure comme le rapport entre la différence de deux angles/pentes qui se suivent
    # sur la longueur parcourue de la courbe
    return angle(XY[:,0],XY[:,1])/length(XY)

def angle(x,y):
    Pente=np.arctan2((np.roll(y,-1)-y),( np.roll(x,-1)-x)) ## Angle with 0
    Ang=Pente-np.roll(Pente,1)  #Difference of angle
    Ang[Ang<-np.pi]+= 2*np.pi # Modulo
    Ang[Ang> np.pi]+=-2*np.pi # Modulo
    return (180/np.pi)*Ang

def dist(XY):
    return np.sum(np.sqrt( (XY[:-1,0]-XY[1 :,0])**2 +
                           (XY[:-1,1]-XY[1 :,1])**2 ))

#########################

################################################################################
################## IMAGE OPERATIONS ############################################
def reduceIMGsize(IMG):
    '''
    depreciated, too many bugs
    '''
    bordersize=0
    index=0
    while sum(IMG[index,:])==0: index+=1
    ymin=max(0,index-bordersize)

    index=len(IMG[:,0])-1
    while sum(IMG[index,:])==0: index-=1
    ymax=min(index-bordersize,   len(IMG[:,0])-1)

    index=0
    while sum(IMG[:,index])==0: index+=1
    xmin=max(0,index-bordersize)

    index=len(IMG[0,:])-1
    while sum(IMG[:,index])==0: index-=1
    xmax=min(len(IMG[0,:])-bordersize,index+1)
    return(xmin,xmax,ymin,ymax)

################################################################################
################### ARC CREATION ###############################################
################################################################################
def Voronoi_Clean(XY,IMG,p):
    """
    DESCRIPTION :
    	_Takes all the points from every contour, and generate every segments of the voronoi
    	diagram. It create points at mid-range between two contours, but also some useless one.
    	_The program set all the generated points outside of the figure to [0,0]
    	_It then suppress all segments which are linked to a point not in the figure (thanks to IMG)
    	_Then it suppress all segments not linked to 2 different contours
      _Then it reorganise information
    INPUT :
        * XY : All the coordinates of the contour points, with their label
        * IMG : Matrix of values =0 if not on the gorgonian !=O if on gorgonian
    OUTPUT :
        * Vertices all usefull points positions generated by the Voronoi diagram
        * Segments all association of points we keep
        * Nconect : number of points having the connectivity of Nconect label.
    WHAT NEED TO BE UPGRADED :
        * There is no real needs, although the is badly coded. It works.
    Coded by <NAME>. Last update 03/03/2017
    """
    t=time.time()
    print('Completing Voronoi Calculation...',end='')
    vorSkel=Voronoi(XY[:,0:2])

    #plt.figure('Hop')
    #plt.imshow(IMG.binary.T,cmap='binary')
    #plt.plot(vorSkel.vertices[:,0],vorSkel.Vertices[:,1],'*',c='k')
    #voronoi_plot_2d(vorSkel)
    #plt.show()
    print('Done, t=',time.time()-t)
    # vorSkel.vertices       All the points created
    # vorSkel.ridge_vertices All the segments created of vertices
    # vorSkel.ridge_points   Link between label of original points in voronoi and real one
    print('Introduced', len(vorSkel.ridge_vertices),'Ridges')
    t=time.time()
    print('Removing infinity/out of structure Ridges...',end='')

    #Vertices Cleaning : detect all potentially good points
    supprpts={}                                         # Dictionnary : if the point is associated to true, it will be suppressed.
    supprpts[-1]=True                                   # Suppress label for all points at infinity

    for i in range(len(vorSkel.vertices[:,0])):                 # We check every pointd
       if (0<vorSkel.vertices[i,0]<IMG.X and 0<vorSkel.vertices[i,1]<IMG.Y):
           if IMG.binary[int(vorSkel.vertices[i,0]),int(vorSkel.vertices[i,1])]==0:# If they are not on the structure
               supprpts[i]=True                            # We will delete them
       else:
           supprpts[i]=True
    # Creation of segments with only points on the structure
    nsegok=0 								# Number of segment "OK" I.E without values from supprpts
    for i, item in enumerate(vorSkel.ridge_vertices):  			# For every segment
        if not (supprpts.get(item[0],False) or supprpts.get(item[1],False)) : # If the first point will not be suppr
                nsegok+=1      					# We count this segment as kept


    Segments=np.zeros((nsegok,4))	# On fill Segments of : [IndexVertice1|IndexVertice2|IndexPoint1|IndexPoint2]
    index=0 								# Counter
    for i, item in enumerate(vorSkel.ridge_vertices): 			# We now add every segments, checking same conditions
        if not supprpts.get(item[0],False):
            if not supprpts.get(item[1],False):
                Segments[index,0:2]=item 			# The Vertices of the segment
                Segments[index,2:4]=vorSkel.ridge_points[i]  		# The points (Contour) linked to the segment
                index+=1

    print('Done, t=',time.time()-t)
    print('kept', nsegok,'Ridges')

    t=time.time()
    print('Removing Ridges only linked to one contours...',end='')
    # Segments cleaning : only the one created with two different labels contours
    nsegok=0 								# Number of segments associated to 2 different contours
    for i in range(len(Segments[:,0])): 			# For Every segments
        if XY[np.int(Segments[i,2]),3] != XY[np.int(Segments[i,3]),3]: #if the segment is created by 2 different contours
            nsegok+=1                                   # We count this segment as kept

    Keptseg=np.zeros((nsegok,4)) 						# We will only keep these segments
    item=0                          					# Position in keptseg
    for i in range(len(Segments[:,0])): 				# For every segments
        if XY[np.int(Segments[i,2]),3] != XY[np.int(Segments[i,3]),3]: # If it satisfy our previous condition
            Keptseg[item,0:2]=Segments[i,0:2]                   #We add it to the segment
            Keptseg[item,2  ]=XY[np.int(Segments[i,2]),2]
            Keptseg[item,3  ]=XY[np.int(Segments[i,3]),2]
            item+=1


    #Vertices cleaning
    Vertices2=np.zeros((len(vorSkel.vertices),4))       # |X|Y|Connectivity for each point | Label
    Vertices2[:,0:2]=vorSkel.vertices                   # We copy X and Y
    for i in range(len(Keptseg)):               # for each segment
        Vertices2[np.int(Keptseg[i,0]),2]+=1    # we add 1 in connectivity for every point taht compose him
        Vertices2[np.int(Keptseg[i,1]),2]+=1    # Same
    print('Done. t=',time.time()-t )

    t=time.time()
    print('Reattribution of labels...',end='')
    #We associate a label for every kept Vertice
    label=0
    for i in range(len(Vertices2)):
        if Vertices2[i,2]>=1:
            Vertices2[i,3]=label
            label+=1

    #We calculate the number of point having a certain connectivity
    i=0
    while (len(Vertices2[Vertices2[:,2]==i]) or i<3 ):  # double condition so we don't skip points if there is no dead end
        Nconect=np.zeros(i) 					# We now know the maximal connectivity
        i+=1
    Nconect=np.zeros(i)
    i=0
    while (len(Vertices2[Vertices2[:,2]==i]) or i<3 ):
        Nconect[i]=len(Vertices2[Vertices2[:,2]==i])    # We count the number of points with this connectivity
        i+=1


    VerticesKept=np.zeros((np.int(np.sum(Nconect[1::])),5)) # We recreate a vector with only the pooints we keep
    index=0
    for i in range(len(Vertices2)): 						# We look at every points
        if Vertices2[i,2]>0:        						# if we can keep it
            VerticesKept[index,0:4]=Vertices2[i,:] 			# We add it
            index+=1


    # Reattribution des labels
    Segments=1.0*Keptseg 							# We change all the lagbels
    for i in range(len(Segments[:,0])):				# For every segments
        Segments[i,0]=Vertices2[int(Keptseg[i,0]),3] 		# We give them the new label
        Segments[i,1]=Vertices2[int(Keptseg[i,1]),3]


    Vertices=np.zeros(( len(VerticesKept) , 4 )) #On renomme Vertices
    Vertices[:,0:3]=VerticesKept[:,0:3]
    Vertices[:,3  ]=VerticesKept[:,4]
    print('Done. t=',time.time()-t)

    #### TERMINAL PRINT ###################################################
    print("Finished with :",len(Vertices),'points et',len(Segments) ,'segments')
    print("number of point :")
    for i in range(1,len(Nconect)):
        print(int(Nconect[i]), 'of connectivity', i)

    """
    DESCRIPTION :
    	*This function creates arcs (associations of segments), by looking at all the association of segments
    	between 2 points of connectivity different of 2
    INPUT :
		* Vertices : array 		[X|Y] of every points
		* Segments : array    	All the 2 associations of points
		* Nconect  : list
		* Kmin 	   : float
		* IMG_DIST : 2D-Array 	with the distance to the closest border
    OUTPUT :
        * Arc 	   : List of list of Vertices
    WHAT NEED TO BE UPGRADED :
        * Dictionnary could help a lot
        * The system not to do the same arc twice also
    Coded by <NAME>. Last update 03/03/2017
    """
    ######### Get parameters values ##################
    Kmin=p.get('Kmin', 1.1)

    ##################################################

    print('Arc Creation...',end='')
    t=time.time()
    Noeuds   = np.zeros((len(Vertices[Vertices[:,2]>2]),2+len(Nconect)))   # Useless, but needed to generate Ptsdepart (badly coded)
    Arcs     = []                                                          # All the arcs
    PtsAssoc=np.zeros((len(Vertices[:,0]),len(Nconect)-1))-1               # All the points connected to the point
    Ptsdepart=0*Noeuds[:,0:len(Nconect)]      #Ensemble des points ayant une connectivité != reste 4 2, desquels on va reconstruire les arcs

    #At this time, I didn't know dictionnary
    for i in range(len(Segments[:,0])): # For every segments
        for j in range(2):              # We look at both points
            ok=0
            index=0
            while ok==0: 				# Yes the structure is weird but work
                if PtsAssoc[int(Segments[i,j]),index]==-1:             # if the case is free
                    PtsAssoc[int(Segments[i,j]),index]=Segments[i,1-j] #It place the coordinate of the other points
                    ok=1
                else: index+=1 # if the case is full we go to the next one


    #All the starting points
    wherepts=np.zeros((len(PtsAssoc[:,0]),2))
    index=0
    sumpts=0
    for i in range(len(PtsAssoc[:,0])): 				#We look at every points
        if PtsAssoc[i,2]!=-1:							#if their connectivity is different of 2
            Ptsdepart[index,0]=i 						#We add its label
            Ptsdepart[index,1::]=PtsAssoc[i,:] 			#We copy every points linked to it

            wherepts[i,0]=sumpts                  		#So we know at what point correspond what arc
            wherepts[i,1]=sumpts+Vertices[i,2]-1 #
            sumpts+=Vertices[i,2]

            index+=1


    #Creation des arcs
    numarcsuppr=0
    debutfin=np.zeros((len(Ptsdepart[Ptsdepart!=0])-len(Ptsdepart[:,0]),2)) #WIll contains every first and last point
    index=0
    for i in range(len(Ptsdepart[:,0])-1): 									#For each crossing
        pts=Ptsdepart[i,:]
        for j in range(1,len(pts[pts!=-1])): 								#For each point linked to it
            Ok=1
            #print(index,len(debutfin),i,len(Ptsdepart[:,0]))
            debutfin[index,0]=Ptsdepart[i,0] 								# We note the first point

            liste=[int(Ptsdepart[i,0])]      # We add the first point to the list
            actualpt=Ptsdepart[i,j]     	 # The point after (the one we are actually in fact)
            prvspt=Ptsdepart[i,0]       	 # The point before(the first one for the moment)
            while Ok:                   	 # While the point is not an end
                liste.append(int(actualpt))  #We add it

                if Vertices[int(actualpt),2]==2: #if the arc goes on
                    nextpt=PtsAssoc[int(actualpt)][0:2] #We find the next one
                    temp=actualpt                       #on a weird way BECAUSE I CODED IT VERY BAAAAAAD
                    actualpt=nextpt[nextpt!=prvspt][0]  #here it is
                    prvspt=temp                     # We refresh the previous point
                else:                               #If the point we are in is a crossroad or a dead end
                    Ok=0                            #We won't go further
                    debutfin[index,1]=actualpt      #We note this point in debutfin
                    index+=1                        #We will be on the next arc label
                    #WE NOW CHECK IF WE CAN KEEP IT !
                    dfselect=debutfin[int(wherepts[int(liste[-1]),0]):int(wherepts[int(liste[-1]),1])+1,1] #Comparaison entre les elements de fin et debut
                    if liste[0] not in dfselect: #if the arc is not already existing
                        if Vertices[int(actualpt),2]==1: #If last point is a dead end (and because of the splitsegment an artefact)
                            X0=Vertices[int(liste[ 0]) ,0]; Y0=Vertices[int(liste[ 0]) ,1]
                            X1=Vertices[int(liste[-1]) ,0]; Y1=Vertices[int(liste[-1]) ,1]
                            D=max(IMG.dist[int(X0),int(Y0)],IMG.dist[int(X1),int(Y1)]) #We check distances between ends of the arc
                                                                                       #And also the distance of theses point to the exterior
                            if np.sqrt( (X0-X1)**2 + (Y0-Y1)**2 ) > Kmin*D:               #if the arc is bg enough
                                Arcs.append(liste)                                        #We add it to the list
                            else:
                                numarcsuppr+=1
                        else:
                            Arcs.append(liste)

    print('Done. time=', time.time()-t)

    print('We created', len(Arcs), 'Arcs')
    print('We aborted the generation of', numarcsuppr, '"False" arcs')

    """
    DESCRIPTION :
    because of the splitting, some segments where not conserved during the arc creation
	in consequence some crossroads are not true crossroads, and some arcs should get a fusion.
	That's what we do here !
    INPUT :
    	*Arcs . We don't need anything else
    OUTPUT :
     * Arcs . But proper !
    WHAT NEED TO BE UPGRADED :
	* I think it's ok here
     * We could do a fusion of this and AssembleVoies
    Coded by <NAME>. Last update 03/03/2017
    """
    t=time.time()
    print('Arcs Regroupment...',end='')
    zoup=len(Arcs)
    #Get for every end-points the arcs connected to
    ArcsFirstlast=np.zeros((len(Arcs),2),dtype=np.int32)
    for i,elements in enumerate(Arcs):
        ArcsFirstlast[i,0:2]=[elements[0],elements[-1]]
    Ptsconnected={}
    for i,elements in enumerate(ArcsFirstlast):
        Dict1=Ptsconnected.get(elements[0], [])
        Dict2=Ptsconnected.get(elements[1], [])
        Ptsconnected[elements[0]]=Dict1+[i]
        Ptsconnected[elements[1]]=Dict2+[i]

    #Creation of the links 2 per 2
    Links=[]
    for pt,arcs in Ptsconnected.items():
        if len(arcs)==2:
            Links+=[[arcs[0],arcs[1]]]

    VoiesArcs=[] #arc 1, arc2...
    ArcsTrueConnected={}
    Arcsnumconnect={}
    for elements in Links:
        Dict1=ArcsTrueConnected.get(elements[0], [])
        Dict2=ArcsTrueConnected.get(elements[1], [])
        Dict3=Arcsnumconnect.get(elements[0], 0)
        Dict4=Arcsnumconnect.get(elements[1], 0)
        ArcsTrueConnected[elements[0]]=Dict1+[elements[1]]
        ArcsTrueConnected[elements[1]]=Dict2+[elements[0]]
        Arcsnumconnect[elements[0]]=Dict3+1
        Arcsnumconnect[elements[1]]=Dict4+1

    # Create streets
    dontbeginwithit={}
    for i in ArcsTrueConnected.keys(): #Pour tous les arcs
        Dict1=Arcsnumconnect.get(i, 0)
        Dict2=dontbeginwithit.get(i, False)
        if Dict1==1 and Dict2==False: #Si ils ne sont connecté qu'une fois, et pas encore utilisé
            Ok=0
            actualarcs=i
            nextarc=ArcsTrueConnected[i][0]
            ActualVoies=[i]
            while Ok==0:
                ActualVoies+=[nextarc]
                if len(ArcsTrueConnected[nextarc])==1:                               #Si le prochain arc est un bout
                    dontbeginwithit[ArcsTrueConnected[nextarc][0]]=True              #On empeche de pouvoir repartir avec
                    Ok=1
                    VoiesArcs+=[ActualVoies]
                else:
                    previous=actualarcs
                    actualarcs=nextarc
                    choice=ArcsTrueConnected[nextarc][:]
                    nextarc=list(set(choice+[previous])-set([previous]))[0]

    VoiesPts=[]
    for ArcAsso in VoiesArcs: #Pour chaque association
        First =ArcsFirstlast[ArcAsso[0]]
        Second=ArcsFirstlast[ArcAsso[1]]
        pts=Arcs[ArcAsso[0]]

        if First[1] in Second:
            ActualVoie=pts[:]
        if First[0] in Second:
            ActualVoie= pts[::-1]

        for Arc in ArcAsso[1:]:
            pts=[Arcs[Arc]][0]
            if pts[0]==ActualVoie[-1]:
                ActualVoie+=pts[1:]
            elif pts[-1]==ActualVoie[-1]:
                pts=pts[::-1]
                ActualVoie+=pts[1:]
        VoiesPts+=[ActualVoie]

    numsup=0
    for ArcAsso in VoiesArcs: #Pour chaque association
        for Arc in ArcAsso:
            Arcs[Arc]=[]
            numsup+=1

    Arcs+=VoiesPts
    Arcs2=[a for a in Arcs if len(a)!=0]

    print('Done. t=',time.time()-t)
    print('On a regroupé', zoup,'arcs en',len(Arcs2))

    return Vertices, Arcs2    ,Segments

def Arcs_nettoyage(B):
    B.sort(key=len)                                            # We sort it with the number of points (useless)
    for i,b in enumerate(B):
        if b[0]>b[-1]: B[i]=B[i][::-1]                         #Smallest elemnt first
    dic={}                                                    #List containing first element
    kept=[]                                                    #List of kept indexes
    for i,b in enumerate(B):                                   #Only keeping first list having the same first point
        if not dic.get(str(b[0])+' '+str(b[-1]),False):
            dic[str(b[0])+' '+str(b[-1])]=True
            kept.append(i)
    return np.array(B)[kept]

def removeuselesspoints(XY,delta):
    X=XY[:,0]
    Y=XY[:,1]
    Xkept=X[0:2]
    Ykept=Y[0:2]
    for x,y in zip(X[2:-1],Y[2:-1]):
        m = (Ykept[-1]-Ykept[-2])/(Xkept[-1]-Xkept[-2])
        p = Y[-1]-m*X[-1]
        if abs(m* x +  y +p)/np.sqrt(1 +m**2 ) > delta:
            Xkept=np.hstack((Xkept,x))
            Ykept=np.hstack((Ykept,y))
    Xkept=np.hstack((Xkept,X[-1]))
    Ykept=np.hstack((Ykept,Y[-1]))
    return(np.column_stack((Xkept,Ykept)))

def UpgradeArcsVoies(IMG,AllArcs,AllVoies):
    '''
    When Ways are defined, we can have the correct shape of the arc without soap effect
    '''
    print('Better points Arcs')
    for A in AllArcs.list:
        A.XYasVoies=np.zeros((len(A.XYNoPlace)+2,2))
        A.XYasVoies[1:-1,:]=A.XYNoPlace
        if not A.IsInaPlace:
            ### Premier point
            if A.FirstLink == ['Extremity']:### Si c'est une extremité
                if AllVoies.list[A.Usedinvoie].Arc[0]==A.index: A.XYasVoies[0,:] = AllVoies.list[A.Usedinvoie].XY[0,:]
                else:                                           A.XYasVoies[0,:] = AllVoies.list[A.Usedinvoie].XY[-1,:]


            else:### Si c'est un lien
                if (A.FirstLink[1]=='first' or A.FirstLink[1]=='First'): A.XYasVoies[0,:]=( A.XYNoPlace[0,:] + AllArcs.list[A.FirstLink[0]].XYNoPlace[ 0,:] )/2
                else:                                                    A.XYasVoies[0,:]=( A.XYNoPlace[0,:] + AllArcs.list[A.FirstLink[0]].XYNoPlace[-1,:] )/2

            ### Dernier point
            if A.LastLink == ['Extremity']:### Si c'est une extremité
                if AllVoies.list[A.Usedinvoie].Arc[0]==A.index:
                    if    (np.sqrt( ( AllVoies.list[A.Usedinvoie].XY[-1,0]-A.XYasVoies[-2,0]  )**2 +
                                    ( AllVoies.list[A.Usedinvoie].XY[-1,1]-A.XYasVoies[-2,1]  )**2 )
                        <  np.sqrt( ( AllVoies.list[A.Usedinvoie].XY[0,0] -A.XYasVoies[-2,0]  )**2 +
                                    ( AllVoies.list[A.Usedinvoie].XY[0,1] -A.XYasVoies[-2,1]  )**2 ) ):
                        A.XYasVoies[-1,:] = AllVoies.list[A.Usedinvoie].XY[-1,:]
                    else :A.XYasVoies[-1,:] = AllVoies.list[A.Usedinvoie].XY[ 0,:]
                else:     A.XYasVoies[-1,:] = AllVoies.list[A.Usedinvoie].XY[-1,:]


            else:### Si c'est un lien
                if (A.LastLink[1]=='first' or A.LastLink[1]=='First'): A.XYasVoies[-1,:]=(A.XYNoPlace[-1,:]+AllArcs.list[A.LastLink[0]].XYNoPlace[ 0,:])/2
                else:                                                  A.XYasVoies[-1,:]=(A.XYNoPlace[-1,:]+AllArcs.list[A.LastLink[0]].XYNoPlace[-1,:])/2

            A.XYasVoiesLight=removeuselesspoints(A.XYasVoies,IMG.X/100)
            A.Angle= np.arctan2(np.abs(A.XYasVoies[-1,1]-
                                          A.XYasVoies[0 ,1] ),
                                   np.abs(A.XYasVoies[-1,0]-
                                          A.XYasVoies[0 ,0]))
    print('Simpler points Voies')
    print(AllVoies)
    for j,V in enumerate(AllVoies.list):

            V.Vertices2 = np.vstack((a for a in [ AllArcs.list[V.Arc[i]].XYasVoies[::V.lecture[i]] for i,elem in enumerate(V.Arc)]))
    return AllArcs,AllVoies

###############################################################################
##################### LINK CREATION ###########################################
###############################################################################
def PreparePlaces(Arcs,p):
    '''
    We look at all the arcs, and create what will be their connections :
    1) We get all the extremities of every Arcs as label points. All of them are Keys in RoughPlace, their elements are the (arcs and side) connected
    2) For Every Arcs, we check if it's in a place. We connect both sides
    3) For Every Places created
    '''

    ### 1)
    ### we create the "Rough Places" : With all the Arcs which arrive to one of the place
    ### Link contains all the Rough Places belonging to the other
    RoughPlace={}
    Link=[]
    for i,Arc in enumerate(Arcs.list):

        D0=RoughPlace.get(Arc.First, []);D0+=[[i,'first']];RoughPlace[Arc.First]=D0
        D1=RoughPlace.get(Arc.Last , []);D1+=[[i,'last']] ;RoughPlace[Arc.Last ]=D1

        if Arc.IsInaPlace:
            Link+=[[Arc.First,Arc.Last]]

    ### 2)
    ### BiggerPlace : contains all the surrounding roughplaces linked
    BiggerPlace={}
    for L in Link:
        D0=BiggerPlace.get(L[0],[]);          D0+=[L[1]]       ;BiggerPlace[L[0]]=D0
        D1=BiggerPlace.get(L[1],[]);          D1+=[L[0]]       ;BiggerPlace[L[1]]=D1

    ### Placeused : if the roughplace has already been used in a Place
    PlacesArcs=RoughPlace.copy()
    PlacesCenters={}
    Explored={}

    ### Reproductive method
    for P in RoughPlace.keys(): #For every Places
        PlacesCenters[P]=[P]+BiggerPlace.get(P,[])                              #They contains themselves

    stay=True
    while stay:                                                                 #While We have still some place to make grow
        stay=False
        #print('First turn')
        #input()
        for P in PlacesCenters.keys():                                          #For everyplaces
            if (len(PlacesCenters[P])>1 and Explored.get(P,False)==False):              # If there is still some work to do
                #print(P,'##########')
                #print('La place',PlacesCenters[P])

                count=len(PlacesCenters[P])
                A=np.copy(PlacesCenters[P])
                for P2 in A:
                    if P2!=P:
                        PlacesCenters[P]+=PlacesCenters[P2]
                        #print(P2,PlacesCenters[P2])
                PlacesCenters[P]=list(set(PlacesCenters[P]))
                #print('Now',PlacesCenters[P])
                if len(PlacesCenters[P])==count:Explored[P]=True;#print('Finished!')
                else:stay=True
                #input()

    NewPlacesCenters={}
    NewPlacesArcs={}
    index=0
    alreadycopied={}
    for P in PlacesCenters.keys(): # For every Places
        if not alreadycopied.get(P,False): # If it hasn't been used
            NewPlacesCenters[index]=PlacesCenters[P]

            PArcs=[]
            for P2 in NewPlacesCenters[index]:
                alreadycopied[P2]=True
                PArcs+=PlacesArcs[P2]
            NewPlacesArcs[index]=PArcs
            index+=1

    return NewPlacesArcs,NewPlacesCenters

def prepareCriteria(IMG,P,AllArcs):
    '''
    Dictionnary of the criteria for each place
    '''
    P.Criteria= {}
    P.Criteria['D1']            = [None]*len(P.Potentiallink)
    P.Criteria['DCenter']       = [None]*len(P.Potentiallink)

    P.Criteria['inLen']         = [None]*len(P.Potentiallink)
    P.Criteria['inMinD']        = [None]*len(P.Potentiallink)
    P.Criteria['inVarD']        = [None]*len(P.Potentiallink)
    P.Criteria['inDintegrale']  = [None]*len(P.Potentiallink)
    P.Criteria['Ang12']         = [None]*len(P.Potentiallink)

    P.Criteria['Outlen']        = [None]*len(P.Potentiallink)
    P.Criteria['OutDintegrale'] = [None]*len(P.Potentiallink)

    P.Criteria['Ang1']          = [None]*len(P.Potentiallink)
    P.Criteria['Ang2']          = [None]*len(P.Potentiallink)

    P.Criteria['Rarc1']         = [None]*len(P.Potentiallink)
    P.Criteria['Rarc2']         = [None]*len(P.Potentiallink)

    P.Criteria['D1']            = [None]*len(P.Potentiallink)
    P.Criteria['D2']            = [None]*len(P.Potentiallink)

    for j,pl in enumerate(P.Potentiallink):
        # print('numéro de la place :'')
        ang1l,ang2l,ang12 = chooseptangle(pl,AllArcs)
        rr,cc=linemaison([int(pl[2][0]),int(pl[2][1])],[int(pl[5][0]),int(pl[5][1])])

        pt1,pt2=P.mulLen[j][0][0],P.mulLen[j][0][1]
        rr2,cc2=linemaison([int(pt1[0]),int(pt1[1])],[int(pt2[0]),int(pt2[1])])


        # CRITERE 0 : LA PLACE, LES TAILLES
        P.Criteria['D1'][j]             = IMG.dist[int(pl[2][0]),int(pl[2][1])]
        P.Criteria['D2'][j]             = IMG.dist[int(pl[5][0]),int(pl[5][1])]
        P.Criteria['DCenter'][j]       = np.amax([ IMG.dist[int(X[0]),int(X[1])] for X in P.XY ])
        P.Criteria['Rarc1'][j]          = AllArcs.list[pl[0]].Rmin
        P.Criteria['Rarc2'][j]          = AllArcs.list[pl[3]].Rmin

        # CRITERE 1 : LA COURBE DE REPARTITION DES DISTANCES INTERNES A LA PLACE
        P.Criteria['inLen'][j]         =  np.sqrt( (pl[2][0]-pl[5][0] )**2 + (pl[2][1]-pl[5][1] )**2 )

        P.Criteria['inMinD'][j]        =np.amin(IMG.dist[rr,cc])
        P.Criteria['inVarD'][j]        =np.amax(IMG.dist[rr,cc])-np.amin(IMG.dist[rr,cc])
        P.Criteria['inDintegrale'][j]  =np.sum(IMG.dist[rr,cc])

        # CRITERE 2 : LES ANGLES FORMEES
        P.Criteria['Ang12'][j]         =ang12
        P.Criteria['Ang1'][j]          =ang1l
        P.Criteria['Ang2'][j]          =ang2l

        # CRITERE 3 : LA LONGUEUR QUI SORT DE LA PLACE
        # VALEUR DE BASE
        # VALEUR INTEGREE
        P.Criteria['Outlen']       [j]= np.sqrt((pt2[0]-pt1[0] )**2 + (pt2[1]-pt1[1] )**2 )
        P.Criteria['OutDintegrale'][j]= np.sum(IMG.dist[rr2,cc2])
    return( P.Criteria)

def PrepareScore(IMG,AllArcs,AllPlaces,p):
    for i,Place in enumerate(AllPlaces.list):#For each place with more than one arc
        if len(Place.Arcs)>1:
            problem=False
            index=0
            AllPlaces.list[i].mulLen        = [] #Lengths over the place
            AllPlaces.list[i].Potentiallink = [] #Geometric characteristics
            AllPlaces.list[i].Potentialscore= [] #Interior ability to go inside a place

            # WE ADD THE DIFFERENTS ELEMENTS, COMPARING ALL THE DIFFERENT POSSIBILITIES
            for j,Arc in enumerate(Place.Arcs):
                for k,Arc2 in enumerate(Place.Arcs[j+1:]) :
                    # potentiallink : |Arc1Label|Arc1Extremity|Arc1Pt|Arc2Label|Arc2Extremity|Arc2Pt|

                    # FIRST ARC
                    LIST=[];
                    LIST.append( Arc [0] )
                    LIST.append( Arc [1] )
                    if p.get('refereepoint',False):
                        if Arc [1]=='first': LIST.append( [AllArcs.list[Arc [0]].FirstReferee[0], AllArcs.list[Arc [0]].FirstReferee[1]] )
                        else               : LIST.append( [AllArcs.list[Arc [0]].LastReferee [0], AllArcs.list[Arc [0]].LastReferee [1]] )
                    else:
                        if Arc [1]=='first': LIST.append( [AllArcs.list[Arc [0]].XYNoPlace[ 0,0], AllArcs.list[Arc [0]].XYNoPlace[ 0,1]] )
                        else               : LIST.append( [AllArcs.list[Arc [0]].XYNoPlace[-1,0], AllArcs.list[Arc [0]].XYNoPlace[-1,1]] )

                    # SECOND ARC
                    LIST.append( Arc2[0] )
                    LIST.append( Arc2[1] )
                    if p.get('refereepoint',False):
                        if Arc2[1]=='first': LIST.append( [AllArcs.list[Arc2[0]].FirstReferee[0], AllArcs.list[Arc2[0]].FirstReferee[1]] )
                        else               : LIST.append( [AllArcs.list[Arc2[0]].LastReferee [0], AllArcs.list[Arc2[0]].LastReferee [1]] )
                    else:
                        if Arc2[1]=='first': LIST.append( [AllArcs.list[Arc2[0]].XYNoPlace[ 0,0], AllArcs.list[Arc2[0]].XYNoPlace[ 0,1]] )
                        else :               LIST.append( [AllArcs.list[Arc2[0]].XYNoPlace[-1,0], AllArcs.list[Arc2[0]].XYNoPlace[-1,1]] )
                    #print(LIST)
                    #print(i,j,k,LIST)
                    if (LIST[2][0]!=LIST[5][0] and LIST[2][1]!=LIST[5][1]):
                        rr,cc=linemaison([int(LIST[2][0]),
                                          int(LIST[2][1])],
                                         [int(LIST[5][0]),
                                          int(LIST[5][1])])
                        score =  min(IMG.dist[rr,cc])
                    else : score=0

                    index+=1
                    if score!=0:
                        AllPlaces.list[i].mulLen        .append(lengthprolongation(LIST[2],LIST[5],IMG,p.get('delta',0)))
                        AllPlaces.list[i].Potentialscore.append(score)
                        AllPlaces.list[i].Potentiallink .append(LIST)

            ### Creation du dictionnaire des criteres
            Place.Criteria=prepareCriteria(IMG,Place,AllArcs)
    return(AllPlaces)

def lengthprolongation(pt1,pt2,IMG,delta):
    mulLen=[]

    pt01=np.array([pt1[0],pt1[1]])
    pt02=np.array([pt2[0],pt2[1]])
    #print(pt01,pt02)
    D1=IMG.dist[int(pt01[0]),int(pt01[1])]
    D2=IMG.dist[int(pt02[0]),int(pt02[1])]

    if delta:
        L1= [pt01,
             pt01+np.array(-D1/delta,-D1/delta),
             pt01+np.array(-D1/delta,+D1/delta),
             pt01+np.array(+D1/delta,-D1/delta),
             pt01+np.array(+D1/delta,+D1/delta)]
        L2= [pt02,
             pt02+np.array(-D2/delta,-D2/delta),
             pt02+np.array(-D2/delta,+D2/delta),
             pt02+np.array(+D2/delta,-D2/delta),
             pt02+np.array(+D2/delta,+D2/delta)]
    else :
        L1=[pt01]
        L2=[pt02]

    for pt1 in L1:
        for pt2 in L2:
            try :
                D1=IMG.dist[int(pt1[0]),int(pt1[1])]
                D2=IMG.dist[int(pt2[0]),int(pt2[1])]
                L =np.sqrt( (pt1[0]-pt2[0])**2+  (pt1[1]-pt2[1])**2 )

                Disttot1=np.copy(D1)
                Disttot2=np.copy(D2)
                pre1=np.copy(pt1)
                pre2=np.copy(pt2)

                while 1:
                    pre1=pt1-(pt2-pt1)*Disttot1/L
                    newdist=IMG.dist[int(pre1[0]),int(pre1[1])]
                    Disttot1+=newdist
                    if newdist==0: break
                while 2:
                    pre2=pt2+(pt2-pt1)*Disttot2/L
                    newdist=IMG.dist[int(pre2[0]),int(pre2[1])]
                    Disttot2+=newdist
                    if newdist==0: break
                mulLen.append([pre1,pre2])
            except BaseException:
                mulLen.append([pt1,pt2])
                print('MultilenMarchePas')
    return mulLen

def LinkByScore(IMG,AllArcs,AllPlaces,p):
    Al = AllArcs.list
    Pl = AllPlaces.list
    crit=p['crit']
    for i,P in enumerate(AllPlaces.list):#For each place with more than one arc
        Plk=P.Potentiallink
        if len(P.Potentiallink)>=1:


            ### Print of criterias
            '''
            for j,key  in enumerate(['D1','D2','DCenter','Rarc1','Rarc2',
                                     'inLen','inMinD','inVarD','inDintegrale',
                                     'Outlen','OutDintegrale',
                                     'Ang1','Ang2','Ang12']):
                if j in [0,5,9,11]: print('-'*15+(1+len(P.Criteria[key]))*'-'*6)
                print(key+ (15-len(key))*' ',end='')
                for p in P.Criteria[key]:
                    print(np.round(p,3),(6-len(str(np.round(p,3))))*' ',end='')
                print('')
            print('Place number :',i)
            print('Number of arcs :',len(P.Arcs))
            print('Number of valid associations :',len(P.Potentiallink))
            '''


            ############### CREATION DU SCORE ######################################
            #if p['ScoreMode'] == '+' : score = np.sum(np.array([ np.array(P.Criteria[key])*val for key,val in p['coeffs'].items()]).reshape(-1,len(P.Potentiallink)),axis=1)
            #if p['ScoreMode'] == '*' : score = np.prod(np.array([ np.array(P.Criteria[key])**val for key,val in p['coeffs'].items()]).reshape(-1,len(P.Potentiallink)),axis=1)
            #print(np.array(P.Criteria['Outlen']))

            #print(crit)
            score , Plk = zip(*sorted(zip( np.array(P.Criteria[crit]), Plk )))
            score=score[::-1]
            Plk=Plk[::-1]


            # We scan the list, add the links we wants
            if  Plk[0][1]=='first': Al[ Plk[0][0] ].FirstLink=Plk[0][3:5]
            else                  : Al[ Plk[0][0] ]. LastLink=Plk[0][3:5]
            if  Plk[0][4]=='first': Al[ Plk[0][3] ].FirstLink=Plk[0][0:2]
            else                  : Al[ Plk[0][3] ]. LastLink=Plk[0][0:2]
            P.Links.append([Plk[0][0],Plk[0][3],Plk[0][1],Plk[0][4]])

            # We check for every Arcs, if it has no Link on the side we want, we add an extremity
            for j,Arc in enumerate(P.Arcs) :
                if ( Arc[1]=='first'  and len(Al[Arc[0]].FirstLink)==1 ):P.Extremities.append([Arc[0],'First'])
                if ( Arc[1]=='last'   and len(Al[Arc[0]].LastLink) ==1 ):P.Extremities.append([Arc[0],'Last'])
    return AllArcs,AllPlaces

def chooseptangle(pl,AllArcs):
    if pl[1].lower()=='first':
        pt1 = AllArcs.list[pl[0]].FirstReferee
        pt2 = AllArcs.list[pl[0]].LastXY
    else :
        pt1 = AllArcs.list[pl[0]].FirstXY
        pt2 = AllArcs.list[pl[0]].LastReferee

    if pl[4].lower()=='first':
        pt3 = AllArcs.list[pl[3]].FirstReferee
        pt4 = AllArcs.list[pl[3]].LastXY
    else :
        pt3 = AllArcs.list[pl[3]].FirstXY
        pt4 = AllArcs.list[pl[3]].LastReferee
    ang1 =np.abs((np.arctan2(pt2[1] - pt1[1], pt2[0] - pt1[0]) - np.arctan2(pt3[1] - pt2[1], pt3[0] - pt2[0]))%np.pi) # droite1-link
    ang2 =np.abs((np.arctan2(pt4[1] - pt3[1], pt4[0] - pt4[0]) - np.arctan2(pt3[1] - pt2[1], pt3[0] - pt2[0]))%np.pi) # droite2-link
    ang3 =np.abs((np.arctan2(pt4[1] - pt3[1], pt4[0] - pt3[0]) - np.arctan2(pt2[1] - pt1[1], pt2[0] - pt1[0]))%np.pi) # droite1-droite2
    return ang1,ang2,ang3




























###############################################################################
##################### CHECKS OF THE RESULTS ###################################
###############################################################################

def AllCheckings(IMG,AllContours,AllArcs,AllPlaces,AllVoies,p,k=False):
    if not k : k=input('What do you want to check ?\n 0 : image binarisation \n 1 : are contours artefacts \n 2 : what points are in arcs \n 3 : what places are together \n 4 : what Ways are created\n')
    import matplotlib.pylab as pl
    from matplotlib.collections import LineCollection
    import random
    if k=='0':
        plt.figure("Checking Image",figsize=(10,10))
        plt.title('Binary image')
        plt.imshow(IMG.binary,cmap='binary')
        plt.axis('scaled')
        plt.show()



    if k=='1':
        plt.figure("Checking artefacts",figsize=(10,10))
        ax=plt.gca()
        for C in AllContours.list:
            if C.artefact:
                plt.plot(C.X,C.Y,'*',color='red')
                Pol=mpl.patches.Polygon(C.XY,color='red')
                ax.add_patch(Pol)
                print('ARTEFACT',np.mean(C.XY[:,0]),np.mean(C.XY[:,1]))
            elif C.isexterior:
                plt.plot(C.X,C.Y,c='k')
            else:
                Pol=mpl.patches.Polygon(C.XY,color='blue')
                ax.add_patch(Pol)
        plt.show()


    if k=='2':
        Lines_Arcs=[]

        for A in AllArcs.list:
            Lines_Arcs+=list(zip(list(zip(A.XY[0:-1,0],A.XY[0:-1,1]))
                                ,list(zip(A.XY[1:  ,0],A.XY[1:  ,1]))))

        plt.figure("Checking artefacts",figsize=(10,10))
        ax=plt.gca()
        ax.add_collection(LineCollection(Lines_Arcs,color='k',linewidth=2))

        colormax  = pl.cm.jet( np.linspace(0,1,1+AllContours.ncontours ) )
        for i,C in enumerate(AllContours.list):
            if C.isexterior:
                plt.plot(C.X,C.Y,c='k')
            else:
                Pol=mpl.patches.Polygon(C.XY,color=colormax[int(random.random()*AllContours.ncontours),:])
                ax.add_patch(Pol)
        plt.xlim([0,IMG.X])
        plt.ylim([0,IMG.Y])
        plt.show()

    if k=='3':
        fx=p.get('fx',10)
        fy=p.get('fy',10)

        plt.figure('ArcsPlaces',figsize=(fx,fy))
        plt.imshow(IMG.binary.T,cmap='binary')
        axes = plt.gca()
        '''
        Lines_Arcs=[]
        for A in AllArcs.list:
            Lines_Arcs+=list(zip(list(zip(A.XY[0:-1,0],A.XY[0:-1,1]))
                                ,list(zip(A.XY[1:  ,0],A.XY[1:  ,1]))))
        axes.add_collection(LineCollection(Lines_Arcs,color='k',linewidth=1))
        '''
        colormax  = pl.cm.jet( np.linspace(0,1,1+len(AllPlaces.list)) )
        for i,Place in enumerate(AllPlaces.list):
            for j in range(len(Place.Centers)):
                plt.plot(Place.XY[j,0],Place.XY[j,1],'*',c='k')
                Pol=mpl.patches.Circle((Place.XY[j,0],Place.XY[j,1]),Place.Radius[j]  ,color=colormax[i,:]  )
                axes.add_patch(Pol)
            for arc in Place.ArcsInside:
                plt.plot(AllArcs.list[arc].XY[:,0],AllArcs.list[arc].XY[:,1],color='r')

        plt.axis('scaled')
        plt.show()

    if k=='4':

        fx=p.get('fx',10)
        fy=p.get('fy',10)
        plt.figure('Voies',figsize=(fx,fy))
        axes = plt.gca()
        colormax  = pl.cm.jet( np.linspace(0,1,1+len(AllVoies.list)) )
        for i,Voies in enumerate(AllVoies.list):
            plt.plot(Voies.XY[:,0],Voies.XY[:,1],color=colormax[i,:])
            #for A in Voies.Arc:
            #    plt.plot(AllArcs.list[A].XY[:,0],AllArcs.list[A].XY[:,1],color=colormax[i,:])
            #if len(Voies.XY[:,0]==1):
            #    plt.plot(Voies.XY[:,0],Voies.XY[:,1],'*',color=colormax[i,:])
            #axes.annotate(i,xy=(np.mean( Voies.XY[:,0]),np.mean(Voies.XY[:,1] )), xycoords='data',color=colormax[i,: ])

        for i,C in enumerate(AllContours.list):
            if C.isexterior:
                plt.plot(C.X,C.Y,c='k')
            else:
                Pol=mpl.patches.Polygon(C.XY,color=(0.9,0.9,0.9))
                axes.add_patch(Pol)

        plt.axis('scaled')
        plt.show()

Description :    Gives all the attributes and values of an object     Input :* Obj : the object you want to explore            * nmax (optional):  is the number of elements you want to print from the attributes     Output: None ######################### # Calcul de la courbure comme le rapport entre la différence de deux angles/pentes qui se suivent # sur la longueur parcourue de la courbe ## Angle with 0 #Difference of angle # Modulo # Modulo ######################### ################################################################################ ################## IMAGE OPERATIONS ############################################ depreciated, too many bugs ################################################################################ ################### ARC CREATION ############################################### ################################################################################ DESCRIPTION :     	_Takes all the points from every contour, and generate every segments of the voronoi     	diagram. It create points at mid-range between two contours, but also some useless one.     	_The program set all the generated points outside of the figure to [0,0]     	_It then suppress all segments which are linked to a point not in the figure (thanks to IMG)     	_Then it suppress all segments not linked to 2 different contours       _Then it reorganise information     INPUT :         * XY : All the coordinates of the contour points, with their label         * IMG : Matrix of values =0 if not on the gorgonian !=O if on gorgonian     OUTPUT :         * Vertices all usefull points positions generated by the Voronoi diagram         * Segments all association of points we keep         * Nconect : number of points having the connectivity of Nconect label.     WHAT NEED TO BE UPGRADED :         * There is no real needs, although the is badly coded. It works.     Coded by <NAME>. Last update 03/03/2017 #plt.figure('Hop') #plt.imshow(IMG.binary.T,cmap='binary') #plt.plot(vorSkel.vertices[:,0],vorSkel.Vertices[:,1],'*',c='k') #voronoi_plot_2d(vorSkel) #plt.show() # vorSkel.vertices       All the points created # vorSkel.ridge_vertices All the segments created of vertices # vorSkel.ridge_points   Link between label of original points in voronoi and real one #Vertices Cleaning : detect all potentially good points # Dictionnary : if the point is associated to true, it will be suppressed. # Suppress label for all points at infinity # We check every pointd # If they are not on the structure # We will delete them # Creation of segments with only points on the structure # Number of segment "OK" I.E without values from supprpts # For every segment # If the first point will not be suppr # We count this segment as kept # On fill Segments of : [IndexVertice1|IndexVertice2|IndexPoint1|IndexPoint2] # Counter # We now add every segments, checking same conditions # The Vertices of the segment # The points (Contour) linked to the segment # Segments cleaning : only the one created with two different labels contours # Number of segments associated to 2 different contours # For Every segments #if the segment is created by 2 different contours # We count this segment as kept # We will only keep these segments # Position in keptseg # For every segments # If it satisfy our previous condition #We add it to the segment #Vertices cleaning # |X|Y|Connectivity for each point | Label # We copy X and Y # for each segment # we add 1 in connectivity for every point taht compose him # Same #We associate a label for every kept Vertice #We calculate the number of point having a certain connectivity # double condition so we don't skip points if there is no dead end # We now know the maximal connectivity # We count the number of points with this connectivity # We recreate a vector with only the pooints we keep # We look at every points # if we can keep it # We add it # Reattribution des labels # We change all the lagbels # For every segments # We give them the new label #On renomme Vertices #### TERMINAL PRINT ################################################### DESCRIPTION :     	*This function creates arcs (associations of segments), by looking at all the association of segments     	between 2 points of connectivity different of 2     INPUT : 		* Vertices : array 		[X|Y] of every points 		* Segments : array    	All the 2 associations of points 		* Nconect  : list 		* Kmin 	   : float 		* IMG_DIST : 2D-Array 	with the distance to the closest border     OUTPUT :         * Arc 	   : List of list of Vertices     WHAT NEED TO BE UPGRADED :         * Dictionnary could help a lot         * The system not to do the same arc twice also     Coded by <NAME>. Last update 03/03/2017 ######### Get parameters values ################## ################################################## # Useless, but needed to generate Ptsdepart (badly coded) # All the arcs # All the points connected to the point #Ensemble des points ayant une connectivité != reste 4 2, desquels on va reconstruire les arcs #At this time, I didn't know dictionnary # For every segments # We look at both points # Yes the structure is weird but work # if the case is free #It place the coordinate of the other points # if the case is full we go to the next one #All the starting points #We look at every points #if their connectivity is different of 2 #We add its label #We copy every points linked to it #So we know at what point correspond what arc # #Creation des arcs #WIll contains every first and last point #For each crossing #For each point linked to it #print(index,len(debutfin),i,len(Ptsdepart[:,0])) # We note the first point # We add the first point to the list # The point after (the one we are actually in fact) # The point before(the first one for the moment) # While the point is not an end #We add it #if the arc goes on #We find the next one #on a weird way BECAUSE I CODED IT VERY BAAAAAAD #here it is # We refresh the previous point #If the point we are in is a crossroad or a dead end #We won't go further #We note this point in debutfin #We will be on the next arc label #WE NOW CHECK IF WE CAN KEEP IT ! #Comparaison entre les elements de fin et debut #if the arc is not already existing #If last point is a dead end (and because of the splitsegment an artefact) #We check distances between ends of the arc #And also the distance of theses point to the exterior #if the arc is bg enough #We add it to the list DESCRIPTION :     because of the splitting, some segments where not conserved during the arc creation 	in consequence some crossroads are not true crossroads, and some arcs should get a fusion. 	That's what we do here !     INPUT :     	*Arcs . We don't need anything else     OUTPUT :      * Arcs . But proper !     WHAT NEED TO BE UPGRADED : 	* I think it's ok here      * We could do a fusion of this and AssembleVoies     Coded by <NAME>. Last update 03/03/2017 #Get for every end-points the arcs connected to #Creation of the links 2 per 2 #arc 1, arc2... # Create streets #Pour tous les arcs #Si ils ne sont connecté qu'une fois, et pas encore utilisé #Si le prochain arc est un bout #On empeche de pouvoir repartir avec #Pour chaque association #Pour chaque association # We sort it with the number of points (useless) #Smallest elemnt first #List containing first element #List of kept indexes #Only keeping first list having the same first point When Ways are defined, we can have the correct shape of the arc without soap effect ### Premier point ### Si c'est une extremité ### Si c'est un lien ### Dernier point ### Si c'est une extremité ### Si c'est un lien ############################################################################### ##################### LINK CREATION ########################################### ############################################################################### We look at all the arcs, and create what will be their connections :     1) We get all the extremities of every Arcs as label points. All of them are Keys in RoughPlace, their elements are the (arcs and side) connected     2) For Every Arcs, we check if it's in a place. We connect both sides     3) For Every Places created ### 1) ### we create the "Rough Places" : With all the Arcs which arrive to one of the place ### Link contains all the Rough Places belonging to the other ### 2) ### BiggerPlace : contains all the surrounding roughplaces linked ### Placeused : if the roughplace has already been used in a Place ### Reproductive method #For every Places #They contains themselves #While We have still some place to make grow #print('First turn') #input() #For everyplaces # If there is still some work to do #print(P,'##########') #print('La place',PlacesCenters[P]) #print(P2,PlacesCenters[P2]) #print('Now',PlacesCenters[P]) #print('Finished!') #input() # For every Places # If it hasn't been used Dictionnary of the criteria for each place # print('numéro de la place :'') # CRITERE 0 : LA PLACE, LES TAILLES # CRITERE 1 : LA COURBE DE REPARTITION DES DISTANCES INTERNES A LA PLACE # CRITERE 2 : LES ANGLES FORMEES # CRITERE 3 : LA LONGUEUR QUI SORT DE LA PLACE # VALEUR DE BASE # VALEUR INTEGREE #For each place with more than one arc #Lengths over the place #Geometric characteristics #Interior ability to go inside a place # WE ADD THE DIFFERENTS ELEMENTS, COMPARING ALL THE DIFFERENT POSSIBILITIES # potentiallink : |Arc1Label|Arc1Extremity|Arc1Pt|Arc2Label|Arc2Extremity|Arc2Pt| # FIRST ARC # SECOND ARC #print(LIST) #print(i,j,k,LIST) ### Creation du dictionnaire des criteres #print(pt01,pt02) #For each place with more than one arc ### Print of criterias for j,key  in enumerate(['D1','D2','DCenter','Rarc1','Rarc2',                                      'inLen','inMinD','inVarD','inDintegrale',                                      'Outlen','OutDintegrale',                                      'Ang1','Ang2','Ang12']):                 if j in [0,5,9,11]: print('-'*15+(1+len(P.Criteria[key]))*'-'*6)                 print(key+ (15-len(key))*' ',end='')                 for p in P.Criteria[key]:                     print(np.round(p,3),(6-len(str(np.round(p,3))))*' ',end='')                 print('')             print('Place number :',i)             print('Number of arcs :',len(P.Arcs))             print('Number of valid associations :',len(P.Potentiallink)) ############### CREATION DU SCORE ###################################### #if p['ScoreMode'] == '+' : score = np.sum(np.array([ np.array(P.Criteria[key])*val for key,val in p['coeffs'].items()]).reshape(-1,len(P.Potentiallink)),axis=1) #if p['ScoreMode'] == '*' : score = np.prod(np.array([ np.array(P.Criteria[key])**val for key,val in p['coeffs'].items()]).reshape(-1,len(P.Potentiallink)),axis=1) #print(np.array(P.Criteria['Outlen'])) #print(crit) # We scan the list, add the links we wants # We check for every Arcs, if it has no Link on the side we want, we add an extremity # droite1-link # droite2-link # droite1-droite2 ############################################################################### ##################### CHECKS OF THE RESULTS ################################### ############################################################################### Lines_Arcs=[]         for A in AllArcs.list:             Lines_Arcs+=list(zip(list(zip(A.XY[0:-1,0],A.XY[0:-1,1]))                                 ,list(zip(A.XY[1:  ,0],A.XY[1:  ,1]))))         axes.add_collection(LineCollection(Lines_Arcs,color='k',linewidth=1)) #for A in Voies.Arc: #    plt.plot(AllArcs.list[A].XY[:,0],AllArcs.list[A].XY[:,1],color=colormax[i,:]) #if len(Voies.XY[:,0]==1): #    plt.plot(Voies.XY[:,0],Voies.XY[:,1],'*',color=colormax[i,:]) #axes.annotate(i,xy=(np.mean( Voies.XY[:,0]),np.mean(Voies.XY[:,1] )), xycoords='data',color=colormax[i,: ])