2-opt for map, ui update

Brian [2016-07-31 11:00:20]
2-opt for map, ui update

- 2 opt for map, more efficient path finding
- ui update, added a place for later features
Filename
PokemonGo/RocketAPI/Window/MainForm.Designer.cs
PokemonGo/RocketAPI/Window/MainForm.cs
PokemonGo/RocketAPI/Window/PokemonGo.RocketAPI.Window.csproj
PokemonGo/RocketAPI/Window/Properties/AssemblyInfo.cs
PokemonGo/RocketAPI/Window/RouteOptimizer.cs
PokemonGo/RocketAPI/Window/SettingsForm.cs
diff --git a/PokemonGo/RocketAPI/Window/MainForm.Designer.cs b/PokemonGo/RocketAPI/Window/MainForm.Designer.cs
index 7d859a6..a9e99eb 100644
--- a/PokemonGo/RocketAPI/Window/MainForm.Designer.cs
+++ b/PokemonGo/RocketAPI/Window/MainForm.Designer.cs
@@ -1,4 +1,4 @@
-namespace PokemonGo.RocketAPI.Window
+namespace PokemonGo.RocketAPI.Window
 {
     partial class MainForm
     {
@@ -57,10 +57,12 @@ namespace PokemonGo.RocketAPI.Window
             this.tabControl1 = new System.Windows.Forms.TabControl();
             this.tabPage1 = new System.Windows.Forms.TabPage();
             this.tabPage2 = new System.Windows.Forms.TabPage();
+            this.label1 = new System.Windows.Forms.Label();
             this.statusStrip1.SuspendLayout();
             this.menuStrip1.SuspendLayout();
             ((System.ComponentModel.ISupportInitialize)(this.objectListView1)).BeginInit();
             this.tabControl1.SuspendLayout();
+            this.tabPage1.SuspendLayout();
             this.SuspendLayout();
             //
             // logTextBox
@@ -112,8 +114,8 @@ namespace PokemonGo.RocketAPI.Window
             // startStopBotToolStripMenuItem
             //
             this.startStopBotToolStripMenuItem.Name = "startStopBotToolStripMenuItem";
-            this.startStopBotToolStripMenuItem.Size = new System.Drawing.Size(71, 21);
-            this.startStopBotToolStripMenuItem.Text = "Start Bot";
+            this.startStopBotToolStripMenuItem.Size = new System.Drawing.Size(85, 21);
+            this.startStopBotToolStripMenuItem.Text = "▶ Start Bot";
             this.startStopBotToolStripMenuItem.Click += new System.EventHandler(this.startStopBotToolStripMenuItem_Click);
             //
             // todoToolStripMenuItem
@@ -306,6 +308,7 @@ namespace PokemonGo.RocketAPI.Window
             this.tabControl1.Alignment = System.Windows.Forms.TabAlignment.Bottom;
             this.tabControl1.Controls.Add(this.tabPage1);
             this.tabControl1.Controls.Add(this.tabPage2);
+            this.tabControl1.Enabled = false;
             this.tabControl1.Font = new System.Drawing.Font("Microsoft Sans Serif", 9F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
             this.tabControl1.Location = new System.Drawing.Point(674, 368);
             this.tabControl1.Name = "tabControl1";
@@ -316,12 +319,13 @@ namespace PokemonGo.RocketAPI.Window
             //
             // tabPage1
             //
+            this.tabPage1.Controls.Add(this.label1);
             this.tabPage1.Location = new System.Drawing.Point(4, 4);
             this.tabPage1.Name = "tabPage1";
             this.tabPage1.Padding = new System.Windows.Forms.Padding(3);
             this.tabPage1.Size = new System.Drawing.Size(330, 216);
             this.tabPage1.TabIndex = 0;
-            this.tabPage1.Text = "tabPage1";
+            this.tabPage1.Text = "Incomming Feature";
             this.tabPage1.UseVisualStyleBackColor = true;
             //
             // tabPage2
@@ -329,11 +333,21 @@ namespace PokemonGo.RocketAPI.Window
             this.tabPage2.Location = new System.Drawing.Point(4, 4);
             this.tabPage2.Name = "tabPage2";
             this.tabPage2.Padding = new System.Windows.Forms.Padding(3);
-            this.tabPage2.Size = new System.Drawing.Size(330, 220);
+            this.tabPage2.Size = new System.Drawing.Size(330, 216);
             this.tabPage2.TabIndex = 1;
-            this.tabPage2.Text = "tabPage2";
+            this.tabPage2.Text = ":3";
             this.tabPage2.UseVisualStyleBackColor = true;
             //
+            // label1
+            //
+            this.label1.AutoSize = true;
+            this.label1.Font = new System.Drawing.Font("Microsoft Sans Serif", 15.75F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
+            this.label1.Location = new System.Drawing.Point(58, 105);
+            this.label1.Name = "label1";
+            this.label1.Size = new System.Drawing.Size(206, 25);
+            this.label1.TabIndex = 0;
+            this.label1.Text = "Incomming Features";
+            //
             // MainForm
             //
             this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 12F);
@@ -361,6 +375,8 @@ namespace PokemonGo.RocketAPI.Window
             this.menuStrip1.PerformLayout();
             ((System.ComponentModel.ISupportInitialize)(this.objectListView1)).EndInit();
             this.tabControl1.ResumeLayout(false);
+            this.tabPage1.ResumeLayout(false);
+            this.tabPage1.PerformLayout();
             this.ResumeLayout(false);
             this.PerformLayout();

@@ -395,5 +411,6 @@ namespace PokemonGo.RocketAPI.Window
         private System.Windows.Forms.TabControl tabControl1;
         private System.Windows.Forms.TabPage tabPage1;
         private System.Windows.Forms.TabPage tabPage2;
+        private System.Windows.Forms.Label label1;
     }
 }
diff --git a/PokemonGo/RocketAPI/Window/MainForm.cs b/PokemonGo/RocketAPI/Window/MainForm.cs
index 96eeb1b..e16595b 100644
--- a/PokemonGo/RocketAPI/Window/MainForm.cs
+++ b/PokemonGo/RocketAPI/Window/MainForm.cs
@@ -1,4 +1,4 @@
-using System;
+using System;
 using System.Collections.Generic;
 using System.ComponentModel;
 using System.Data;
@@ -145,7 +145,7 @@ namespace PokemonGo.RocketAPI.Window
             using (var wC = new WebClient())
                 return
                     wC.DownloadString(
-                        "https://raw.githubusercontent.com/DetectiveSquirrel/Pokemon-Go-Rocket-API/master/PokemonGo/RocketAPI/Window/Properties/AssemblyInfo.cs");
+                        "https://raw.githubusercontent.com/1461748123/Pokemon-Go-Rocket-API/master/PokemonGo/RocketAPI/Window/Properties/AssemblyInfo.cs");
         }

         public void ColoredConsoleWrite(Color color, string text)
