1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186
| Option Explicit
Const N As Byte = 3
Dim Sh As Worksheet
Dim Tb As Variant
Dim T As Double
Sub TRAITEMENT()
Dim LastLig As Long, Nb As Long
T = Timer
'Création d'une feuille temporaire et y copie les colonnes B, H et I à partir de la feuille BD
Set Sh = ThisWorkbook.Worksheets.Add
With ThisWorkbook.Worksheets("BD")
LastLig = .Cells(.Rows.Count, 2).End(xlUp).Row
Union(.Range("B5:B" & LastLig), .Range("H5:I" & LastLig)).Copy Sh.Range("A1")
End With
'Nb: nombre de données (nombre de points)
Nb = LastLig - 5
With Sh
'On tri les données an prenant la latitude la plus grande
.Range("A2:C" & Nb + 1).Sort Key1:=.Range("B2"), Order1:=xlDescending, Header:=xlNo
'On refait un tri des données par ordre croissant des distances à partir du point 1
'Appel à la procédure TRIER ci-après
TRIER 2, Nb
'On applique le traitement au tableau (procédures ci-après)
Tb = .Range("A2:C" & Nb + 1)
PARCOURS Nb
.Range("A2:C" & Nb + 1) = Tb
Erase Tb
'Après traitement, on importe la population de chaque point
With .Range("D2:D" & Nb + 1)
.Formula = "=VLOOKUP(A2,BD!$B$6:$L$" & LastLig & ",11,FALSE)"
.Value = .Value
End With
'on fait le regroupement des points selon la population globale
Tb = .Range("A2:E" & Nb + 1)
CLASSEMENT Nb
.Range("A2:E" & Nb + 1) = Tb
End With
'on réinjecte le groupement dans la feuille BD
With ThisWorkbook.Worksheets("BD").Range("M6:M" & LastLig)
.Formula = "=VLOOKUP(B6,'" & Sh.Name & "'!$A$2:$E$" & Nb + 1 & ",5,false)"
.Value = .Value
End With
'Eventuellement on supprime la feuille temporaire
'Application.DisplayAlerts = False
'Sh.Delete
'Application.DisplayAlerts = True
Set Sh = Nothing
MsgBox "optimisation terminée en " & Format(TimeSerial(0, 0, Timer - T), "hh:mm:ss")
End Sub
'procédure qui permet de refaire l'inversion de l'ordre des point tant que la permutation permet de diminuer
'la distance total du parcours (Cf fonction DIFF_2OPT)
Private Sub PARCOURS(ByVal Nb As Integer)
Dim p As Integer, q As Integer
Dim Modif As Boolean
Dim Ind As Byte
Do
Modif = False
Ind = Ind + 1
For p = 2 To Nb - 1
For q = p + 1 To Nb
If DIFF_2OPT(p, q, Nb) < 0 Then
RENVERSE p, q
Modif = True
Application.StatusBar = "Traitement en cours... Passage " & Ind & " : " & p & " et " & q & " " & Format(TimeSerial(0, 0, Timer - T), "hh:mm:ss")
End If
DoEvents
Next q
Next p
Loop Until Not Modif
Application.StatusBar = False
End Sub
'Procédure permetant de trier les points d'un échantillon de Nb points
'en prenant comme critère la distance de chaque point par rapport au point k
Private Sub TRIER(ByVal k As Integer, ByVal Nb As Integer)
Dim m As Integer
With Sh
Tb = .Range("A" & k & ":C" & Nb + 1)
For m = k To Nb + 1
With .Range("D" & m)
.Formula = "=Distance(" & k - 1 & "," & m - 1 & ")"
.Value = .Value
End With
Next m
.Range("A" & k & ":D" & Nb + 1).Sort Key1:=.Range("D" & k), Order1:=xlAscending, Header:=xlNo
.Range("D" & k & ":D" & Nb + 1).ClearContents
End With
End Sub
'procédure qui permet le regroupement des points successifs
'en respactant que la population globale =>15000 et >160000
Private Sub CLASSEMENT(ByVal Nb As Integer)
Dim i As Integer, Indx As Integer
Dim T As Long
Indx = 1
For i = 1 To Nb
T = T + Tb(i, 4)
Tb(i, 5) = "Groupe_" & Indx
If T >= 15000 Then
If T < 16000 Then
Indx = Indx + 1
T = 0
Else
T = Tb(i, 4)
End If
End If
Next i
End Sub
'Fonction qui permet de claculer la distances entre 2 points i et j
'connaissant les latitudes et longitudes respectives de i et j
Function DISTANCE(ByVal i As Integer, ByVal j As Integer) As Double
Dim Lat1 As Double, Lat2 As Double, Lon1 As Double, Lon2 As Double
Const R As Integer = 6371 ' de la terre, en km
Lat1 = DEG2RAD(Tb(i, 2))
Lon1 = DEG2RAD(Tb(i, 3))
Lat2 = DEG2RAD(Tb(j, 2))
Lon2 = DEG2RAD(Tb(j, 3))
' Calcul
DISTANCE = WorksheetFunction.Acos((Sin(Lat1) * Sin(Lat2)) + (Cos(Lat1) * Cos(Lat2) * Cos(Lon1 - Lon2))) * R
End Function
' Fonction qui convertit les degrés en radians
Private Function DEG2RAD(ByVal Dg As Double) As Double
Dim pPi As Double
pPi = Application.WorksheetFunction.Pi()
DEG2RAD = Dg / 180 * pPi
End Function
'Permute les points i et j (dans notre cas on permute respctivement le N°, la latitude et la longitude de i et j)
Private Sub PERMUTE(ByVal i As Integer, ByVal j As Integer)
Dim Tmp(1 To N) As Variant
Dim y As Byte
If i <> j Then
For y = 1 To N
Tmp(y) = Tb(i, y)
Tb(i, y) = Tb(j, y)
Tb(j, y) = Tmp(y)
Next y
End If
End Sub
'Renverse le parcours entre les villes i et j
Private Sub RENVERSE(ByVal i As Integer, ByVal j As Integer)
Dim a As Integer, b As Integer
a = Application.Min(i, j)
b = Application.Max(i, j)
Do While a < b
PERMUTE a, b
a = a + 1
b = b - 1
DoEvents
Loop
End Sub
'Différence de la distance du parcours si on renversait les villes i et j
Private Function DIFF_2OPT(ByVal i As Integer, ByVal j As Integer, ByVal Nb As Integer) As Double
Dim d As Double
If i < j Then
d = DISTANCE(i - 1, j) - DISTANCE(i - 1, i)
If j < Nb Then d = d + DISTANCE(i, j + 1) - DISTANCE(j, j + 1)
DIFF_2OPT = d
End If
End Function |
Partager