@@ -359,7 +359,6 @@ namespace PokemonGo.RocketAPI.Window
                 {
                     ColoredConsoleWrite(Color.Red, $"No nearby useful locations found. Please wait 10 seconds.");
                     await Task.Delay(10000);
-                    CheckVersion();
                     Execute();
                 }
                 else
@@ -373,15 +372,13 @@ namespace PokemonGo.RocketAPI.Window
                     bot_started = false;
                 }
             }
-            catch (Exception ex)
-            {
-                ColoredConsoleWrite(Color.Red, ex.ToString());
-                if (!Stopping)
-                {
-                    client = null;
-                    Execute();
-                }
-            }
+            catch (TaskCanceledException) { ColoredConsoleWrite(Color.Red, "Task Canceled Exception - Restarting"); if (!Stopping) Execute(); }
+            catch (UriFormatException) { ColoredConsoleWrite(Color.Red, "System URI Format Exception - Restarting"); if (!Stopping) Execute(); }
+            catch (ArgumentOutOfRangeException) { ColoredConsoleWrite(Color.Red, "ArgumentOutOfRangeException - Restarting"); if (!Stopping) Execute(); }
+            catch (ArgumentNullException) { ColoredConsoleWrite(Color.Red, "Argument Null Refference - Restarting"); if (!Stopping) Execute(); }
+            catch (NullReferenceException) { ColoredConsoleWrite(Color.Red, "Null Refference - Restarting"); if (!Stopping) Execute(); }
+            catch (Exception ex) { ColoredConsoleWrite(Color.Red, ex.ToString()); if (!Stopping) Execute(); }
+            finally { client = null;}

         }

@@ -579,7 +576,7 @@ namespace PokemonGo.RocketAPI.Window
             UpdateMap();
             ColoredConsoleWrite(Color.Cyan, $"Finding fastest route through all PokeStops..");
             LatLong startingLatLong = new LatLong(ClientSettings.DefaultLatitude, ClientSettings.DefaultLongitude);
-            pokeStops = RouteOptimizer<FortData>.Optimize(rawPokeStops, startingLatLong, pokestopsOverlay);
+            pokeStops = RouteOptimizer.Optimize(rawPokeStops, startingLatLong, pokestopsOverlay);
             wildPokemons = mapObjects.MapCells.SelectMany(i => i.WildPokemons);
             if (!ForceUnbanning && !Stopping)
                 ColoredConsoleWrite(Color.Cyan, $"Visiting {pokeStops.Count()} PokeStops");
@@ -1073,7 +1070,7 @@ namespace PokemonGo.RocketAPI.Window
         {
             //ConsoleClear(); // dont really want the console to be wipped on bot stop, unnecessary
             ColoredConsoleWrite(Color.Red, $"Bot successfully stopped.");
-            startStopBotToolStripMenuItem.Text = "Start Bot";
+            startStopBotToolStripMenuItem.Text = "▶ Start Bot";
             Stopping = false;
             bot_started = false;
         }
@@ -1096,7 +1093,7 @@ namespace PokemonGo.RocketAPI.Window
             if (!bot_started)
             {
                 bot_started = true;
-                startStopBotToolStripMenuItem.Text = "Stop Bot";
+                startStopBotToolStripMenuItem.Text = "■ Stop Bot";
                 Task.Run(() =>
                 {
                     try
diff --git a/PokemonGo/RocketAPI/Window/PokemonGo.RocketAPI.Window.csproj b/PokemonGo/RocketAPI/Window/PokemonGo.RocketAPI.Window.csproj
index cb0252d..2d856d8 100644
--- a/PokemonGo/RocketAPI/Window/PokemonGo.RocketAPI.Window.csproj
+++ b/PokemonGo/RocketAPI/Window/PokemonGo.RocketAPI.Window.csproj
@@ -38,6 +38,10 @@
   <PropertyGroup>
     <NoWin32Manifest>true</NoWin32Manifest>
   </PropertyGroup>
+  <PropertyGroup>
+    <StartupObject>
+    </StartupObject>
+  </PropertyGroup>
   <ItemGroup>
     <Reference Include="GMap.NET.Core">
       <HintPath>lib\GMap.NET.Core.dll</HintPath>
@@ -109,7 +113,6 @@
     <Compile Include="SettingsForm.Designer.cs">
       <DependentUpon>SettingsForm.cs</DependentUpon>
     </Compile>
-    <Compile Include="TSP.cs" />
     <EmbeddedResource Include="MainForm.resx">
       <DependentUpon>MainForm.cs</DependentUpon>
     </EmbeddedResource>
diff --git a/PokemonGo/RocketAPI/Window/Properties/AssemblyInfo.cs b/PokemonGo/RocketAPI/Window/Properties/AssemblyInfo.cs
index 86f3a34..66e91a5 100644
--- a/PokemonGo/RocketAPI/Window/Properties/AssemblyInfo.cs
+++ b/PokemonGo/RocketAPI/Window/Properties/AssemblyInfo.cs
@@ -32,5 +32,5 @@ using System.Runtime.InteropServices;
 // You can specify all the values or you can default the Build and Revision Numbers
 // by using the '*' as shown below:
 // [assembly: AssemblyVersion("1.0.*")]
-[assembly: AssemblyVersion("1.7.2.0")]
+[assembly: AssemblyVersion("1.7.2.1")]
 [assembly: AssemblyFileVersion("1.0.0.0")]
diff --git a/PokemonGo/RocketAPI/Window/RouteOptimizer.cs b/PokemonGo/RocketAPI/Window/RouteOptimizer.cs
index b6f1bd4..8f8a73e 100644
--- a/PokemonGo/RocketAPI/Window/RouteOptimizer.cs
+++ b/PokemonGo/RocketAPI/Window/RouteOptimizer.cs
@@ -1,93 +1,150 @@
-using GMap.NET.WindowsForms;
+using GMap.NET;
+using GMap.NET.WindowsForms;
 using PokemonGo.RocketAPI.GeneratedCode;
-using PokemonGo.RocketAPI.Extensions;
 using System;
 using System.Collections.Generic;
 using System.Linq;
 using System.Text;
+using System.Threading;
 using System.Threading.Tasks;

 namespace PokemonGo.RocketAPI.Window
 {
-    public static class RouteOptimizer<T> where T: ILatLong
+    public static class RouteOptimizer
     {
-        public static List<T> Optimize(T[] stops, ILatLong startingPosition, GMapOverlay routeOverlay)
+        public static List<FortData> Optimize(FortData[] pokeStops, LatLong latlng, GMapOverlay routeOverlay)
         {
-            List<T> optimizedRoute = new List<T>(stops);
+            List<FortData> optimizedRoute = new List<FortData>(pokeStops);

             // NN
-            T NN = FindNN(optimizedRoute, startingPosition);
+            FortData NN = FindNN(optimizedRoute, latlng.Latitude, latlng.Longitude);
             optimizedRoute.Remove(NN);
             optimizedRoute.Insert(0, NN);
-            for (int i=1; i< stops.Length; i++)
+            for (int i = 1; i < pokeStops.Length; i++)
             {
-                NN = FindNN(optimizedRoute.Skip(i), NN);
+                NN = FindNN(optimizedRoute.Skip(i), NN.Latitude, NN.Longitude);
                 optimizedRoute.Remove(NN);
                 optimizedRoute.Insert(i, NN);
+                Visualize(optimizedRoute, routeOverlay);
             }

             // 2-Opt
-            optimizedRoute = Optimize2Opt(optimizedRoute);
+            bool isOptimized;
+            do
+            {
+                optimizedRoute = Optimize2Opt(optimizedRoute, out isOptimized);
+                Visualize(optimizedRoute, routeOverlay);
+            }
+            while (isOptimized);

             return optimizedRoute;
         }

-        public static float routeCost(List<T> stops)
+        private static void Visualize(List<FortData> pokeStops, GMapOverlay routeOverlay)
         {
-            return Enumerable.Range(0, stops.Count - 1).Aggregate<int, float>(0, (sum,i) =>
+            MainForm.synchronizationContext.Post(new SendOrPostCallback(o =>
             {
-                return sum + (float)stops[i].distanceFrom(stops[i + 1]);
-            });
-        }
+                List<FortData> p = new List<FortData>((List<FortData>)o);
+                routeOverlay.Markers.Clear();
+                List<PointLatLng> routePoint = new List<PointLatLng>();
+                foreach (var pokeStop in p)
+                {
+                    var pokeStopLoc = new PointLatLng(pokeStop.Latitude, pokeStop.Longitude);

-        private static List<T> reverseSublist(List<T> stops, int startIndex, int endIndex)
-        {
-            return stops
-                .Take(startIndex)
-                .Concat(
-                    stops
-                    .Skip(startIndex)
-                    .Take(endIndex - startIndex)
-                    .Reverse()
-                ).Concat(stops.Skip(endIndex)).ToList();
+                    routePoint.Add(pokeStopLoc);
+                }
+                routeOverlay.Routes.Clear();
+                routeOverlay.Routes.Add(new GMapRoute(routePoint, "Walking Path"));
+            }), pokeStops);
         }

-        private static List<T> Optimize2Opt(List<T> stops)
+        private static List<FortData> Optimize2Opt(List<FortData> pokeStops, out bool isOptimized)
         {
-            List<T> optimizedRoute = stops;
+            int n = pokeStops.Count;
+            float bestGain = 0;
+            int bestI = -1;
+            int bestJ = -1;

-            int n = stops.Count;
-            bool foundCheaperRoute;
-            float minCost = routeCost(optimizedRoute);
-            do
+            for (int ai = 0; ai < n; ai++)
             {
-                foundCheaperRoute = false;
-                for (int i = 0; i < n - 1; i++)
+                for (int ci = 0; ci < n; ci++)
                 {
-                    for (int j = i + 1; j < n ; j++)
+                    int bi = (ai + 1) % n;
+                    int di = (ci + 1) % n;
+
+                    FortData a = pokeStops[ai];
+                    FortData b = pokeStops[bi];
+                    FortData c = pokeStops[ci];
+                    FortData d = pokeStops[di];
+
+                    float ab = GetDistance(a, b);
+                    float cd = GetDistance(c, d);
+                    float ac = GetDistance(a, c);
+                    float bd = GetDistance(b, d);
+
+                    if (ci != ai && ci != bi)
                     {
-                        List<T> newRoute = reverseSublist(optimizedRoute, i, j);
-                        float newCost = routeCost(newRoute);
-                        if (newCost < minCost)
+                        float gain = (ab + cd) - (ac + bd);
+                        if (gain > bestGain)
                         {
-                            minCost = newCost;
-                            optimizedRoute = newRoute;
-                            foundCheaperRoute = true;
-                            break;
+                            bestGain = gain;
+                            bestI = bi;
+                            bestJ = ci;
                         }
                     }
-                    if (foundCheaperRoute)
-                        break;
                 }
             }
-            while (foundCheaperRoute);
-            return optimizedRoute;
+
+            if (bestI != -1)
+            {
+                List<FortData> optimizedRoute;
+                if (bestI > bestJ)
+                {
+                    optimizedRoute = new List<FortData>();
+                    optimizedRoute.Add(pokeStops[0]);
+                    optimizedRoute.AddRange(pokeStops.Skip(bestI));
+                    optimizedRoute.Reverse(1, n - bestI);
+                    optimizedRoute.AddRange(pokeStops.GetRange(bestJ + 1, bestI - bestJ - 1));
+                    optimizedRoute.AddRange(pokeStops.GetRange(1, bestJ));
+                    optimizedRoute.Reverse(n - bestJ, bestJ);
+                }
+                else if (bestI == 0)
+                {
+                    optimizedRoute = new List<FortData>(pokeStops);
+                    optimizedRoute.Reverse(bestJ + 1, n - bestJ - 1);
+                }
+                else
+                {
+                    optimizedRoute = new List<FortData>(pokeStops);
+                    optimizedRoute.Reverse(bestI, bestJ - bestI + 1);
+                }
+
+                isOptimized = true;
+                return optimizedRoute;
+            }
+            isOptimized = false;
+            return pokeStops;
+        }
+
+        private static FortData FindNN(IEnumerable<FortData> pokeStops, double cLatitude, double cLongitude)
+        {
+            return pokeStops.OrderBy(p => GetDistance(cLatitude, cLongitude, p.Latitude, p.Longitude)).First();
         }

-        private static T FindNN(IEnumerable<T> stops, ILatLong fromPosition)
+        private static float GetDistance(FortData a, FortData b)
         {
-            return stops.OrderBy(p => fromPosition.distanceFrom(p)).First();
+            return GetDistance(a.Latitude, a.Longitude, b.Latitude, b.Longitude);
         }

+        private static float GetDistance(double lat1, double lng1, double lat2, double lng2)
+        {
+            double R = 6371e3;
+            Func<double, float> toRad = x => (float)(x * (Math.PI / 180));
+            lat1 = toRad(lat1);
+            lat2 = toRad(lat2);
+            float dLng = toRad(lng2 - lng1);
+
+            return (float)(Math.Acos(Math.Sin(lat1) * Math.Sin(lat2) + Math.Cos(lat1) * Math.Cos(lat2) * Math.Cos(dLng)) * R);
+        }
     }
-}
+}
\ No newline at end of file
diff --git a/PokemonGo/RocketAPI/Window/SettingsForm.cs b/PokemonGo/RocketAPI/Window/SettingsForm.cs
index 78bac93..d95de7c 100644
--- a/PokemonGo/RocketAPI/Window/SettingsForm.cs
+++ b/PokemonGo/RocketAPI/Window/SettingsForm.cs
@@ -103,6 +103,7 @@ namespace PokemonGo.RocketAPI.Window
             Settings.Instance.SetSetting(evolveAllChk.Checked ? "true" : "false", "EvolveAllGivenPokemons");
             Settings.Instance.SetSetting(CatchPokemonBox.Checked ? "true" : "false", "CatchPokemon");
             Settings.Instance.Reload();
+
             Close();
         }
You may download the files in Public Git.