Compare commits
53 Commits
23de653bde
..
1.0
| Author | SHA1 | Date | |
|---|---|---|---|
| de97589344 | |||
| 9f19f0ffe5 | |||
| 969d4fc34c | |||
| 991800728e | |||
| 067e7233a0 | |||
| 6f36c829c2 | |||
| c105382269 | |||
| f417f3581a | |||
| 5a6ca35334 | |||
| 398466c671 | |||
| 5421b5071b | |||
| 03130f6c42 | |||
| e8028528e0 | |||
| f356d90c35 | |||
| e4edd71adc | |||
| 5c6e3c5b2b | |||
| 42858f847d | |||
| 7c189bc2d9 | |||
| 6b94935259 | |||
| 462d07093a | |||
| 89c7e15a70 | |||
| 195108bcde | |||
| dd3dbcadf6 | |||
| af8db571f3 | |||
| 66906cb54e | |||
| e650072213 | |||
| 96de5485fe | |||
| 417cb7d8eb | |||
| b7676b90c2 | |||
| e727dc9301 | |||
| ac65c7b4f3 | |||
| 511f5d98e4 | |||
| 39e9dbb7d6 | |||
| b6de154438 | |||
| d722015cd1 | |||
| d559d4a31e | |||
| 1d17963572 | |||
| 7f0f481cc3 | |||
| 863ce1922f | |||
| 592025e283 | |||
| 6d2d2e11a8 | |||
| 134ac85ad1 | |||
| 025c2f8d61 | |||
| 57028f1fc9 | |||
| 2c1340780e | |||
| df9231aed6 | |||
| aac44fcfb9 | |||
| 55d45adc1d | |||
| 16be9bf7ef | |||
| 2c2239427c | |||
| 221fb88e08 | |||
| 044a00e167 | |||
| 66e8699afe |
@@ -1,10 +1,25 @@
|
|||||||
# Work in progress
|
# Track Trends Alpha 1.0
|
||||||
|
|
||||||
# How to run it on your machine
|
# Installation
|
||||||
|
|
||||||
you will need to take a couple of folders and files in the /bin/debug or /bin/release folder
|
As this project is a little finnicky, installing it and making it run is quite a job. Grab a coffe and lets begin.
|
||||||
|
|
||||||
You need to take the recoverCookiesCSV.py in ./Test_Merge and put it in the /bin/... folder
|
## Before installation
|
||||||
Same for the all geckodriver-v0.xx.x-win32 folder
|
|
||||||
|
|
||||||
You also have to change the TESS_DATA_FOLDER constant in the Windows.cs file. A small one is included in the project files
|
- Make sure you have a recent version of python installed (tested with 3.9)
|
||||||
|
- Make sure you have chrome installed on your pc and that its installed in the default location
|
||||||
|
- Connect to the F1TV with your credentials (can be done after installation but sometimes it takes some time to get register into the cookies db so I would advise you to do it now to be sure you can use the app directly after installation)
|
||||||
|
|
||||||
|
## Installation process
|
||||||
|
1. First you will need to download the files from the project.
|
||||||
|
3. Before unzipping Ill advise checking if the folder is locked or not (to check you right click on the folder and all the way at the end of the context menu if there is a checkbox to unlock you need to check it).
|
||||||
|
4. You need to unzip the project.
|
||||||
|
5. Locate the .SLN file that represents the project. (Should be named either TrackTrends or Test_Merge) and open it in Visual Studio (Tested with 2022 community edition).
|
||||||
|
6. Before running it you need to go back to the file explorer and click on either the "TrackTrends" or "Test_Merge" folder and locate three very important files/folders (geckodriver-v0.xx.x-win32 folder,recoverCookiesCSV.py file,TessData folder) and put them into the ./bin/debug or ./bin/release folder.
|
||||||
|
7. If you want to store the TessData folder or if you already have it somewehere else on your machine (that can happen as thoses kind of files can be quite heavy) its possible, follow step 8.
|
||||||
|
8. Even if you have put the TessData folder in ./debug you will need to change in the file `Window.cs` file at line 39 the TESS_DATA_FOLDER constant to match your scenario.
|
||||||
|
9. Add those two Environnement variables as followed
|
||||||
|
- MOZ_HEADLESS_WIDTH => 3840
|
||||||
|
- MOZ_HEADLESS_HEIGHT => 2160
|
||||||
|
10. If you dont want to create your own config file at your first application start. I added for you a config file made for 2023 named `Clean_4K_2023.json` in the same folder as the python file. You will need to add it into a folder named `Presets` that you will have to create if it does not already exists
|
||||||
|
11. Have fun !
|
||||||
@@ -1,14 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<configuration>
|
|
||||||
<startup>
|
|
||||||
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.7.2" />
|
|
||||||
</startup>
|
|
||||||
<runtime>
|
|
||||||
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
|
|
||||||
<dependentAssembly>
|
|
||||||
<assemblyIdentity name="System.Runtime.CompilerServices.Unsafe" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
|
|
||||||
<bindingRedirect oldVersion="0.0.0.0-6.0.0.0" newVersion="6.0.0.0" />
|
|
||||||
</dependentAssembly>
|
|
||||||
</assemblyBinding>
|
|
||||||
</runtime>
|
|
||||||
</configuration>
|
|
||||||
@@ -1,129 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Drawing;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
using Tesseract;
|
|
||||||
|
|
||||||
namespace Test_Merge
|
|
||||||
{
|
|
||||||
public class ConfigurationTool
|
|
||||||
{
|
|
||||||
public Zone MainZone;
|
|
||||||
public const int NUMBER_OF_DRIVERS = 20;
|
|
||||||
public const int NUMBER_OF_ZONES = 9;
|
|
||||||
|
|
||||||
public ConfigurationTool(Bitmap fullImage,Rectangle mainZoneDimensions)
|
|
||||||
{
|
|
||||||
MainZone = new Zone(fullImage,mainZoneDimensions);
|
|
||||||
AutoCalibrate();
|
|
||||||
}
|
|
||||||
public void AddWindows(List<Rectangle> rectangles)
|
|
||||||
{
|
|
||||||
foreach (Zone driverZone in MainZone.Zones)
|
|
||||||
{
|
|
||||||
Bitmap zoneImage = driverZone.ZoneImage;
|
|
||||||
|
|
||||||
for (int i = 1; i <= rectangles.Count; i++)
|
|
||||||
{
|
|
||||||
switch (i)
|
|
||||||
{
|
|
||||||
case 1:
|
|
||||||
//First zone should be the driver's Position
|
|
||||||
driverZone.AddWindow(new DriverPositionWindow(driverZone.ZoneImage, rectangles[i]));
|
|
||||||
break;
|
|
||||||
case 2:
|
|
||||||
//First zone should be the driver's Position
|
|
||||||
driverZone.AddWindow(new DriverGapToLeaderWindow(driverZone.ZoneImage, rectangles[i]));
|
|
||||||
break;
|
|
||||||
case 3:
|
|
||||||
//First zone should be the driver's Position
|
|
||||||
driverZone.AddWindow(new DriverLapTimeWindow(driverZone.ZoneImage, rectangles[i]));
|
|
||||||
break;
|
|
||||||
case 4:
|
|
||||||
//First zone should be the driver's Position
|
|
||||||
driverZone.AddWindow(new DriverDrsWindow(driverZone.ZoneImage, rectangles[i]));
|
|
||||||
break;
|
|
||||||
case 5:
|
|
||||||
//First zone should be the driver's Position
|
|
||||||
driverZone.AddWindow(new DriverTyresWindow(driverZone.ZoneImage, rectangles[i]));
|
|
||||||
break;
|
|
||||||
case 6:
|
|
||||||
//First zone should be the driver's Position
|
|
||||||
driverZone.AddWindow(new DriverNameWindow(driverZone.ZoneImage, rectangles[i]));
|
|
||||||
break;
|
|
||||||
case 7:
|
|
||||||
//First zone should be the driver's Position
|
|
||||||
driverZone.AddWindow(new DriverSectorWindow(driverZone.ZoneImage, rectangles[i]));
|
|
||||||
break;
|
|
||||||
case 8:
|
|
||||||
//First zone should be the driver's Position
|
|
||||||
driverZone.AddWindow(new DriverSectorWindow(driverZone.ZoneImage, rectangles[i]));
|
|
||||||
break;
|
|
||||||
case 9:
|
|
||||||
//First zone should be the driver's Position
|
|
||||||
driverZone.AddWindow(new DriverSectorWindow(driverZone.ZoneImage, rectangles[i]));
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
public void AutoCalibrate()
|
|
||||||
{
|
|
||||||
List<Rectangle> detectedText = new List<Rectangle>();
|
|
||||||
List<Zone> zones = new List<Zone>();
|
|
||||||
|
|
||||||
TesseractEngine engine = new TesseractEngine(Window.TESS_DATA_FOLDER.FullName, "eng", EngineMode.Default);
|
|
||||||
Image image = MainZone.ZoneImage;
|
|
||||||
var tessImage = Pix.LoadFromMemory(Window.ImageToByte(image));
|
|
||||||
|
|
||||||
Page page = engine.Process(tessImage);
|
|
||||||
using (var iter = page.GetIterator())
|
|
||||||
{
|
|
||||||
iter.Begin();
|
|
||||||
do
|
|
||||||
{
|
|
||||||
Rect boundingBox;
|
|
||||||
if (iter.TryGetBoundingBox(PageIteratorLevel.Word, out boundingBox))
|
|
||||||
{
|
|
||||||
//var text = iter.GetText(PageIteratorLevel.Word).ToUpper();
|
|
||||||
//We remove all the rectangles that are definitely too big
|
|
||||||
if (boundingBox.Height < image.Height / NUMBER_OF_DRIVERS)
|
|
||||||
{
|
|
||||||
//Now we add a filter to only get the boxes in the right because they are much more reliable in size
|
|
||||||
if (boundingBox.X1 > image.Width / 2)
|
|
||||||
{
|
|
||||||
//Now we check if an other square box has been found roughly in the same y axis
|
|
||||||
bool match = false;
|
|
||||||
//The tolerance is roughly half the size that a window will be
|
|
||||||
int tolerance = (image.Height / NUMBER_OF_DRIVERS) / 2;
|
|
||||||
|
|
||||||
foreach (Rectangle rect in detectedText)
|
|
||||||
{
|
|
||||||
if (rect.Y > boundingBox.Y1 - tolerance && rect.Y < boundingBox.Y1 + tolerance)
|
|
||||||
{
|
|
||||||
//There already is a rectangle in this line
|
|
||||||
match = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
//if nothing matched we can add it
|
|
||||||
if (!match)
|
|
||||||
detectedText.Add(new Rectangle(boundingBox.X1, boundingBox.Y1, boundingBox.Width, boundingBox.Height));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} while (iter.Next(PageIteratorLevel.Word));
|
|
||||||
}
|
|
||||||
foreach (Rectangle Rectangle in detectedText)
|
|
||||||
{
|
|
||||||
Rectangle windowRectangle;
|
|
||||||
Size windowSize = new Size(image.Width, image.Height / NUMBER_OF_DRIVERS);
|
|
||||||
Point windowLocation = new Point(0, (Rectangle.Y + Rectangle.Height / 2) - windowSize.Height / 2);
|
|
||||||
windowRectangle = new Rectangle(windowLocation, windowSize);
|
|
||||||
//We add the driver zones
|
|
||||||
MainZone.AddZone(new Zone(MainZone.ZoneImage, windowRectangle));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,26 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Drawing;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
|
|
||||||
namespace Test_Merge
|
|
||||||
{
|
|
||||||
internal class DriverGapToLeaderWindow:Window
|
|
||||||
{
|
|
||||||
public DriverGapToLeaderWindow(Bitmap image, Rectangle bounds) : base(image, bounds)
|
|
||||||
{
|
|
||||||
Name = "Gap to leader";
|
|
||||||
}
|
|
||||||
/// <summary>
|
|
||||||
/// Decodes the gap to leader using Tesseract OCR
|
|
||||||
/// </summary>
|
|
||||||
/// <returns></returns>
|
|
||||||
public override async Task<object> DecodePng()
|
|
||||||
{
|
|
||||||
int result = await GetTimeFromPng(WindowImage, OcrImage.WindowType.Gap, Engine);
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,26 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
using System.Drawing;
|
|
||||||
|
|
||||||
namespace Test_Merge
|
|
||||||
{
|
|
||||||
internal class DriverSectorWindow:Window
|
|
||||||
{
|
|
||||||
public DriverSectorWindow(Bitmap image, Rectangle bounds) : base(image, bounds)
|
|
||||||
{
|
|
||||||
Name = "Sector 1";
|
|
||||||
}
|
|
||||||
/// <summary>
|
|
||||||
/// Decodes the sector
|
|
||||||
/// </summary>
|
|
||||||
/// <returns>the sector time in int (ms)</returns>
|
|
||||||
public override async Task<object> DecodePng()
|
|
||||||
{
|
|
||||||
int ocrResult = await GetTimeFromPng(WindowImage, OcrImage.WindowType.Sector, Engine);
|
|
||||||
return ocrResult;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,236 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Diagnostics;
|
|
||||||
using System.Drawing;
|
|
||||||
using System.IO;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Reflection;
|
|
||||||
using System.Text;
|
|
||||||
using System.Threading;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
using System.Windows.Forms;
|
|
||||||
using OpenQA.Selenium;
|
|
||||||
using OpenQA.Selenium.Firefox;
|
|
||||||
using OpenQA.Selenium.Interactions;
|
|
||||||
using OpenQA.Selenium.Support.UI;
|
|
||||||
|
|
||||||
namespace Test_Merge
|
|
||||||
{
|
|
||||||
public class F1TVEmulator
|
|
||||||
{
|
|
||||||
public const string COOKIE_HOST = ".formula1.com";
|
|
||||||
public const string PYTHON_COOKIE_RETRIEVAL_FILENAME = "recoverCookiesCSV.py";
|
|
||||||
public const string GECKODRIVER_FILENAME = @"geckodriver-v0.27.0-win32\geckodriver.exe";
|
|
||||||
//BE CAREFULL IF YOU CHANGE IT HERE YOU NEED TO CHANGE IT IN THE PYTHON SCRIPT TOO
|
|
||||||
public const string COOKIES_CSV_FILENAME = "cookies.csv";
|
|
||||||
|
|
||||||
private FirefoxDriver Driver;
|
|
||||||
|
|
||||||
private bool _ready;
|
|
||||||
private string _grandPrixUrl;
|
|
||||||
public string GrandPrixUrl { get => _grandPrixUrl; private set => _grandPrixUrl = value; }
|
|
||||||
public bool Ready { get => _ready; set => _ready = value; }
|
|
||||||
|
|
||||||
public F1TVEmulator(string grandPrixUrl)
|
|
||||||
{
|
|
||||||
GrandPrixUrl = grandPrixUrl;
|
|
||||||
Ready = false;
|
|
||||||
}
|
|
||||||
private void StartCookieRecovering()
|
|
||||||
{
|
|
||||||
string scriptPath = Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), PYTHON_COOKIE_RETRIEVAL_FILENAME);
|
|
||||||
Process process = new Process();
|
|
||||||
process.StartInfo.FileName = "python.exe";
|
|
||||||
process.StartInfo.Arguments = scriptPath;
|
|
||||||
process.StartInfo.UseShellExecute = false;
|
|
||||||
process.StartInfo.RedirectStandardOutput = true;
|
|
||||||
process.Start();
|
|
||||||
string output = process.StandardOutput.ReadToEnd();
|
|
||||||
process.WaitForExit();
|
|
||||||
}
|
|
||||||
public async Task<int> Start()
|
|
||||||
{
|
|
||||||
//SETUP
|
|
||||||
//Those values can be changed to alter the way that the selenium driver looks and behaves in general
|
|
||||||
|
|
||||||
Ready = false;
|
|
||||||
|
|
||||||
string loginCookieName = "login";
|
|
||||||
string loginSessionCookieName = "login-session";
|
|
||||||
string loginCookieValue = GetCookie(COOKIE_HOST, loginCookieName);
|
|
||||||
string loginSessionValue = GetCookie(COOKIE_HOST, loginSessionCookieName);
|
|
||||||
|
|
||||||
int windowWidth = 1920;
|
|
||||||
int windowHeight = 1080;
|
|
||||||
|
|
||||||
var service = FirefoxDriverService.CreateDefaultService(AppDomain.CurrentDomain.BaseDirectory + GECKODRIVER_FILENAME);
|
|
||||||
service.Host = "127.0.0.1";
|
|
||||||
service.Port = 5555;
|
|
||||||
|
|
||||||
FirefoxOptions options = new FirefoxOptions();
|
|
||||||
options.AddArgument("--window-size=" + windowWidth + "," + windowHeight + "");
|
|
||||||
options.AddArgument("--disable-web-security");
|
|
||||||
options.AddArgument("--same-site-none-secure");
|
|
||||||
options.AcceptInsecureCertificates = true;
|
|
||||||
//Headless part
|
|
||||||
options.AddArgument("--headless");
|
|
||||||
options.AddArgument("--silent-launch");
|
|
||||||
options.AddArgument("--no-startup-window");
|
|
||||||
|
|
||||||
//ACTUAL STARTUP
|
|
||||||
try
|
|
||||||
{
|
|
||||||
Driver = new FirefoxDriver(service, options);
|
|
||||||
}
|
|
||||||
catch
|
|
||||||
{
|
|
||||||
//Could not start the driver, could be because an other instance is running. make sure its closed before re attempting
|
|
||||||
return 101;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
var loginCookie = new Cookie(loginCookieName, loginCookieValue, COOKIE_HOST, "/", DateTime.Now.AddDays(5));
|
|
||||||
var loginSessionCookie = new Cookie(loginSessionCookieName, loginSessionValue, COOKIE_HOST, "/", DateTime.Now.AddDays(5));
|
|
||||||
|
|
||||||
Actions actions = new Actions(Driver);
|
|
||||||
|
|
||||||
Driver.Navigate().GoToUrl("https://f1tv.formula1.com/");
|
|
||||||
|
|
||||||
Driver.Manage().Cookies.AddCookie(loginCookie);
|
|
||||||
Driver.Manage().Cookies.AddCookie(loginSessionCookie);
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
Driver.Navigate().GoToUrl(GrandPrixUrl);
|
|
||||||
}
|
|
||||||
catch
|
|
||||||
{
|
|
||||||
//The url is not a valid url
|
|
||||||
Driver.Dispose();
|
|
||||||
return 103;
|
|
||||||
}
|
|
||||||
|
|
||||||
//Waits for the page to fully load
|
|
||||||
Driver.Manage().Timeouts().PageLoad = TimeSpan.FromSeconds(30);
|
|
||||||
|
|
||||||
//Removes the cookie prompt
|
|
||||||
try
|
|
||||||
{
|
|
||||||
IWebElement conscentButton = Driver.FindElement(By.Id("truste-consent-button"));
|
|
||||||
conscentButton.Click();
|
|
||||||
}
|
|
||||||
catch
|
|
||||||
{
|
|
||||||
Driver.Dispose();
|
|
||||||
return 104;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
//Again waits for the page to fully load (when you accept cookies it takes a little time for the page to load)
|
|
||||||
//Cannot use The timeout because the feed loading is not really loading so there is not event or anything
|
|
||||||
Thread.Sleep(5000);
|
|
||||||
|
|
||||||
//Switches to the Data channel
|
|
||||||
try
|
|
||||||
{
|
|
||||||
IWebElement dataChannelButton = Driver.FindElement(By.ClassName("data-button"));
|
|
||||||
dataChannelButton.Click();
|
|
||||||
}
|
|
||||||
catch
|
|
||||||
{
|
|
||||||
//If the data button does not exists its because the user is not connected
|
|
||||||
Driver.Dispose();
|
|
||||||
return 102;
|
|
||||||
}
|
|
||||||
//Open settings
|
|
||||||
// Press the space key, this should make the setting button visible
|
|
||||||
// It does not matter if the feed is paused because when changing channel it autoplays
|
|
||||||
actions.SendKeys(OpenQA.Selenium.Keys.Space).Perform();
|
|
||||||
Thread.Sleep(1000);
|
|
||||||
//Clicks on the settings Icon
|
|
||||||
try
|
|
||||||
{
|
|
||||||
IWebElement settingsButton = Driver.FindElement(By.ClassName("bmpui-ui-settingstogglebutton"));
|
|
||||||
settingsButton.Click();
|
|
||||||
IWebElement selectElement = Driver.FindElement(By.ClassName("bmpui-ui-videoqualityselectbox"));
|
|
||||||
SelectElement select = new SelectElement(selectElement);
|
|
||||||
IWebElement selectOption = selectElement.FindElement(By.CssSelector("option[value^='1080_']"));
|
|
||||||
selectOption.Click();
|
|
||||||
|
|
||||||
}
|
|
||||||
catch
|
|
||||||
{
|
|
||||||
//Sometimes it can crash because it could not get the options to show up in time. When it happens just retry
|
|
||||||
Driver.Dispose();
|
|
||||||
return 105;
|
|
||||||
}
|
|
||||||
|
|
||||||
//Makes the feed fullscreen
|
|
||||||
WebDriverWait wait = new WebDriverWait(Driver, TimeSpan.FromSeconds(10));
|
|
||||||
IWebElement fullScreenButton = Driver.FindElement(By.ClassName("bmpui-ui-fullscreentogglebutton"));
|
|
||||||
fullScreenButton.Click();
|
|
||||||
|
|
||||||
//STARTUP FINISHED READY TO SCREENSHOT
|
|
||||||
Ready = true;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
public void Stop()
|
|
||||||
{
|
|
||||||
Ready = false;
|
|
||||||
Driver.Dispose();
|
|
||||||
}
|
|
||||||
public Bitmap Screenshot()
|
|
||||||
{
|
|
||||||
Bitmap result = new Bitmap(100, 100);
|
|
||||||
if (Ready)
|
|
||||||
{
|
|
||||||
Screenshot scrsht = ((ITakesScreenshot)Driver).GetScreenshot();
|
|
||||||
// Get the raw bytes of the screenshot
|
|
||||||
byte[] screenshotBytes = Convert.FromBase64String(scrsht.AsBase64EncodedString);
|
|
||||||
// Create a new MemoryStream from the bytes
|
|
||||||
MemoryStream stream = new MemoryStream(screenshotBytes);
|
|
||||||
// Create a new Bitmap object from the MemoryStream
|
|
||||||
result = new Bitmap(stream);
|
|
||||||
}
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
public string GetCookie(string host, string name)
|
|
||||||
{
|
|
||||||
StartCookieRecovering();
|
|
||||||
string value = "";
|
|
||||||
List<Cookie> cookies = new List<Cookie>();
|
|
||||||
using (var reader = new StreamReader(COOKIES_CSV_FILENAME))
|
|
||||||
{
|
|
||||||
// Read the header row and validate column order
|
|
||||||
string header = reader.ReadLine();
|
|
||||||
string[] expectedColumns = { "host_key", "name", "value", "path", "expires_utc", "is_secure", "is_httponly" };
|
|
||||||
string[] actualColumns = header.Split(',');
|
|
||||||
for (int i = 0; i < expectedColumns.Length; i++)
|
|
||||||
{
|
|
||||||
if (expectedColumns[i] != actualColumns[i])
|
|
||||||
{
|
|
||||||
throw new InvalidOperationException($"Expected column '{expectedColumns[i]}' at index {i} but found '{actualColumns[i]}'");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Read each data row and parse values into a Cookie object
|
|
||||||
while (!reader.EndOfStream)
|
|
||||||
{
|
|
||||||
string line = reader.ReadLine();
|
|
||||||
string[] fields = line.Split(',');
|
|
||||||
|
|
||||||
string hostname = fields[0];
|
|
||||||
string cookieName = fields[1];
|
|
||||||
|
|
||||||
if (hostname == host && cookieName == name)
|
|
||||||
{
|
|
||||||
value = fields[2];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Generated
-61
@@ -1,61 +0,0 @@
|
|||||||
namespace Test_Merge
|
|
||||||
{
|
|
||||||
partial class Form1
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Required designer variable.
|
|
||||||
/// </summary>
|
|
||||||
private System.ComponentModel.IContainer components = null;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Clean up any resources being used.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
|
|
||||||
protected override void Dispose(bool disposing)
|
|
||||||
{
|
|
||||||
if (disposing && (components != null))
|
|
||||||
{
|
|
||||||
components.Dispose();
|
|
||||||
}
|
|
||||||
base.Dispose(disposing);
|
|
||||||
}
|
|
||||||
|
|
||||||
#region Windows Form Designer generated code
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Required method for Designer support - do not modify
|
|
||||||
/// the contents of this method with the code editor.
|
|
||||||
/// </summary>
|
|
||||||
private void InitializeComponent()
|
|
||||||
{
|
|
||||||
this.btnSettings = new System.Windows.Forms.Button();
|
|
||||||
this.SuspendLayout();
|
|
||||||
//
|
|
||||||
// btnSettings
|
|
||||||
//
|
|
||||||
this.btnSettings.Location = new System.Drawing.Point(12, 12);
|
|
||||||
this.btnSettings.Name = "btnSettings";
|
|
||||||
this.btnSettings.Size = new System.Drawing.Size(102, 53);
|
|
||||||
this.btnSettings.TabIndex = 0;
|
|
||||||
this.btnSettings.Text = "Settings";
|
|
||||||
this.btnSettings.UseVisualStyleBackColor = true;
|
|
||||||
this.btnSettings.Click += new System.EventHandler(this.btnSettings_Click);
|
|
||||||
//
|
|
||||||
// Form1
|
|
||||||
//
|
|
||||||
this.AutoScaleDimensions = new System.Drawing.SizeF(8F, 16F);
|
|
||||||
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
|
|
||||||
this.ClientSize = new System.Drawing.Size(800, 450);
|
|
||||||
this.Controls.Add(this.btnSettings);
|
|
||||||
this.Name = "Form1";
|
|
||||||
this.Text = "Form1";
|
|
||||||
this.ResumeLayout(false);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
private System.Windows.Forms.Button btnSettings;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -1,27 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.ComponentModel;
|
|
||||||
using System.Data;
|
|
||||||
using System.Drawing;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
using System.Windows.Forms;
|
|
||||||
|
|
||||||
namespace Test_Merge
|
|
||||||
{
|
|
||||||
public partial class Form1 : Form
|
|
||||||
{
|
|
||||||
public Form1()
|
|
||||||
{
|
|
||||||
InitializeComponent();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void btnSettings_Click(object sender, EventArgs e)
|
|
||||||
{
|
|
||||||
Settings settingsForm = new Settings();
|
|
||||||
settingsForm.ShowDialog();
|
|
||||||
MessageBox.Show(settingsForm.GrandPrixUrl);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,278 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
using System.Drawing;
|
|
||||||
using System.IO;
|
|
||||||
using System.Text.Json;
|
|
||||||
using System.Windows.Forms;
|
|
||||||
|
|
||||||
namespace Test_Merge
|
|
||||||
{
|
|
||||||
internal class OCRDecoder
|
|
||||||
{
|
|
||||||
private string _configFile;
|
|
||||||
private string _imagesFolder;
|
|
||||||
private List<string> _drivers;
|
|
||||||
private List<Zone> _mainZones;
|
|
||||||
private Bitmap FullImage;
|
|
||||||
public string ConfigFile { get => _configFile; private set => _configFile = value; }
|
|
||||||
public string ImagesFolder { get => _imagesFolder; private set => _imagesFolder = value; }
|
|
||||||
public List<string> Drivers { get => _drivers; private set => _drivers = value; }
|
|
||||||
public List<Zone> MainZones { get => _mainZones; set => _mainZones = value; }
|
|
||||||
|
|
||||||
//All the image infos will be deleted in not too much time when the merge with the program that recovers the images
|
|
||||||
const string DEFAULT_IMAGE_NAME = "screen_";
|
|
||||||
// You will defenitely have to change this if you want to be able to see debug images
|
|
||||||
public const string DEBUG_DUMP_FOLDER = @"C:\Users\Moi\Desktop\imgDump\Decode\";
|
|
||||||
const int NUMBER_OF_DRIVERS = 20;
|
|
||||||
|
|
||||||
public OCRDecoder(string configFile, string imageFolder)
|
|
||||||
{
|
|
||||||
ConfigFile = configFile;
|
|
||||||
ImagesFolder = imageFolder;
|
|
||||||
Load(82);
|
|
||||||
}
|
|
||||||
/// <summary>
|
|
||||||
/// Method that reads the JSON config file and create all the Zones and Windows
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="imageNumber">The image #id on wich you want to create the zones on</param>
|
|
||||||
private void Load(int imageNumber)
|
|
||||||
{
|
|
||||||
MainZones = new List<Zone>();
|
|
||||||
try
|
|
||||||
{
|
|
||||||
FullImage = (Bitmap)Image.FromFile(ImagesFolder + DEFAULT_IMAGE_NAME + imageNumber + ".png");
|
|
||||||
}
|
|
||||||
catch
|
|
||||||
{
|
|
||||||
MessageBox.Show("Trouble reaching the image");
|
|
||||||
//Maybe a bit to harsh, Ill see what I can do to soft this a bit
|
|
||||||
Application.Exit();
|
|
||||||
}
|
|
||||||
|
|
||||||
Zone MainZone;
|
|
||||||
try
|
|
||||||
{
|
|
||||||
using (var streamReader = new StreamReader(ConfigFile))
|
|
||||||
{
|
|
||||||
var jsonText = streamReader.ReadToEnd();
|
|
||||||
var jsonDocument = JsonDocument.Parse(jsonText);
|
|
||||||
|
|
||||||
var driversNames = jsonDocument.RootElement.GetProperty("Drivers");
|
|
||||||
Drivers = new List<string>();
|
|
||||||
|
|
||||||
foreach (var nameElement in driversNames.EnumerateArray())
|
|
||||||
{
|
|
||||||
Drivers.Add(nameElement.GetString());
|
|
||||||
}
|
|
||||||
|
|
||||||
var mainProperty = jsonDocument.RootElement.GetProperty("Main");
|
|
||||||
Point MainPosition = new Point(mainProperty.GetProperty("x").GetInt32(), mainProperty.GetProperty("y").GetInt32());
|
|
||||||
Size MainSize = new Size(mainProperty.GetProperty("width").GetInt32(), mainProperty.GetProperty("height").GetInt32());
|
|
||||||
Rectangle MainRectangle = new Rectangle(MainPosition, MainSize);
|
|
||||||
MainZone = new Zone(FullImage, MainRectangle);
|
|
||||||
|
|
||||||
var zones = mainProperty.GetProperty("Zones");
|
|
||||||
var driverZone = zones[0].GetProperty("DriverZone");
|
|
||||||
|
|
||||||
Point FirstZonePosition = new Point(driverZone.GetProperty("x").GetInt32(), driverZone.GetProperty("y").GetInt32());
|
|
||||||
Size FirstZoneSize = new Size(driverZone.GetProperty("width").GetInt32(), driverZone.GetProperty("height").GetInt32());
|
|
||||||
|
|
||||||
var windows = driverZone.GetProperty("Windows");
|
|
||||||
|
|
||||||
//var driverPosition = windows.GetProperty("Position");
|
|
||||||
var driverPosition = windows[0].GetProperty("Position");
|
|
||||||
Size driverPositionArea = new Size(driverPosition.GetProperty("width").GetInt32(), FirstZoneSize.Height);
|
|
||||||
Point driverPositionPosition = new Point(driverPosition.GetProperty("x").GetInt32(), driverPosition.GetProperty("y").GetInt32());
|
|
||||||
|
|
||||||
var driverGapToLeader = windows[0].GetProperty("GapToLeader");
|
|
||||||
Size driverGapToLeaderArea = new Size(driverGapToLeader.GetProperty("width").GetInt32(), FirstZoneSize.Height);
|
|
||||||
Point driverGapToLeaderPosition = new Point(driverGapToLeader.GetProperty("x").GetInt32(), driverGapToLeader.GetProperty("y").GetInt32());
|
|
||||||
|
|
||||||
var driverLapTime = windows[0].GetProperty("LapTime");
|
|
||||||
Size driverLapTimeArea = new Size(driverLapTime.GetProperty("width").GetInt32(), FirstZoneSize.Height);
|
|
||||||
Point driverLapTimePosition = new Point(driverLapTime.GetProperty("x").GetInt32(), driverLapTime.GetProperty("y").GetInt32());
|
|
||||||
|
|
||||||
|
|
||||||
var driverDrs = windows[0].GetProperty("Drs");
|
|
||||||
Size driverDrsArea = new Size(driverDrs.GetProperty("width").GetInt32(), FirstZoneSize.Height);
|
|
||||||
Point driverDrsPosition = new Point(driverDrs.GetProperty("x").GetInt32(), driverDrs.GetProperty("y").GetInt32());
|
|
||||||
|
|
||||||
var driverTyres = windows[0].GetProperty("Tyres");
|
|
||||||
Size driverTyresArea = new Size(driverTyres.GetProperty("width").GetInt32(), FirstZoneSize.Height);
|
|
||||||
Point driverTyresPosition = new Point(driverTyres.GetProperty("x").GetInt32(), driverTyres.GetProperty("y").GetInt32());
|
|
||||||
|
|
||||||
var driverName = windows[0].GetProperty("Name");
|
|
||||||
Size driverNameArea = new Size(driverName.GetProperty("width").GetInt32(), FirstZoneSize.Height);
|
|
||||||
Point driverNamePosition = new Point(driverName.GetProperty("x").GetInt32(), driverName.GetProperty("y").GetInt32());
|
|
||||||
|
|
||||||
var driverSector1 = windows[0].GetProperty("Sector1");
|
|
||||||
Size driverSector1Area = new Size(driverSector1.GetProperty("width").GetInt32(), FirstZoneSize.Height);
|
|
||||||
Point driverSector1Position = new Point(driverSector1.GetProperty("x").GetInt32(), driverSector1.GetProperty("y").GetInt32());
|
|
||||||
|
|
||||||
var driverSector2 = windows[0].GetProperty("Sector2");
|
|
||||||
Size driverSector2Area = new Size(driverSector2.GetProperty("width").GetInt32(), FirstZoneSize.Height);
|
|
||||||
Point driverSector2Position = new Point(driverSector2.GetProperty("x").GetInt32(), driverSector2.GetProperty("y").GetInt32());
|
|
||||||
|
|
||||||
var driverSector3 = windows[0].GetProperty("Sector3");
|
|
||||||
Size driverSector3Area = new Size(driverSector3.GetProperty("width").GetInt32(), FirstZoneSize.Height);
|
|
||||||
Point driverSector3Position = new Point(driverSector3.GetProperty("x").GetInt32(), driverSector3.GetProperty("y").GetInt32());
|
|
||||||
|
|
||||||
float offset = (((float)MainZone.ZoneImage.Height - (float)(Drivers.Count * FirstZoneSize.Height)) / (float)Drivers.Count);
|
|
||||||
Bitmap MainZoneImage = MainZone.ZoneImage;
|
|
||||||
List<Zone> zonesToAdd = new List<Zone>();
|
|
||||||
List<Bitmap> zonesImages = new List<Bitmap>();
|
|
||||||
|
|
||||||
for (int i = 0; i < NUMBER_OF_DRIVERS; i++)
|
|
||||||
{
|
|
||||||
Point tmpPos = new Point(0, FirstZonePosition.Y + i * FirstZoneSize.Height - Convert.ToInt32(i * offset));
|
|
||||||
Zone newDriverZone = new Zone(MainZoneImage, new Rectangle(tmpPos, FirstZoneSize));
|
|
||||||
zonesToAdd.Add(newDriverZone);
|
|
||||||
zonesImages.Add(newDriverZone.ZoneImage);
|
|
||||||
}
|
|
||||||
|
|
||||||
//Parallel.For(0, NUMBER_OF_DRIVERS, i =>
|
|
||||||
for (int i = 0; i < NUMBER_OF_DRIVERS; i++)
|
|
||||||
{
|
|
||||||
Zone newDriverZone = zonesToAdd[(int)i];
|
|
||||||
Bitmap zoneImg = zonesImages[(int)i];
|
|
||||||
|
|
||||||
newDriverZone.AddWindow(new DriverPositionWindow(zoneImg, new Rectangle(driverPositionPosition, driverPositionArea)));
|
|
||||||
newDriverZone.AddWindow(new DriverGapToLeaderWindow(zoneImg, new Rectangle(driverGapToLeaderPosition, driverGapToLeaderArea)));
|
|
||||||
newDriverZone.AddWindow(new DriverLapTimeWindow(zoneImg, new Rectangle(driverLapTimePosition, driverLapTimeArea)));
|
|
||||||
newDriverZone.AddWindow(new DriverDrsWindow(zoneImg, new Rectangle(driverDrsPosition, driverDrsArea)));
|
|
||||||
newDriverZone.AddWindow(new DriverTyresWindow(zoneImg, new Rectangle(driverTyresPosition, driverTyresArea)));
|
|
||||||
newDriverZone.AddWindow(new DriverNameWindow(zoneImg, new Rectangle(driverNamePosition, driverNameArea)));
|
|
||||||
newDriverZone.AddWindow(new DriverSectorWindow(zoneImg, new Rectangle(driverSector1Position, driverSector1Area)));
|
|
||||||
newDriverZone.AddWindow(new DriverSectorWindow(zoneImg, new Rectangle(driverSector2Position, driverSector2Area)));
|
|
||||||
newDriverZone.AddWindow(new DriverSectorWindow(zoneImg, new Rectangle(driverSector3Position, driverSector3Area)));
|
|
||||||
|
|
||||||
MainZone.AddZone(newDriverZone);
|
|
||||||
}//);
|
|
||||||
//MessageBox.Show("We have a main zone with " + MainZone.Zones.Count() + " Driver zones with " + MainZone.Zones[4].Windows.Count() + " windows each and we have " + Drivers.Count + " drivers");
|
|
||||||
MainZones.Add(MainZone);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (IOException ex)
|
|
||||||
{
|
|
||||||
MessageBox.Show("Error reading JSON file: " + ex.Message);
|
|
||||||
}
|
|
||||||
catch (JsonException ex)
|
|
||||||
{
|
|
||||||
MessageBox.Show("Invalid JSON format: " + ex.Message);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/// <summary>
|
|
||||||
/// Changes the zones and windows to the new image
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="imageNumber">The #id of the new image on wich to do OCR</param>
|
|
||||||
public void ChangeImage(int imageNumber)
|
|
||||||
{
|
|
||||||
Bitmap img = null;
|
|
||||||
string imagePath = ImagesFolder + DEFAULT_IMAGE_NAME + imageNumber + ".png";
|
|
||||||
try
|
|
||||||
{
|
|
||||||
img = (Bitmap)Image.FromFile(imagePath);
|
|
||||||
}
|
|
||||||
catch
|
|
||||||
{
|
|
||||||
MessageBox.Show("Unable to reach the image at " + imagePath);
|
|
||||||
}
|
|
||||||
if (img != null)
|
|
||||||
{
|
|
||||||
FullImage = img;
|
|
||||||
foreach (Zone z in MainZones)
|
|
||||||
{
|
|
||||||
z.Image = img;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/// <summary>
|
|
||||||
/// Method that calls all the zones and windows to get the content they can find on the image to display them
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="idImage">The id of the image we are working with</param>
|
|
||||||
/// <returns>a string representation of all the returns</returns>
|
|
||||||
public async Task<string> Decode(int idImage)
|
|
||||||
{
|
|
||||||
string result = "";
|
|
||||||
ChangeImage(idImage);
|
|
||||||
List<DriverData> mainResults = new List<DriverData>();
|
|
||||||
|
|
||||||
//Decode
|
|
||||||
for (int mainZoneId = 0; mainZoneId < MainZones.Count; mainZoneId++)
|
|
||||||
{
|
|
||||||
switch (mainZoneId)
|
|
||||||
{
|
|
||||||
case 0:
|
|
||||||
//Main Zone
|
|
||||||
foreach (Zone z in MainZones[mainZoneId].Zones)
|
|
||||||
{
|
|
||||||
mainResults.Add(await z.Decode(Drivers));
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
//Next there could be a Title Zone and TrackInfoZone
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//Display
|
|
||||||
foreach (DriverData driver in mainResults)
|
|
||||||
{
|
|
||||||
result += driver.ToString();
|
|
||||||
result += Environment.NewLine;
|
|
||||||
}
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
/// <summary>
|
|
||||||
/// Method that can be used to convert an amount of miliseconds into a more readable human form
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="amountOfMs">The given amount of miliseconds ton convert</param>
|
|
||||||
/// <returns>A human readable string that represents the ms</returns>
|
|
||||||
public static string ConvertMsToTime(int amountOfMs)
|
|
||||||
{
|
|
||||||
//Convert.ToInt32 would round upand I dont want that
|
|
||||||
int minuts = (int)((float)amountOfMs / (1000f * 60f));
|
|
||||||
int seconds = (int)((amountOfMs - (minuts * 60f * 1000f)) / 1000);
|
|
||||||
int ms = amountOfMs - ((minuts * 60 * 1000) + (seconds * 1000));
|
|
||||||
|
|
||||||
return minuts + ":" + seconds.ToString("00") + ":" + ms.ToString("000");
|
|
||||||
}
|
|
||||||
/// <summary>
|
|
||||||
/// Old method that can draw on an image where the windows and zones are created. mostly used for debugging
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="idImage">the #id of the image we are working with</param>
|
|
||||||
/// <returns>the drawed bitmap</returns>
|
|
||||||
public Bitmap Draw(int idImage)
|
|
||||||
{
|
|
||||||
Bitmap result;
|
|
||||||
try
|
|
||||||
{
|
|
||||||
result = (Bitmap)Image.FromFile(ImagesFolder + DEFAULT_IMAGE_NAME + idImage + ".png");
|
|
||||||
}
|
|
||||||
catch
|
|
||||||
{
|
|
||||||
MessageBox.Show("Image could not be found");
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
Graphics g = Graphics.FromImage(result);
|
|
||||||
|
|
||||||
foreach (Zone z in MainZones)
|
|
||||||
{
|
|
||||||
int count = 0;
|
|
||||||
foreach (Zone zz in z.Zones)
|
|
||||||
{
|
|
||||||
g.DrawRectangle(Pens.Red, z.Bounds);
|
|
||||||
foreach (Window w in zz.Windows)
|
|
||||||
{
|
|
||||||
g.DrawRectangle(Pens.Blue, new Rectangle(z.Bounds.X + zz.Bounds.X, z.Bounds.Y + zz.Bounds.Y, zz.Bounds.Width, zz.Bounds.Height));
|
|
||||||
}
|
|
||||||
|
|
||||||
count++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Generated
-421
@@ -1,421 +0,0 @@
|
|||||||
namespace Test_Merge
|
|
||||||
{
|
|
||||||
partial class Settings
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Required designer variable.
|
|
||||||
/// </summary>
|
|
||||||
private System.ComponentModel.IContainer components = null;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Clean up any resources being used.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
|
|
||||||
protected override void Dispose(bool disposing)
|
|
||||||
{
|
|
||||||
if (disposing && (components != null))
|
|
||||||
{
|
|
||||||
components.Dispose();
|
|
||||||
}
|
|
||||||
base.Dispose(disposing);
|
|
||||||
}
|
|
||||||
|
|
||||||
#region Windows Form Designer generated code
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Required method for Designer support - do not modify
|
|
||||||
/// the contents of this method with the code editor.
|
|
||||||
/// </summary>
|
|
||||||
private void InitializeComponent()
|
|
||||||
{
|
|
||||||
this.label1 = new System.Windows.Forms.Label();
|
|
||||||
this.label2 = new System.Windows.Forms.Label();
|
|
||||||
this.gpbxInfos = new System.Windows.Forms.GroupBox();
|
|
||||||
this.tbxGpYear = new System.Windows.Forms.TextBox();
|
|
||||||
this.tbxGpName = new System.Windows.Forms.TextBox();
|
|
||||||
this.tbxGpUrl = new System.Windows.Forms.TextBox();
|
|
||||||
this.label4 = new System.Windows.Forms.Label();
|
|
||||||
this.label3 = new System.Windows.Forms.Label();
|
|
||||||
this.groupBox1 = new System.Windows.Forms.GroupBox();
|
|
||||||
this.lsbDrivers = new System.Windows.Forms.ListBox();
|
|
||||||
this.btnRemoveDriver = new System.Windows.Forms.Button();
|
|
||||||
this.btnAddDriver = new System.Windows.Forms.Button();
|
|
||||||
this.tbxDriverName = new System.Windows.Forms.TextBox();
|
|
||||||
this.groupBox2 = new System.Windows.Forms.GroupBox();
|
|
||||||
this.btnRefresh = new System.Windows.Forms.Button();
|
|
||||||
this.pbxMain = new System.Windows.Forms.PictureBox();
|
|
||||||
this.groupBox3 = new System.Windows.Forms.GroupBox();
|
|
||||||
this.pbxDriverZone = new System.Windows.Forms.PictureBox();
|
|
||||||
this.groupBox4 = new System.Windows.Forms.GroupBox();
|
|
||||||
this.label8 = new System.Windows.Forms.Label();
|
|
||||||
this.lsbPresets = new System.Windows.Forms.ListBox();
|
|
||||||
this.textBox5 = new System.Windows.Forms.TextBox();
|
|
||||||
this.btnSavePreset = new System.Windows.Forms.Button();
|
|
||||||
this.lblWindowsRemaining = new System.Windows.Forms.Label();
|
|
||||||
this.lblZonePointsRemaning = new System.Windows.Forms.Label();
|
|
||||||
this.lblWindowPointsRemaining = new System.Windows.Forms.Label();
|
|
||||||
this.btnCreateWindow = new System.Windows.Forms.Button();
|
|
||||||
this.btnCreatZone = new System.Windows.Forms.Button();
|
|
||||||
this.gpbxInfos.SuspendLayout();
|
|
||||||
this.groupBox1.SuspendLayout();
|
|
||||||
this.groupBox2.SuspendLayout();
|
|
||||||
((System.ComponentModel.ISupportInitialize)(this.pbxMain)).BeginInit();
|
|
||||||
this.groupBox3.SuspendLayout();
|
|
||||||
((System.ComponentModel.ISupportInitialize)(this.pbxDriverZone)).BeginInit();
|
|
||||||
this.groupBox4.SuspendLayout();
|
|
||||||
this.SuspendLayout();
|
|
||||||
//
|
|
||||||
// label1
|
|
||||||
//
|
|
||||||
this.label1.AutoSize = true;
|
|
||||||
this.label1.Font = new System.Drawing.Font("Microsoft YaHei UI", 16.2F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
|
|
||||||
this.label1.Location = new System.Drawing.Point(593, 16);
|
|
||||||
this.label1.Name = "label1";
|
|
||||||
this.label1.Size = new System.Drawing.Size(132, 36);
|
|
||||||
this.label1.TabIndex = 0;
|
|
||||||
this.label1.Text = "Setttings";
|
|
||||||
//
|
|
||||||
// label2
|
|
||||||
//
|
|
||||||
this.label2.AutoSize = true;
|
|
||||||
this.label2.Font = new System.Drawing.Font("Microsoft YaHei UI", 10.2F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
|
|
||||||
this.label2.Location = new System.Drawing.Point(6, 27);
|
|
||||||
this.label2.Name = "label2";
|
|
||||||
this.label2.Size = new System.Drawing.Size(132, 23);
|
|
||||||
this.label2.TabIndex = 1;
|
|
||||||
this.label2.Text = "Grand Prix URL";
|
|
||||||
//
|
|
||||||
// gpbxInfos
|
|
||||||
//
|
|
||||||
this.gpbxInfos.Controls.Add(this.tbxGpYear);
|
|
||||||
this.gpbxInfos.Controls.Add(this.tbxGpName);
|
|
||||||
this.gpbxInfos.Controls.Add(this.tbxGpUrl);
|
|
||||||
this.gpbxInfos.Controls.Add(this.label4);
|
|
||||||
this.gpbxInfos.Controls.Add(this.label3);
|
|
||||||
this.gpbxInfos.Controls.Add(this.label2);
|
|
||||||
this.gpbxInfos.Font = new System.Drawing.Font("Microsoft YaHei UI", 10.2F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
|
|
||||||
this.gpbxInfos.Location = new System.Drawing.Point(18, 55);
|
|
||||||
this.gpbxInfos.Name = "gpbxInfos";
|
|
||||||
this.gpbxInfos.Size = new System.Drawing.Size(259, 226);
|
|
||||||
this.gpbxInfos.TabIndex = 2;
|
|
||||||
this.gpbxInfos.TabStop = false;
|
|
||||||
this.gpbxInfos.Text = "RaceSettings";
|
|
||||||
//
|
|
||||||
// tbxGpYear
|
|
||||||
//
|
|
||||||
this.tbxGpYear.Font = new System.Drawing.Font("Microsoft YaHei UI", 10.2F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
|
|
||||||
this.tbxGpYear.Location = new System.Drawing.Point(6, 187);
|
|
||||||
this.tbxGpYear.Name = "tbxGpYear";
|
|
||||||
this.tbxGpYear.Size = new System.Drawing.Size(247, 29);
|
|
||||||
this.tbxGpYear.TabIndex = 6;
|
|
||||||
this.tbxGpYear.TextChanged += new System.EventHandler(this.tbxGpYear_TextChanged);
|
|
||||||
//
|
|
||||||
// tbxGpName
|
|
||||||
//
|
|
||||||
this.tbxGpName.Font = new System.Drawing.Font("Microsoft YaHei UI", 10.2F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
|
|
||||||
this.tbxGpName.Location = new System.Drawing.Point(6, 117);
|
|
||||||
this.tbxGpName.Name = "tbxGpName";
|
|
||||||
this.tbxGpName.Size = new System.Drawing.Size(247, 29);
|
|
||||||
this.tbxGpName.TabIndex = 5;
|
|
||||||
this.tbxGpName.TextChanged += new System.EventHandler(this.tbxGpName_TextChanged);
|
|
||||||
//
|
|
||||||
// tbxGpUrl
|
|
||||||
//
|
|
||||||
this.tbxGpUrl.Font = new System.Drawing.Font("Microsoft YaHei UI", 10.2F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
|
|
||||||
this.tbxGpUrl.Location = new System.Drawing.Point(6, 53);
|
|
||||||
this.tbxGpUrl.Name = "tbxGpUrl";
|
|
||||||
this.tbxGpUrl.Size = new System.Drawing.Size(247, 29);
|
|
||||||
this.tbxGpUrl.TabIndex = 4;
|
|
||||||
this.tbxGpUrl.TextChanged += new System.EventHandler(this.tbxGpUrl_TextChanged);
|
|
||||||
//
|
|
||||||
// label4
|
|
||||||
//
|
|
||||||
this.label4.AutoSize = true;
|
|
||||||
this.label4.Font = new System.Drawing.Font("Microsoft YaHei UI", 10.2F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
|
|
||||||
this.label4.Location = new System.Drawing.Point(6, 161);
|
|
||||||
this.label4.Name = "label4";
|
|
||||||
this.label4.Size = new System.Drawing.Size(45, 23);
|
|
||||||
this.label4.TabIndex = 3;
|
|
||||||
this.label4.Text = "Year";
|
|
||||||
//
|
|
||||||
// label3
|
|
||||||
//
|
|
||||||
this.label3.AutoSize = true;
|
|
||||||
this.label3.Font = new System.Drawing.Font("Microsoft YaHei UI", 10.2F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
|
|
||||||
this.label3.Location = new System.Drawing.Point(6, 91);
|
|
||||||
this.label3.Name = "label3";
|
|
||||||
this.label3.Size = new System.Drawing.Size(59, 23);
|
|
||||||
this.label3.TabIndex = 2;
|
|
||||||
this.label3.Text = "Name";
|
|
||||||
//
|
|
||||||
// groupBox1
|
|
||||||
//
|
|
||||||
this.groupBox1.Controls.Add(this.lsbDrivers);
|
|
||||||
this.groupBox1.Controls.Add(this.btnRemoveDriver);
|
|
||||||
this.groupBox1.Controls.Add(this.btnAddDriver);
|
|
||||||
this.groupBox1.Controls.Add(this.tbxDriverName);
|
|
||||||
this.groupBox1.Location = new System.Drawing.Point(18, 287);
|
|
||||||
this.groupBox1.Name = "groupBox1";
|
|
||||||
this.groupBox1.Size = new System.Drawing.Size(259, 376);
|
|
||||||
this.groupBox1.TabIndex = 3;
|
|
||||||
this.groupBox1.TabStop = false;
|
|
||||||
this.groupBox1.Text = "DriverList";
|
|
||||||
//
|
|
||||||
// lsbDrivers
|
|
||||||
//
|
|
||||||
this.lsbDrivers.Font = new System.Drawing.Font("Microsoft YaHei UI", 10F);
|
|
||||||
this.lsbDrivers.FormattingEnabled = true;
|
|
||||||
this.lsbDrivers.ItemHeight = 23;
|
|
||||||
this.lsbDrivers.Location = new System.Drawing.Point(10, 109);
|
|
||||||
this.lsbDrivers.Name = "lsbDrivers";
|
|
||||||
this.lsbDrivers.Size = new System.Drawing.Size(243, 257);
|
|
||||||
this.lsbDrivers.TabIndex = 10;
|
|
||||||
//
|
|
||||||
// btnRemoveDriver
|
|
||||||
//
|
|
||||||
this.btnRemoveDriver.Font = new System.Drawing.Font("Microsoft YaHei UI", 10.2F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
|
|
||||||
this.btnRemoveDriver.Location = new System.Drawing.Point(132, 24);
|
|
||||||
this.btnRemoveDriver.Name = "btnRemoveDriver";
|
|
||||||
this.btnRemoveDriver.Size = new System.Drawing.Size(121, 44);
|
|
||||||
this.btnRemoveDriver.TabIndex = 9;
|
|
||||||
this.btnRemoveDriver.Text = "Remove";
|
|
||||||
this.btnRemoveDriver.UseVisualStyleBackColor = true;
|
|
||||||
this.btnRemoveDriver.Click += new System.EventHandler(this.btnRemoveDriver_Click);
|
|
||||||
//
|
|
||||||
// btnAddDriver
|
|
||||||
//
|
|
||||||
this.btnAddDriver.Font = new System.Drawing.Font("Microsoft YaHei UI", 10.2F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
|
|
||||||
this.btnAddDriver.Location = new System.Drawing.Point(10, 24);
|
|
||||||
this.btnAddDriver.Name = "btnAddDriver";
|
|
||||||
this.btnAddDriver.Size = new System.Drawing.Size(116, 44);
|
|
||||||
this.btnAddDriver.TabIndex = 8;
|
|
||||||
this.btnAddDriver.Text = "Add";
|
|
||||||
this.btnAddDriver.UseVisualStyleBackColor = true;
|
|
||||||
this.btnAddDriver.Click += new System.EventHandler(this.btnAddDriver_Click);
|
|
||||||
//
|
|
||||||
// tbxDriverName
|
|
||||||
//
|
|
||||||
this.tbxDriverName.Font = new System.Drawing.Font("Microsoft YaHei UI", 10.2F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
|
|
||||||
this.tbxDriverName.Location = new System.Drawing.Point(10, 74);
|
|
||||||
this.tbxDriverName.Name = "tbxDriverName";
|
|
||||||
this.tbxDriverName.Size = new System.Drawing.Size(243, 29);
|
|
||||||
this.tbxDriverName.TabIndex = 7;
|
|
||||||
//
|
|
||||||
// groupBox2
|
|
||||||
//
|
|
||||||
this.groupBox2.Controls.Add(this.btnRefresh);
|
|
||||||
this.groupBox2.Controls.Add(this.pbxMain);
|
|
||||||
this.groupBox2.Font = new System.Drawing.Font("Microsoft YaHei UI", 10F);
|
|
||||||
this.groupBox2.Location = new System.Drawing.Point(283, 55);
|
|
||||||
this.groupBox2.Name = "groupBox2";
|
|
||||||
this.groupBox2.Size = new System.Drawing.Size(906, 608);
|
|
||||||
this.groupBox2.TabIndex = 4;
|
|
||||||
this.groupBox2.TabStop = false;
|
|
||||||
this.groupBox2.Text = "Preview";
|
|
||||||
//
|
|
||||||
// btnRefresh
|
|
||||||
//
|
|
||||||
this.btnRefresh.Location = new System.Drawing.Point(6, 23);
|
|
||||||
this.btnRefresh.Name = "btnRefresh";
|
|
||||||
this.btnRefresh.Size = new System.Drawing.Size(101, 33);
|
|
||||||
this.btnRefresh.TabIndex = 1;
|
|
||||||
this.btnRefresh.Text = "Refresh";
|
|
||||||
this.btnRefresh.UseVisualStyleBackColor = true;
|
|
||||||
this.btnRefresh.Click += new System.EventHandler(this.btnRefresh_Click);
|
|
||||||
//
|
|
||||||
// pbxMain
|
|
||||||
//
|
|
||||||
this.pbxMain.Location = new System.Drawing.Point(6, 23);
|
|
||||||
this.pbxMain.Name = "pbxMain";
|
|
||||||
this.pbxMain.Size = new System.Drawing.Size(900, 579);
|
|
||||||
this.pbxMain.SizeMode = System.Windows.Forms.PictureBoxSizeMode.Zoom;
|
|
||||||
this.pbxMain.TabIndex = 0;
|
|
||||||
this.pbxMain.TabStop = false;
|
|
||||||
this.pbxMain.Click += new System.EventHandler(this.pbxMain_Click);
|
|
||||||
//
|
|
||||||
// groupBox3
|
|
||||||
//
|
|
||||||
this.groupBox3.Controls.Add(this.pbxDriverZone);
|
|
||||||
this.groupBox3.Font = new System.Drawing.Font("Microsoft YaHei UI", 10F);
|
|
||||||
this.groupBox3.Location = new System.Drawing.Point(18, 669);
|
|
||||||
this.groupBox3.Name = "groupBox3";
|
|
||||||
this.groupBox3.Size = new System.Drawing.Size(1390, 83);
|
|
||||||
this.groupBox3.TabIndex = 5;
|
|
||||||
this.groupBox3.TabStop = false;
|
|
||||||
this.groupBox3.Text = "DriverZonePreview";
|
|
||||||
//
|
|
||||||
// pbxDriverZone
|
|
||||||
//
|
|
||||||
this.pbxDriverZone.Location = new System.Drawing.Point(10, 27);
|
|
||||||
this.pbxDriverZone.Name = "pbxDriverZone";
|
|
||||||
this.pbxDriverZone.Size = new System.Drawing.Size(1374, 50);
|
|
||||||
this.pbxDriverZone.SizeMode = System.Windows.Forms.PictureBoxSizeMode.Zoom;
|
|
||||||
this.pbxDriverZone.TabIndex = 0;
|
|
||||||
this.pbxDriverZone.TabStop = false;
|
|
||||||
this.pbxDriverZone.Click += new System.EventHandler(this.pbxDriverZone_Click);
|
|
||||||
//
|
|
||||||
// groupBox4
|
|
||||||
//
|
|
||||||
this.groupBox4.Controls.Add(this.label8);
|
|
||||||
this.groupBox4.Controls.Add(this.lsbPresets);
|
|
||||||
this.groupBox4.Controls.Add(this.textBox5);
|
|
||||||
this.groupBox4.Controls.Add(this.btnSavePreset);
|
|
||||||
this.groupBox4.Controls.Add(this.lblWindowsRemaining);
|
|
||||||
this.groupBox4.Controls.Add(this.lblZonePointsRemaning);
|
|
||||||
this.groupBox4.Controls.Add(this.lblWindowPointsRemaining);
|
|
||||||
this.groupBox4.Controls.Add(this.btnCreateWindow);
|
|
||||||
this.groupBox4.Controls.Add(this.btnCreatZone);
|
|
||||||
this.groupBox4.Font = new System.Drawing.Font("Microsoft YaHei UI", 10F);
|
|
||||||
this.groupBox4.Location = new System.Drawing.Point(1195, 55);
|
|
||||||
this.groupBox4.Name = "groupBox4";
|
|
||||||
this.groupBox4.Size = new System.Drawing.Size(213, 608);
|
|
||||||
this.groupBox4.TabIndex = 6;
|
|
||||||
this.groupBox4.TabStop = false;
|
|
||||||
this.groupBox4.Text = "Calibration settings";
|
|
||||||
//
|
|
||||||
// label8
|
|
||||||
//
|
|
||||||
this.label8.AutoSize = true;
|
|
||||||
this.label8.Location = new System.Drawing.Point(6, 314);
|
|
||||||
this.label8.Name = "label8";
|
|
||||||
this.label8.Size = new System.Drawing.Size(68, 23);
|
|
||||||
this.label8.TabIndex = 9;
|
|
||||||
this.label8.Text = "Presets";
|
|
||||||
//
|
|
||||||
// lsbPresets
|
|
||||||
//
|
|
||||||
this.lsbPresets.FormattingEnabled = true;
|
|
||||||
this.lsbPresets.ItemHeight = 23;
|
|
||||||
this.lsbPresets.Location = new System.Drawing.Point(10, 340);
|
|
||||||
this.lsbPresets.Name = "lsbPresets";
|
|
||||||
this.lsbPresets.Size = new System.Drawing.Size(197, 257);
|
|
||||||
this.lsbPresets.TabIndex = 8;
|
|
||||||
//
|
|
||||||
// textBox5
|
|
||||||
//
|
|
||||||
this.textBox5.Font = new System.Drawing.Font("Microsoft YaHei UI", 10.2F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
|
|
||||||
this.textBox5.Location = new System.Drawing.Point(10, 216);
|
|
||||||
this.textBox5.Name = "textBox5";
|
|
||||||
this.textBox5.Size = new System.Drawing.Size(197, 29);
|
|
||||||
this.textBox5.TabIndex = 7;
|
|
||||||
//
|
|
||||||
// btnSavePreset
|
|
||||||
//
|
|
||||||
this.btnSavePreset.Location = new System.Drawing.Point(6, 251);
|
|
||||||
this.btnSavePreset.Name = "btnSavePreset";
|
|
||||||
this.btnSavePreset.Size = new System.Drawing.Size(201, 40);
|
|
||||||
this.btnSavePreset.TabIndex = 7;
|
|
||||||
this.btnSavePreset.Text = "Save as new preset";
|
|
||||||
this.btnSavePreset.UseVisualStyleBackColor = true;
|
|
||||||
//
|
|
||||||
// lblWindowsRemaining
|
|
||||||
//
|
|
||||||
this.lblWindowsRemaining.AutoSize = true;
|
|
||||||
this.lblWindowsRemaining.Location = new System.Drawing.Point(6, 184);
|
|
||||||
this.lblWindowsRemaining.Name = "lblWindowsRemaining";
|
|
||||||
this.lblWindowsRemaining.Size = new System.Drawing.Size(183, 23);
|
|
||||||
this.lblWindowsRemaining.TabIndex = 6;
|
|
||||||
this.lblWindowsRemaining.Text = "7 windows remaining";
|
|
||||||
//
|
|
||||||
// lblZonePointsRemaning
|
|
||||||
//
|
|
||||||
this.lblZonePointsRemaning.AutoSize = true;
|
|
||||||
this.lblZonePointsRemaning.Location = new System.Drawing.Point(6, 85);
|
|
||||||
this.lblZonePointsRemaning.Name = "lblZonePointsRemaning";
|
|
||||||
this.lblZonePointsRemaning.Size = new System.Drawing.Size(163, 23);
|
|
||||||
this.lblZonePointsRemaning.TabIndex = 5;
|
|
||||||
this.lblZonePointsRemaning.Text = "0 points remaining";
|
|
||||||
//
|
|
||||||
// lblWindowPointsRemaining
|
|
||||||
//
|
|
||||||
this.lblWindowPointsRemaining.AutoSize = true;
|
|
||||||
this.lblWindowPointsRemaining.Location = new System.Drawing.Point(6, 161);
|
|
||||||
this.lblWindowPointsRemaining.Name = "lblWindowPointsRemaining";
|
|
||||||
this.lblWindowPointsRemaining.Size = new System.Drawing.Size(163, 23);
|
|
||||||
this.lblWindowPointsRemaining.TabIndex = 4;
|
|
||||||
this.lblWindowPointsRemaining.Text = "0 points remaining";
|
|
||||||
//
|
|
||||||
// btnCreateWindow
|
|
||||||
//
|
|
||||||
this.btnCreateWindow.Location = new System.Drawing.Point(6, 118);
|
|
||||||
this.btnCreateWindow.Name = "btnCreateWindow";
|
|
||||||
this.btnCreateWindow.Size = new System.Drawing.Size(201, 40);
|
|
||||||
this.btnCreateWindow.TabIndex = 2;
|
|
||||||
this.btnCreateWindow.Text = "Create new Window";
|
|
||||||
this.btnCreateWindow.UseVisualStyleBackColor = true;
|
|
||||||
this.btnCreateWindow.Click += new System.EventHandler(this.btnCreateWindow_Click);
|
|
||||||
//
|
|
||||||
// btnCreatZone
|
|
||||||
//
|
|
||||||
this.btnCreatZone.Location = new System.Drawing.Point(6, 42);
|
|
||||||
this.btnCreatZone.Name = "btnCreatZone";
|
|
||||||
this.btnCreatZone.Size = new System.Drawing.Size(201, 40);
|
|
||||||
this.btnCreatZone.TabIndex = 1;
|
|
||||||
this.btnCreatZone.Text = "Create main zone";
|
|
||||||
this.btnCreatZone.UseVisualStyleBackColor = true;
|
|
||||||
this.btnCreatZone.Click += new System.EventHandler(this.btnCreatZone_Click);
|
|
||||||
//
|
|
||||||
// Settings
|
|
||||||
//
|
|
||||||
this.AutoScaleDimensions = new System.Drawing.SizeF(8F, 19F);
|
|
||||||
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
|
|
||||||
this.ClientSize = new System.Drawing.Size(1420, 760);
|
|
||||||
this.Controls.Add(this.groupBox4);
|
|
||||||
this.Controls.Add(this.groupBox3);
|
|
||||||
this.Controls.Add(this.groupBox2);
|
|
||||||
this.Controls.Add(this.groupBox1);
|
|
||||||
this.Controls.Add(this.gpbxInfos);
|
|
||||||
this.Controls.Add(this.label1);
|
|
||||||
this.Font = new System.Drawing.Font("Microsoft YaHei UI", 7.8F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
|
|
||||||
this.Margin = new System.Windows.Forms.Padding(3, 4, 3, 4);
|
|
||||||
this.Name = "Settings";
|
|
||||||
this.StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen;
|
|
||||||
this.Text = "Settings";
|
|
||||||
this.FormClosing += new System.Windows.Forms.FormClosingEventHandler(this.Settings_FormClosing);
|
|
||||||
this.gpbxInfos.ResumeLayout(false);
|
|
||||||
this.gpbxInfos.PerformLayout();
|
|
||||||
this.groupBox1.ResumeLayout(false);
|
|
||||||
this.groupBox1.PerformLayout();
|
|
||||||
this.groupBox2.ResumeLayout(false);
|
|
||||||
((System.ComponentModel.ISupportInitialize)(this.pbxMain)).EndInit();
|
|
||||||
this.groupBox3.ResumeLayout(false);
|
|
||||||
((System.ComponentModel.ISupportInitialize)(this.pbxDriverZone)).EndInit();
|
|
||||||
this.groupBox4.ResumeLayout(false);
|
|
||||||
this.groupBox4.PerformLayout();
|
|
||||||
this.ResumeLayout(false);
|
|
||||||
this.PerformLayout();
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
private System.Windows.Forms.Label label1;
|
|
||||||
private System.Windows.Forms.Label label2;
|
|
||||||
private System.Windows.Forms.GroupBox gpbxInfos;
|
|
||||||
private System.Windows.Forms.TextBox tbxGpYear;
|
|
||||||
private System.Windows.Forms.TextBox tbxGpName;
|
|
||||||
private System.Windows.Forms.TextBox tbxGpUrl;
|
|
||||||
private System.Windows.Forms.Label label4;
|
|
||||||
private System.Windows.Forms.Label label3;
|
|
||||||
private System.Windows.Forms.GroupBox groupBox1;
|
|
||||||
private System.Windows.Forms.ListBox lsbDrivers;
|
|
||||||
private System.Windows.Forms.Button btnRemoveDriver;
|
|
||||||
private System.Windows.Forms.Button btnAddDriver;
|
|
||||||
private System.Windows.Forms.TextBox tbxDriverName;
|
|
||||||
private System.Windows.Forms.GroupBox groupBox2;
|
|
||||||
private System.Windows.Forms.PictureBox pbxMain;
|
|
||||||
private System.Windows.Forms.GroupBox groupBox3;
|
|
||||||
private System.Windows.Forms.PictureBox pbxDriverZone;
|
|
||||||
private System.Windows.Forms.GroupBox groupBox4;
|
|
||||||
private System.Windows.Forms.Button btnCreateWindow;
|
|
||||||
private System.Windows.Forms.Button btnCreatZone;
|
|
||||||
private System.Windows.Forms.ListBox lsbPresets;
|
|
||||||
private System.Windows.Forms.TextBox textBox5;
|
|
||||||
private System.Windows.Forms.Button btnSavePreset;
|
|
||||||
private System.Windows.Forms.Label lblWindowsRemaining;
|
|
||||||
private System.Windows.Forms.Label lblZonePointsRemaning;
|
|
||||||
private System.Windows.Forms.Label lblWindowPointsRemaining;
|
|
||||||
private System.Windows.Forms.Label label8;
|
|
||||||
private System.Windows.Forms.Button btnRefresh;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,309 +0,0 @@
|
|||||||
|
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
using System.Drawing;
|
|
||||||
using System.IO;
|
|
||||||
using Tesseract;
|
|
||||||
using System.Text.RegularExpressions;
|
|
||||||
using System.Drawing.Drawing2D;
|
|
||||||
|
|
||||||
namespace Test_Merge
|
|
||||||
{
|
|
||||||
public class Window
|
|
||||||
{
|
|
||||||
private Rectangle _bounds;
|
|
||||||
private Bitmap _image;
|
|
||||||
private string _name;
|
|
||||||
protected TesseractEngine Engine;
|
|
||||||
public Rectangle Bounds { get => _bounds; private set => _bounds = value; }
|
|
||||||
public Bitmap Image { get => _image; set => _image = value; }
|
|
||||||
public string Name { get => _name; protected set => _name = value; }
|
|
||||||
//This will have to be changed if you want to make it run on your machine
|
|
||||||
public static DirectoryInfo TESS_DATA_FOLDER = new DirectoryInfo(@"C:\Users\Moi\Pictures\SeleniumScreens\TessData");
|
|
||||||
|
|
||||||
public Bitmap WindowImage
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
//This little trickery lets you have the image that the window sees
|
|
||||||
Bitmap sample = new Bitmap(Bounds.Width, Bounds.Height);
|
|
||||||
Graphics g = Graphics.FromImage(sample);
|
|
||||||
g.DrawImage(Image, new Rectangle(0, 0, sample.Width, sample.Height), Bounds, GraphicsUnit.Pixel);
|
|
||||||
return sample;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
public Window(Bitmap image, Rectangle bounds)
|
|
||||||
{
|
|
||||||
Image = image;
|
|
||||||
Bounds = bounds;
|
|
||||||
Engine = new TesseractEngine(TESS_DATA_FOLDER.FullName, "eng", EngineMode.Default);
|
|
||||||
Engine.DefaultPageSegMode = PageSegMode.SingleLine;
|
|
||||||
}
|
|
||||||
/// <summary>
|
|
||||||
/// Method that will have to be used by the childrens to let the model make them decode the images they have
|
|
||||||
/// </summary>
|
|
||||||
/// <returns>Returns an object because we dont know what kind of return it will be</returns>
|
|
||||||
public virtual async Task<Object> DecodePng()
|
|
||||||
{
|
|
||||||
return "NaN";
|
|
||||||
}
|
|
||||||
/// <summary>
|
|
||||||
/// Method that will have to be used by the childrens to let the model make them decode the images they have
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="driverList">This is a list of the different possible drivers in the race. It should not be too big but NEVER be too short</param>
|
|
||||||
/// <returns>Returns an object because we dont know what kind of return it will be</returns>
|
|
||||||
public virtual async Task<Object> DecodePng(List<string> driverList)
|
|
||||||
{
|
|
||||||
return "NaN";
|
|
||||||
}
|
|
||||||
/// <summary>
|
|
||||||
/// This converts an image into a byte[]. It can be usefull when doing unsafe stuff. Use at your own risks
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="inputImage">The image you want to convert</param>
|
|
||||||
/// <returns>A byte array containing the image informations</returns>
|
|
||||||
public static byte[] ImageToByte(Image inputImage)
|
|
||||||
{
|
|
||||||
using (var stream = new MemoryStream())
|
|
||||||
{
|
|
||||||
inputImage.Save(stream, System.Drawing.Imaging.ImageFormat.Png);
|
|
||||||
return stream.ToArray();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/// <summary>
|
|
||||||
/// This method is used to recover a time from a PNG using Tesseract OCR
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="windowImage">The image where the text is</param>
|
|
||||||
/// <param name="windowType">The type of window it is</param>
|
|
||||||
/// <param name="Engine">The Tesseract Engine</param>
|
|
||||||
/// <returns>The time in milliseconds</returns>
|
|
||||||
public static async Task<int> GetTimeFromPng(Bitmap windowImage, OcrImage.WindowType windowType, TesseractEngine Engine)
|
|
||||||
{
|
|
||||||
//Kind of a big method but it has a lot of error handling and has to work with three special cases
|
|
||||||
string rawResult = "";
|
|
||||||
int result = 0;
|
|
||||||
|
|
||||||
switch (windowType)
|
|
||||||
{
|
|
||||||
case OcrImage.WindowType.Sector:
|
|
||||||
//The usual sector is in this form : 33.456
|
|
||||||
Engine.SetVariable("tessedit_char_whitelist", "0123456789.");
|
|
||||||
break;
|
|
||||||
case OcrImage.WindowType.LapTime:
|
|
||||||
//The usual Lap time is in this form : 1:45:345
|
|
||||||
Engine.SetVariable("tessedit_char_whitelist", "0123456789.:");
|
|
||||||
break;
|
|
||||||
case OcrImage.WindowType.Gap:
|
|
||||||
//The usual Gap is in this form : + 34.567
|
|
||||||
Engine.SetVariable("tessedit_char_whitelist", "0123456789.+");
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
Engine.SetVariable("tessedit_char_whitelist", "");
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
Bitmap enhancedImage = new OcrImage(windowImage).Enhance(windowType);
|
|
||||||
|
|
||||||
var tessImage = Pix.LoadFromMemory(ImageToByte(enhancedImage));
|
|
||||||
|
|
||||||
Page page = Engine.Process(tessImage);
|
|
||||||
Graphics g = Graphics.FromImage(enhancedImage);
|
|
||||||
// Get the iterator for the page layout
|
|
||||||
using (var iter = page.GetIterator())
|
|
||||||
{
|
|
||||||
// Loop over the elements of the page layout
|
|
||||||
iter.Begin();
|
|
||||||
do
|
|
||||||
{
|
|
||||||
// Get the text for the current element
|
|
||||||
try
|
|
||||||
{
|
|
||||||
rawResult += iter.GetText(PageIteratorLevel.Word);
|
|
||||||
}
|
|
||||||
catch
|
|
||||||
{
|
|
||||||
//nothing we just dont add it if its not a number
|
|
||||||
}
|
|
||||||
} while (iter.Next(PageIteratorLevel.Word));
|
|
||||||
}
|
|
||||||
|
|
||||||
List<string> rawNumbers;
|
|
||||||
|
|
||||||
//In the gaps we can find '+' but we dont care about it its redondant a driver will never be - something
|
|
||||||
if (windowType == OcrImage.WindowType.Gap)
|
|
||||||
rawResult = Regex.Replace(rawResult, "[^0-9.:]", "");
|
|
||||||
|
|
||||||
//Splits into minuts seconds miliseconds
|
|
||||||
rawNumbers = rawResult.Split('.', ':').ToList<string>();
|
|
||||||
//removes any empty cells (tho this usually sign of a really bad OCR implementation tbh will have to be fixed higher in the chian)
|
|
||||||
rawNumbers.RemoveAll(x => ((string)x) == "");
|
|
||||||
|
|
||||||
if (rawNumbers.Count == 3)
|
|
||||||
{
|
|
||||||
//mm:ss:ms
|
|
||||||
result = (Convert.ToInt32(rawNumbers[0]) * 1000 * 60) + (Convert.ToInt32(rawNumbers[1]) * 1000) + Convert.ToInt32(rawNumbers[2]);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (rawNumbers.Count == 2)
|
|
||||||
{
|
|
||||||
//ss:ms
|
|
||||||
result = (Convert.ToInt32(rawNumbers[0]) * 1000) + Convert.ToInt32(rawNumbers[1]);
|
|
||||||
|
|
||||||
if (result > 999999)
|
|
||||||
{
|
|
||||||
//We know that we have way too much seconds to make a minut
|
|
||||||
//Its usually because the ":" have been interpreted as a number
|
|
||||||
int minuts = (int)(rawNumbers[0][0] - '0');
|
|
||||||
// rawNumbers[0][1] should contain the : that has been mistaken
|
|
||||||
int seconds = Convert.ToInt32(rawNumbers[0][2].ToString() + rawNumbers[0][3].ToString());
|
|
||||||
int ms = Convert.ToInt32(rawNumbers[1]);
|
|
||||||
result = (Convert.ToInt32(minuts) * 1000 * 60) + (Convert.ToInt32(seconds) * 1000) + Convert.ToInt32(ms);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (rawNumbers.Count == 1)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
result = Convert.ToInt32(rawNumbers[0]);
|
|
||||||
}
|
|
||||||
catch
|
|
||||||
{
|
|
||||||
//It can be because the input is empty or because its the LEADER bracket
|
|
||||||
result = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
//Auuuugh
|
|
||||||
result = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
page.Dispose();
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
/// <summary>
|
|
||||||
/// Method that recovers strings from an image using Tesseract OCR
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="WindowImage">The image of the window that contains text</param>
|
|
||||||
/// <param name="Engine">The Tesseract engine</param>
|
|
||||||
/// <param name="allowedChars">The list of allowed chars</param>
|
|
||||||
/// <param name="windowType">The type of window the text is on. Depending on the context the OCR will behave differently</param>
|
|
||||||
/// <returns>the string it found</returns>
|
|
||||||
public static async Task<string> GetStringFromPng(Bitmap WindowImage, TesseractEngine Engine, string allowedChars = "", OcrImage.WindowType windowType = OcrImage.WindowType.Text)
|
|
||||||
{
|
|
||||||
string result = "";
|
|
||||||
|
|
||||||
Engine.SetVariable("tessedit_char_whitelist", allowedChars);
|
|
||||||
|
|
||||||
Bitmap rawData = WindowImage;
|
|
||||||
Bitmap enhancedImage = new OcrImage(rawData).Enhance(windowType);
|
|
||||||
|
|
||||||
Page page = Engine.Process(enhancedImage);
|
|
||||||
using (var iter = page.GetIterator())
|
|
||||||
{
|
|
||||||
iter.Begin();
|
|
||||||
do
|
|
||||||
{
|
|
||||||
result += iter.GetText(PageIteratorLevel.Word);
|
|
||||||
} while (iter.Next(PageIteratorLevel.Word));
|
|
||||||
}
|
|
||||||
page.Dispose();
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
/// <summary>
|
|
||||||
/// Get a smaller image from a bigger one
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="inputBitmap">The big bitmap you want to get a part of</param>
|
|
||||||
/// <param name="newBitmapDimensions">The dimensions of the new bitmap</param>
|
|
||||||
/// <returns>The little bitmap</returns>
|
|
||||||
protected Bitmap GetSmallBitmapFromBigOne(Bitmap inputBitmap, Rectangle newBitmapDimensions)
|
|
||||||
{
|
|
||||||
Bitmap sample = new Bitmap(newBitmapDimensions.Width, newBitmapDimensions.Height);
|
|
||||||
Graphics g = Graphics.FromImage(sample);
|
|
||||||
g.DrawImage(inputBitmap, new Rectangle(0, 0, sample.Width, sample.Height), newBitmapDimensions, GraphicsUnit.Pixel);
|
|
||||||
return sample;
|
|
||||||
}
|
|
||||||
/// <summary>
|
|
||||||
/// Returns the closest string from a list of options
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="options">an array of all the possibilities</param>
|
|
||||||
/// <param name="testString">the string you want to compare</param>
|
|
||||||
/// <returns>The closest option</returns>
|
|
||||||
protected static string FindClosestMatch(List<string> options, string testString)
|
|
||||||
{
|
|
||||||
var closestMatch = "";
|
|
||||||
var closestDistance = int.MaxValue;
|
|
||||||
|
|
||||||
foreach (var item in options)
|
|
||||||
{
|
|
||||||
var distance = LevenshteinDistance(item, testString);
|
|
||||||
if (distance < closestDistance)
|
|
||||||
{
|
|
||||||
closestMatch = item;
|
|
||||||
closestDistance = distance;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return closestMatch;
|
|
||||||
}
|
|
||||||
//This method has been generated with the help of ChatGPT
|
|
||||||
/// <summary>
|
|
||||||
/// Method that computes a score of distance between two strings
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="string1">The first string (order irrelevant)</param>
|
|
||||||
/// <param name="string2">The second string (order irrelevant)</param>
|
|
||||||
/// <returns>The levenshtein distance</returns>
|
|
||||||
protected static int LevenshteinDistance(string string1, string string2)
|
|
||||||
{
|
|
||||||
if (string.IsNullOrEmpty(string1))
|
|
||||||
{
|
|
||||||
return string.IsNullOrEmpty(string2) ? 0 : string2.Length;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (string.IsNullOrEmpty(string2))
|
|
||||||
{
|
|
||||||
return string.IsNullOrEmpty(string1) ? 0 : string1.Length;
|
|
||||||
}
|
|
||||||
|
|
||||||
var d = new int[string1.Length + 1, string2.Length + 1];
|
|
||||||
for (var i = 0; i <= string1.Length; i++)
|
|
||||||
{
|
|
||||||
d[i, 0] = i;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (var j = 0; j <= string2.Length; j++)
|
|
||||||
{
|
|
||||||
d[0, j] = j;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (var i = 1; i <= string1.Length; i++)
|
|
||||||
{
|
|
||||||
for (var j = 1; j <= string2.Length; j++)
|
|
||||||
{
|
|
||||||
var cost = (string1[i - 1] == string2[j - 1]) ? 0 : 1;
|
|
||||||
d[i, j] = Math.Min(Math.Min(d[i - 1, j] + 1, d[i, j - 1] + 1), d[i - 1, j - 1] + cost);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return d[string1.Length, string2.Length];
|
|
||||||
}
|
|
||||||
public virtual string ToJSON()
|
|
||||||
{
|
|
||||||
string result = "";
|
|
||||||
|
|
||||||
result += "\"" + Name + "\"" + ":{" + Environment.NewLine;
|
|
||||||
result += "\t" + "\"x\":" + Bounds.X + "," + Environment.NewLine;
|
|
||||||
result += "\t" + "\"y\":" + Bounds.Y + "," + Environment.NewLine;
|
|
||||||
result += "\t" + "\"width\":" + Bounds.Width + Environment.NewLine;
|
|
||||||
result += "}";
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -3,7 +3,9 @@ Microsoft Visual Studio Solution File, Format Version 12.00
|
|||||||
# Visual Studio Version 17
|
# Visual Studio Version 17
|
||||||
VisualStudioVersion = 17.2.32526.322
|
VisualStudioVersion = 17.2.32526.322
|
||||||
MinimumVisualStudioVersion = 10.0.40219.1
|
MinimumVisualStudioVersion = 10.0.40219.1
|
||||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Test_Merge", "Test_Merge\Test_Merge.csproj", "{F6694884-3B45-4017-9C9A-A0AFFC508245}"
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TrackTrends", "TrackTrends\TrackTrends.csproj", "{F6694884-3B45-4017-9C9A-A0AFFC508245}"
|
||||||
|
EndProject
|
||||||
|
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{BAFC8496-36AE-4539-94DE-0E505E7A8F93}"
|
||||||
EndProject
|
EndProject
|
||||||
Global
|
Global
|
||||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||||
@@ -0,0 +1,30 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<configuration>
|
||||||
|
<configSections>
|
||||||
|
<!-- For more information on Entity Framework configuration, visit http://go.microsoft.com/fwlink/?LinkID=237468 -->
|
||||||
|
<section name="entityFramework" type="System.Data.Entity.Internal.ConfigFile.EntityFrameworkSection, EntityFramework, Version=6.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" requirePermission="false" />
|
||||||
|
</configSections>
|
||||||
|
<startup>
|
||||||
|
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.7.2" />
|
||||||
|
</startup>
|
||||||
|
<runtime>
|
||||||
|
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
|
||||||
|
<dependentAssembly>
|
||||||
|
<assemblyIdentity name="System.Runtime.CompilerServices.Unsafe" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
|
||||||
|
<bindingRedirect oldVersion="0.0.0.0-6.0.0.0" newVersion="6.0.0.0" />
|
||||||
|
</dependentAssembly>
|
||||||
|
</assemblyBinding>
|
||||||
|
</runtime>
|
||||||
|
<entityFramework>
|
||||||
|
<providers>
|
||||||
|
<provider invariantName="System.Data.SqlClient" type="System.Data.Entity.SqlServer.SqlProviderServices, EntityFramework.SqlServer" />
|
||||||
|
<provider invariantName="System.Data.SQLite.EF6" type="System.Data.SQLite.EF6.SQLiteProviderServices, System.Data.SQLite.EF6" />
|
||||||
|
</providers>
|
||||||
|
</entityFramework>
|
||||||
|
<system.data>
|
||||||
|
<DbProviderFactories>
|
||||||
|
<remove invariant="System.Data.SQLite.EF6" />
|
||||||
|
<add name="SQLite Data Provider (Entity Framework 6)" invariant="System.Data.SQLite.EF6" description=".NET Framework Data Provider for SQLite (Entity Framework 6)" type="System.Data.SQLite.EF6.SQLiteProviderFactory, System.Data.SQLite.EF6" />
|
||||||
|
<remove invariant="System.Data.SQLite" /><add name="SQLite Data Provider" invariant="System.Data.SQLite" description=".NET Framework Data Provider for SQLite" type="System.Data.SQLite.SQLiteFactory, System.Data.SQLite" /></DbProviderFactories>
|
||||||
|
</system.data>
|
||||||
|
</configuration>
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,261 @@
|
|||||||
|
/// Author : Maxime Rohmer
|
||||||
|
/// Date : 30/05/2023
|
||||||
|
/// File : ConfigurationTool.cs
|
||||||
|
/// Brief : Class that contains all the methods used to create config files for the main programm
|
||||||
|
/// Version : Alpha 1.0
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Drawing;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Tesseract;
|
||||||
|
using System.IO;
|
||||||
|
using System.Text.Json;
|
||||||
|
using System.Text.Json.Nodes;
|
||||||
|
|
||||||
|
namespace TrackTrends
|
||||||
|
{
|
||||||
|
public class ConfigurationTool
|
||||||
|
{
|
||||||
|
public Zone MainZone;
|
||||||
|
public const int NUMBER_OF_DRIVERS = 20;
|
||||||
|
public const int NUMBER_OF_ZONES = 9;
|
||||||
|
public const string CONFIGS_FOLDER_NAME = "./Presets/";
|
||||||
|
/// <summary>
|
||||||
|
/// Creates the configuration tool. It can only be created if you already have the dimensions of the main zone
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="fullImage">The full image coming from the F1TV Data Channel</param>
|
||||||
|
/// <param name="mainZoneDimensions">The dimensions of the zone where all the drivers data are situated</param>
|
||||||
|
public ConfigurationTool(Bitmap fullImage, Rectangle mainZoneDimensions)
|
||||||
|
{
|
||||||
|
MainZone = new Zone(fullImage, mainZoneDimensions,"Main");
|
||||||
|
AutoCalibrate();
|
||||||
|
}
|
||||||
|
/// <summary>
|
||||||
|
/// Resets the main zone
|
||||||
|
/// </summary>
|
||||||
|
public void ResetMainZone()
|
||||||
|
{
|
||||||
|
MainZone.ResetZones();
|
||||||
|
}
|
||||||
|
/// <summary>
|
||||||
|
/// Reset the windows
|
||||||
|
/// </summary>
|
||||||
|
public void ResetWindows()
|
||||||
|
{
|
||||||
|
MainZone.ResetWindows();
|
||||||
|
}
|
||||||
|
/// <summary>
|
||||||
|
/// Save the current config in a JSON file stored in /Presets/
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="drivers">A list of all the drivers in the GP. IMPORTANT, they need to ALL be mentionned or the program wont be able to detect the missing ones and will F up everything</param>
|
||||||
|
/// <param name="configName">The name the config should have</param>
|
||||||
|
public void SaveToJson(List<string> drivers, string configName)
|
||||||
|
{
|
||||||
|
string JSON = "";
|
||||||
|
|
||||||
|
JsonObject jsonFileObject = new JsonObject();
|
||||||
|
|
||||||
|
//Creates the mainZone object
|
||||||
|
JsonObject mainZoneObject = new JsonObject();
|
||||||
|
|
||||||
|
mainZoneObject.Add("x",MainZone.Bounds.X);
|
||||||
|
mainZoneObject.Add("y",MainZone.Bounds.Y);
|
||||||
|
mainZoneObject.Add("width",MainZone.Bounds.Width);
|
||||||
|
mainZoneObject.Add("height",MainZone.Bounds.Height);
|
||||||
|
|
||||||
|
JsonArray driverZonesArray = new JsonArray();
|
||||||
|
|
||||||
|
//Creates all the subzones that contain driver infos
|
||||||
|
int DriverID = 0;
|
||||||
|
foreach (Zone driverZone in MainZone.Zones)
|
||||||
|
{
|
||||||
|
DriverID++;
|
||||||
|
JsonObject driverZoneObject = new JsonObject();
|
||||||
|
driverZoneObject.Add("name","Driver"+DriverID);
|
||||||
|
driverZoneObject.Add("x", driverZone.Bounds.X);
|
||||||
|
driverZoneObject.Add("y", driverZone.Bounds.Y);
|
||||||
|
driverZoneObject.Add("width", driverZone.Bounds.Width);
|
||||||
|
driverZoneObject.Add("height", driverZone.Bounds.Height);
|
||||||
|
|
||||||
|
JsonArray windowsArray = new JsonArray();
|
||||||
|
JsonObject windowObject = new JsonObject();
|
||||||
|
|
||||||
|
//Creates all the windows of the current driver zone
|
||||||
|
//Note : We store ALL the windows and zones in the JSON because they are not spaced exactly the same on the main zone
|
||||||
|
foreach (Window window in driverZone.Windows)
|
||||||
|
{
|
||||||
|
windowObject.Add(window.Name, new JsonObject {
|
||||||
|
{ "x", window.Bounds.X },
|
||||||
|
{ "y", window.Bounds.Y },
|
||||||
|
{ "width", window.Bounds.Width },
|
||||||
|
{ "height", window.Bounds.Height }
|
||||||
|
});
|
||||||
|
}
|
||||||
|
windowsArray.Add(windowObject);
|
||||||
|
|
||||||
|
driverZoneObject.Add("Windows",windowsArray);
|
||||||
|
|
||||||
|
driverZonesArray.Add(driverZoneObject);
|
||||||
|
}
|
||||||
|
|
||||||
|
mainZoneObject.Add("DriverZones",driverZonesArray);
|
||||||
|
|
||||||
|
JsonArray driversArray = new JsonArray();
|
||||||
|
|
||||||
|
foreach (string driver in drivers)
|
||||||
|
{
|
||||||
|
driversArray.Add(driver);
|
||||||
|
}
|
||||||
|
|
||||||
|
mainZoneObject.Add("Drivers",driversArray);
|
||||||
|
|
||||||
|
jsonFileObject.Add("Main",mainZoneObject);
|
||||||
|
|
||||||
|
JSON = jsonFileObject.ToString();
|
||||||
|
|
||||||
|
//Saving the file
|
||||||
|
string path = CONFIGS_FOLDER_NAME + configName;
|
||||||
|
|
||||||
|
if (File.Exists(path + ".json"))
|
||||||
|
{
|
||||||
|
//We need to create a new name
|
||||||
|
int count = 2;
|
||||||
|
while (File.Exists(path + "_" + count + ".json"))
|
||||||
|
{
|
||||||
|
count++;
|
||||||
|
}
|
||||||
|
path += "_" + count + ".json";
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
path += ".json";
|
||||||
|
}
|
||||||
|
|
||||||
|
File.WriteAllText(path, JSON);
|
||||||
|
}
|
||||||
|
/// <summary>
|
||||||
|
/// Adds a window in the windows list
|
||||||
|
/// Be carefull of the order. It cant be random or it will crash. The programm expect the first to be position, second Gap to leader etc...
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="rectangles">The bounds of the window</param>
|
||||||
|
public void AddWindows(List<Rectangle> rectangles)
|
||||||
|
{
|
||||||
|
foreach (Zone driverZone in MainZone.Zones)
|
||||||
|
{
|
||||||
|
Bitmap zoneImage = driverZone.ZoneImage;
|
||||||
|
|
||||||
|
for (int i = 1; i <= rectangles.Count; i++)
|
||||||
|
{
|
||||||
|
switch (i)
|
||||||
|
{
|
||||||
|
case 1:
|
||||||
|
//First zone should be the driver's Position
|
||||||
|
driverZone.AddWindow(new DriverPositionWindow(driverZone.ZoneImage, rectangles[i - 1], false));
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
//Second zone should be the Gap to leader
|
||||||
|
driverZone.AddWindow(new DriverGapToLeaderWindow(driverZone.ZoneImage, rectangles[i - 1], false));
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
//Third zone should be the driver's Lap Time
|
||||||
|
driverZone.AddWindow(new DriverLapTimeWindow(driverZone.ZoneImage, rectangles[i - 1], false));
|
||||||
|
break;
|
||||||
|
case 4:
|
||||||
|
//Fourth zone should be the driver's DRS status
|
||||||
|
driverZone.AddWindow(new DriverDrsWindow(driverZone.ZoneImage, rectangles[i - 1], false));
|
||||||
|
break;
|
||||||
|
case 5:
|
||||||
|
//Fifth zone should be the driver's Tyre's informations
|
||||||
|
driverZone.AddWindow(new DriverTyresWindow(driverZone.ZoneImage, rectangles[i - 1], false));
|
||||||
|
break;
|
||||||
|
case 6:
|
||||||
|
//Sixth zone should be the driver's Name
|
||||||
|
driverZone.AddWindow(new DriverNameWindow(driverZone.ZoneImage, rectangles[i - 1], false));
|
||||||
|
break;
|
||||||
|
case 7:
|
||||||
|
//Seventh zone should be the driver's First Sector
|
||||||
|
driverZone.AddWindow(new DriverSectorWindow(driverZone.ZoneImage, rectangles[i - 1], 1, false));
|
||||||
|
break;
|
||||||
|
case 8:
|
||||||
|
//Zone number eight should be the driver's Second Sector
|
||||||
|
driverZone.AddWindow(new DriverSectorWindow(driverZone.ZoneImage, rectangles[i - 1], 2, false));
|
||||||
|
break;
|
||||||
|
case 9:
|
||||||
|
//Zone number nine should be the driver's Position Sector
|
||||||
|
driverZone.AddWindow(new DriverSectorWindow(driverZone.ZoneImage, rectangles[i - 1], 3, false));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/// <summary>
|
||||||
|
/// This will automatically create all the driver zones at the correct places if the main zone has been weel positionned
|
||||||
|
/// You cant just divide the image by the number of pilots or it will be messy and inconsistent at the end (Garbage in Garbage Out)
|
||||||
|
/// </summary>
|
||||||
|
public void AutoCalibrate()
|
||||||
|
{
|
||||||
|
List<Rectangle> detectedText = new List<Rectangle>();
|
||||||
|
List<Zone> zones = new List<Zone>();
|
||||||
|
|
||||||
|
TesseractEngine engine = new TesseractEngine(Window.TESS_DATA_FOLDER.FullName, "eng", EngineMode.Default);
|
||||||
|
Image image = MainZone.ZoneImage;
|
||||||
|
var tessImage = Pix.LoadFromMemory(Window.ImageToByte(image));
|
||||||
|
|
||||||
|
Page page = engine.Process(tessImage);
|
||||||
|
//Runs a quick OCR detection. Not to detect any content but just to detect where is all the text positionned.
|
||||||
|
//For each row it decides the best Zone location and adds it to the Driver zone list
|
||||||
|
using (var iter = page.GetIterator())
|
||||||
|
{
|
||||||
|
iter.Begin();
|
||||||
|
do
|
||||||
|
{
|
||||||
|
Rect boundingBox;
|
||||||
|
if (iter.TryGetBoundingBox(PageIteratorLevel.Word, out boundingBox))
|
||||||
|
{
|
||||||
|
//We remove all the rectangles that are definitely too big
|
||||||
|
if (boundingBox.Height < image.Height / NUMBER_OF_DRIVERS)
|
||||||
|
{
|
||||||
|
//Now we add a filter to only get the boxes in the right because they are much more reliable in size
|
||||||
|
if (boundingBox.X1 > image.Width / 2)
|
||||||
|
{
|
||||||
|
//Now we check if an other square box has been found roughly in the same y axis
|
||||||
|
bool match = false;
|
||||||
|
//The tolerance is roughly half the size that a window will be
|
||||||
|
int tolerance = (image.Height / NUMBER_OF_DRIVERS) / 2;
|
||||||
|
|
||||||
|
foreach (Rectangle rect in detectedText)
|
||||||
|
{
|
||||||
|
if (rect.Y > boundingBox.Y1 - tolerance && rect.Y < boundingBox.Y1 + tolerance)
|
||||||
|
{
|
||||||
|
//There already is a rectangle in this line
|
||||||
|
match = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//if nothing matched we can add it
|
||||||
|
if (!match)
|
||||||
|
detectedText.Add(new Rectangle(boundingBox.X1, boundingBox.Y1, boundingBox.Width, boundingBox.Height));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} while (iter.Next(PageIteratorLevel.Word));
|
||||||
|
}
|
||||||
|
//DEBUG
|
||||||
|
int i = 1;
|
||||||
|
foreach (Rectangle Rectangle in detectedText)
|
||||||
|
{
|
||||||
|
Rectangle windowRectangle;
|
||||||
|
Size windowSize = new Size(image.Width, image.Height / NUMBER_OF_DRIVERS);
|
||||||
|
Point windowLocation = new Point(0, (Rectangle.Y + Rectangle.Height / 2) - windowSize.Height / 2);
|
||||||
|
windowRectangle = new Rectangle(windowLocation, windowSize);
|
||||||
|
//We add the driver zones
|
||||||
|
Zone driverZone = new Zone(MainZone.ZoneImage, windowRectangle, "DriverZone");
|
||||||
|
MainZone.AddZone(driverZone);
|
||||||
|
//driverZone.ZoneImage.Save("Driver" + i+".png");
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,379 @@
|
|||||||
|
/// Author : Maxime Rohmer
|
||||||
|
/// Date : 30/05/2023
|
||||||
|
/// File : DataWrapper.cs
|
||||||
|
/// Brief : Class that is used to interface between the main Form (vue) and the Storage (wich is a class that wraps the sqlite database, so the model) its almost MVC :D
|
||||||
|
/// Version : Alpha 1.0
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using System.Windows.Forms;
|
||||||
|
using System.Drawing;
|
||||||
|
|
||||||
|
namespace TrackTrends
|
||||||
|
{
|
||||||
|
internal class DataWrapper
|
||||||
|
{
|
||||||
|
private Reader Reader;
|
||||||
|
private SqliteStorage Storage;
|
||||||
|
List<List<DriverData>> LiveDriverDataLogs = new List<List<DriverData>>();
|
||||||
|
//Note : It could be usefull to get the mainForm at the start of the programm and not have to take it in half of the methods.
|
||||||
|
/// <summary>
|
||||||
|
/// Constructs a new DataWrapper. It needs the config file so it can create a Reader, It also needs a first screenshot for the same reason
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="configFile">The JSON config file that is created by the configuration tool</param>
|
||||||
|
/// <param name="screenshot">A screenshot of the </param>
|
||||||
|
public DataWrapper(string configFile, Bitmap screenshot)
|
||||||
|
{
|
||||||
|
Reader = new Reader(configFile, screenshot, true);
|
||||||
|
//The Storage is here and on the Reader. It seems bad but it is ok as we dont use it at all to insert data and are only using it here to read some. The reader takes care of the inserts (Note: We could technically do both here but I did not find it usefull to transfer everything here)
|
||||||
|
Storage = Reader.Storage;
|
||||||
|
}
|
||||||
|
/// <summary>
|
||||||
|
/// Refreshes the controller so it has the latest driver datas (Be sure to call it everytime you need to use any other method and expects the data to be up to date)
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>Error code, 0 is success, 1 is not (Note: Maybe it could be interesting in the future to add some more error handling here)</returns>
|
||||||
|
public int Refresh()
|
||||||
|
{
|
||||||
|
LiveDriverDataLogs.Add(Reader.Decode(Reader.MainZones, Reader.Drivers));
|
||||||
|
if (LiveDriverDataLogs.Count > 0)
|
||||||
|
return 0;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
/// <summary>
|
||||||
|
/// Changes the image to the newest screenshot in all of the zones and windows
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="image">The new screenshot to put everywhere (Do not mix resolutions)</param>
|
||||||
|
public void ChangeImage(Bitmap image)
|
||||||
|
{
|
||||||
|
Reader.ChangeImage(image);
|
||||||
|
}
|
||||||
|
/// <summary>
|
||||||
|
/// Gets all the data from one driver and also displays into the given panel the last five laps (or less if its the sart of the race) Note: Its responsive :D
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="driverName">The name of the driver (should not be case sensitive but it MUST already exist in the first list that has been inserted into the DB)</param>
|
||||||
|
/// <param name="lastFiveLapsPanel">The pannel where you want the five last laps to be displayed</param>
|
||||||
|
/// <param name="form1">The Main form.</param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public DriverData GetFullDriverData(string driverName, Panel lastFiveLapsPanel, Main form1)
|
||||||
|
{
|
||||||
|
//Note : I know that its a bad idea to ask the Form in this method and some others because it means that it wont work with any main form. And to that Ill say that... your right !
|
||||||
|
DriverData result = new DriverData();
|
||||||
|
if (LiveDriverDataLogs.Count > 0)
|
||||||
|
{
|
||||||
|
//Searches the most recent live data from the given driverName
|
||||||
|
foreach (DriverData data in LiveDriverDataLogs[LiveDriverDataLogs.Count - 1])
|
||||||
|
{
|
||||||
|
if (data.Name == driverName)
|
||||||
|
result = data;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (result.Name != "")
|
||||||
|
{
|
||||||
|
//Recovers and displays the last five laps from the driver
|
||||||
|
lastFiveLapsPanel.Controls.Clear();
|
||||||
|
Size labelDimensions = new Size(lastFiveLapsPanel.Width, lastFiveLapsPanel.Height / 5);
|
||||||
|
|
||||||
|
List<(int LapTime, int Lap)> lapsInfos = Storage.GetDriverLaptimes(driverName, 5);
|
||||||
|
|
||||||
|
int id = 0;
|
||||||
|
foreach ((int LapTime, int Lap) lapData in lapsInfos)
|
||||||
|
{
|
||||||
|
//Hardcodes the new button.
|
||||||
|
//Note : It could be smart to have like a default button for all the methods to use without needing to rewrite everything.
|
||||||
|
Button newButton = new Button();
|
||||||
|
lastFiveLapsPanel.Controls.Add(newButton);
|
||||||
|
newButton.Name = driverName + "_" + lapData.Lap;
|
||||||
|
newButton.Text = Reader.ConvertMsToTime(lapData.LapTime);
|
||||||
|
newButton.Size = labelDimensions;
|
||||||
|
newButton.FlatStyle = FlatStyle.Popup;
|
||||||
|
newButton.Click += form1.btnLapTime_Click;
|
||||||
|
newButton.Location = new Point(0, id * newButton.Height);
|
||||||
|
id++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
/// <summary>
|
||||||
|
/// Runs trough every drivers live data to recover the drivers that are close to each others
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="pnlBattles">The control that will host the displayed battles</param>
|
||||||
|
/// <param name="form1">The main form. It needs to have a method called 'btnDriver_Click' so it can reads the buttons clicks</param>
|
||||||
|
public void DisplayBattles(Panel pnlBattles,Main form1)
|
||||||
|
{
|
||||||
|
DriverData oldDriver = null;
|
||||||
|
List<(DriverData d1, DriverData d2, int gap)> battles = new List<(DriverData d1, DriverData d2, int gap)>();
|
||||||
|
//Search trough all the drivers and finds the one battling
|
||||||
|
foreach (DriverData driver in LiveDriverDataLogs[LiveDriverDataLogs.Count - 1])
|
||||||
|
{
|
||||||
|
if (oldDriver != null && driver.Position != -1 && oldDriver.Position != -1)
|
||||||
|
{
|
||||||
|
if (driver.GapToLeader < oldDriver.GapToLeader)
|
||||||
|
{
|
||||||
|
//There is a problem with the drivers gaps
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
int gap = driver.GapToLeader - oldDriver.GapToLeader;
|
||||||
|
//3000ms is 3s. If drivers are that close then they are definitely in battle. If they are farther then maybe not
|
||||||
|
if (gap <= 3000)
|
||||||
|
{
|
||||||
|
battles.Add((oldDriver, driver, gap));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
oldDriver = driver;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
oldDriver = driver;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//We will only display 4 battles max
|
||||||
|
int maxBattles = 4;
|
||||||
|
if (battles.Count > 0)
|
||||||
|
{
|
||||||
|
pnlBattles.Controls.Clear();
|
||||||
|
int maxUiHeight = Math.Max(pnlBattles.Height / maxBattles, pnlBattles.Height / battles.Count);
|
||||||
|
int id = 0;
|
||||||
|
foreach ((DriverData d1, DriverData d2, int gap) battle in battles)
|
||||||
|
{
|
||||||
|
if(id < maxBattles)
|
||||||
|
{
|
||||||
|
//*hardcoding* the different controls that needs to be added to the panel.
|
||||||
|
//Note : this stuff could totally be handled by the Form with method returning a list of the drivers. It was just easier for me at the time to code it this way but its not the prettiest
|
||||||
|
Button btnFirstDriver = new Button();
|
||||||
|
Button btnSecondDriver = new Button();
|
||||||
|
Label lblGap = new Label();
|
||||||
|
|
||||||
|
pnlBattles.Controls.Add(btnFirstDriver);
|
||||||
|
pnlBattles.Controls.Add(lblGap);
|
||||||
|
pnlBattles.Controls.Add(btnSecondDriver);
|
||||||
|
|
||||||
|
btnFirstDriver.Anchor = AnchorStyles.Left | AnchorStyles.Top;
|
||||||
|
btnSecondDriver.Anchor = AnchorStyles.Right | AnchorStyles.Top;
|
||||||
|
lblGap.Anchor = AnchorStyles.Right | AnchorStyles.Left | AnchorStyles.Top;
|
||||||
|
|
||||||
|
lblGap.TextAlign = ContentAlignment.MiddleCenter;
|
||||||
|
lblGap.Font = new Font(lblGap.Font.FontFamily, 15);
|
||||||
|
|
||||||
|
btnFirstDriver.Click += form1.btnDriver_Click;
|
||||||
|
btnSecondDriver.Click += form1.btnDriver_Click;
|
||||||
|
|
||||||
|
btnFirstDriver.FlatStyle = FlatStyle.Popup;
|
||||||
|
btnSecondDriver.FlatStyle = FlatStyle.Popup;
|
||||||
|
lblGap.FlatStyle = FlatStyle.Popup;
|
||||||
|
|
||||||
|
btnFirstDriver.Size = new Size(pnlBattles.Width / 3, maxUiHeight);
|
||||||
|
btnSecondDriver.Size = new Size(pnlBattles.Width / 3, maxUiHeight);
|
||||||
|
lblGap.Size = new Size(pnlBattles.Width / 3, maxUiHeight);
|
||||||
|
|
||||||
|
btnFirstDriver.Location = new Point(pnlBattles.Width / 3 * 0, id * maxUiHeight);
|
||||||
|
lblGap.Location = new Point(pnlBattles.Width / 3 * 1, id * maxUiHeight);
|
||||||
|
btnSecondDriver.Location = new Point(pnlBattles.Width / 3 * 2, id * maxUiHeight);
|
||||||
|
|
||||||
|
btnFirstDriver.Text = battle.d1.Name;
|
||||||
|
lblGap.Text = "+ " + Reader.ConvertMsToTime(battle.gap);
|
||||||
|
if (battle.gap <= 2000)
|
||||||
|
lblGap.ForeColor = Color.Yellow;
|
||||||
|
if (battle.gap <= 1000)
|
||||||
|
lblGap.ForeColor = Color.Green;
|
||||||
|
btnSecondDriver.Text = battle.d2.Name;
|
||||||
|
|
||||||
|
btnFirstDriver.Name = battle.d1.Name + "_" + id;
|
||||||
|
lblGap.Name = "lbl_Gap_" + id;
|
||||||
|
btnSecondDriver.Name = battle.d2.Name + "_" + id;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
id++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/// <summary>
|
||||||
|
/// Searches the fastest and slowests drivers and displays them in the given panels
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="pnlFastest">Panel that will contain the constructed controls</param>
|
||||||
|
/// <param name="pnlSlowest">Panel that will contain the constructed controls</param>
|
||||||
|
/// <param name="form1">The main form that needs to implement the method btnDriver_Click to allow it to recover custom buttons click</param>
|
||||||
|
public void DisplayTimesDeltas(Panel pnlFastest,Panel pnlSlowest, Main form1)
|
||||||
|
{
|
||||||
|
List<(int avg, string driverName)> averages = new List<(int avg, string driverName)>();
|
||||||
|
foreach (DriverData driver in LiveDriverDataLogs[LiveDriverDataLogs.Count - 1])
|
||||||
|
{
|
||||||
|
//We want to recover the last 5 lap times
|
||||||
|
List<(int lapTime,int lap)> laps = Storage.GetDriverLaptimes(driver.Name,5);
|
||||||
|
if(laps.Count > 0)
|
||||||
|
{
|
||||||
|
int avg = 0;
|
||||||
|
foreach ((int lapTime, int lap) lap in laps)
|
||||||
|
{
|
||||||
|
avg += lap.lapTime;
|
||||||
|
}
|
||||||
|
avg = avg / laps.Count;
|
||||||
|
averages.Add((avg, driver.Name));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
int numberOfDriversToShow = 5;
|
||||||
|
if (averages.Count > 0 && averages.Count > numberOfDriversToShow)
|
||||||
|
{
|
||||||
|
averages = averages.OrderBy(item => item.avg).ToList();
|
||||||
|
pnlFastest.Controls.Clear();
|
||||||
|
pnlSlowest.Controls.Clear();
|
||||||
|
int maxUiSize = pnlFastest.Height / numberOfDriversToShow;
|
||||||
|
|
||||||
|
//Displays the fastest drivers
|
||||||
|
for (int i = 0; i < numberOfDriversToShow; i++)
|
||||||
|
{
|
||||||
|
Button newButton = new Button();
|
||||||
|
(int avg, string driver) data = averages[i];
|
||||||
|
pnlFastest.Controls.Add(newButton);
|
||||||
|
newButton.Size = new Size(pnlFastest.Width, maxUiSize);
|
||||||
|
newButton.Location = new Point(0, i * maxUiSize);
|
||||||
|
newButton.Text = data.driver;
|
||||||
|
newButton.FlatStyle = FlatStyle.Popup;
|
||||||
|
newButton.Name = data.driver + "_fastest_" + i;
|
||||||
|
newButton.Click += form1.btnDriver_Click;
|
||||||
|
//We take the average time lost per lap
|
||||||
|
if (i != 0)
|
||||||
|
newButton.Text += " + " + Reader.ConvertMsToTime(Convert.ToInt32(((float)data.avg - (float)averages[0].avg) / 5.0f));
|
||||||
|
}
|
||||||
|
//Displays the slowests drivers
|
||||||
|
int badId = 0;
|
||||||
|
for (int i = averages.Count -1; i >= averages.Count - numberOfDriversToShow; i--)
|
||||||
|
{
|
||||||
|
Button newButton = new Button();
|
||||||
|
(int avg, string driver) data = averages[i];
|
||||||
|
pnlSlowest.Controls.Add(newButton);
|
||||||
|
newButton.Size = new Size(pnlFastest.Width, maxUiSize);
|
||||||
|
newButton.Location = new Point(0, badId * maxUiSize);
|
||||||
|
newButton.Text = data.driver;
|
||||||
|
newButton.FlatStyle = FlatStyle.Popup;
|
||||||
|
newButton.Name = data.driver + "_slowest_" + i;
|
||||||
|
newButton.Click += form1.btnDriver_Click;
|
||||||
|
//We take the average time lost per lap
|
||||||
|
newButton.Text += " + " + Reader.ConvertMsToTime(Convert.ToInt32(((float)data.avg - (float)averages[0].avg) / 5.0f));
|
||||||
|
badId++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/// <summary>
|
||||||
|
/// Will add to the list of overtakes the different changes of position
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="lsbResult">The listbox containing all the infos</param>
|
||||||
|
public void DisplayOvertakes(ListBox lsbResult)
|
||||||
|
{
|
||||||
|
//Note : This method SHOULD REALLY not do this but just return a string or a list of string with the new overtakes so the form can handle it as it wishes
|
||||||
|
if (LiveDriverDataLogs.Count > 1)
|
||||||
|
{
|
||||||
|
List<DriverData> oldList = LiveDriverDataLogs[LiveDriverDataLogs.Count - 2];
|
||||||
|
List<DriverData> newList = LiveDriverDataLogs[LiveDriverDataLogs.Count - 1];
|
||||||
|
for (int i = 0; i < LiveDriverDataLogs[LiveDriverDataLogs.Count - 1].Count;i++)
|
||||||
|
{
|
||||||
|
if (oldList[i].Name != newList[i].Name) {
|
||||||
|
//There has been a change in the standings
|
||||||
|
for(int y = 0; y < oldList.Count;y++)
|
||||||
|
{
|
||||||
|
if (newList[y].Name == oldList[i].Name)
|
||||||
|
{
|
||||||
|
//We found its new location
|
||||||
|
if (y > i)
|
||||||
|
{
|
||||||
|
//The driver overtook someone
|
||||||
|
lsbResult.Items.Add(newList[y].Name + " climbed to " + y);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
//The driver got overtook by someone
|
||||||
|
lsbResult.Items.Add(newList[y].Name + " fell to " + y);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/// <summary>
|
||||||
|
/// Displays a messageBox containing the infos about a lap time
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="driverName">The name of the driver that has done the lapTime</param>
|
||||||
|
/// <param name="Lap">The number of the lap on wich the lapTime has been set (CAUTION ITS NOT THE RACING LAP ITS FROM THE DB)</param>
|
||||||
|
/// <param name="LapTime">The time (in ms) of the lap</param>
|
||||||
|
public void DisplayLapTimeInfos(string driverName, int Lap, string LapTime)
|
||||||
|
{
|
||||||
|
List<int> sectors = Storage.GetSectorsFromLapTime(driverName, Lap);
|
||||||
|
string message = "Lap time infos" + Environment.NewLine;
|
||||||
|
message += LapTime + Environment.NewLine;
|
||||||
|
if (sectors.Count > 0)
|
||||||
|
message += "Sector 1 : " + Reader.ConvertMsToTime(sectors[0]) + Environment.NewLine;
|
||||||
|
if (sectors.Count > 1)
|
||||||
|
message += "Sector 2 : " + Reader.ConvertMsToTime(sectors[1]) + Environment.NewLine;
|
||||||
|
if (sectors.Count > 2)
|
||||||
|
message += "Sector 3 : " + Reader.ConvertMsToTime(sectors[2]) + Environment.NewLine;
|
||||||
|
MessageBox.Show(message);
|
||||||
|
}
|
||||||
|
/// <summary>
|
||||||
|
/// Displays the live ranking with the names of the drivers and their gap to the leader in the right order
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="pnl">The control that will host all the new controls</param>
|
||||||
|
/// <param name="form1">The main form</param>
|
||||||
|
public void DisplayLiveRanking(Panel pnl, Main form1)
|
||||||
|
{
|
||||||
|
if (LiveDriverDataLogs.Count > 0)
|
||||||
|
{
|
||||||
|
pnl.Controls.Clear();
|
||||||
|
//Gets the last item that should be the most recent data
|
||||||
|
List<DriverData> liveData = LiveDriverDataLogs[LiveDriverDataLogs.Count - 1];
|
||||||
|
|
||||||
|
Button[] buttons = new Button[liveData.Count];
|
||||||
|
|
||||||
|
Size buttonDimensions = new Size(pnl.Width, pnl.Height / liveData.Count);
|
||||||
|
|
||||||
|
for (int driverCount = 0; driverCount < liveData.Count; driverCount++)
|
||||||
|
{
|
||||||
|
Button newButton = new Button();
|
||||||
|
|
||||||
|
newButton.Size = buttonDimensions;
|
||||||
|
newButton.Location = new Point(0, driverCount * buttonDimensions.Height);
|
||||||
|
newButton.FlatStyle = FlatStyle.Popup;
|
||||||
|
|
||||||
|
DriverData driver = liveData[driverCount];
|
||||||
|
|
||||||
|
if (driver.Position == -1)
|
||||||
|
{
|
||||||
|
//Its a DNF
|
||||||
|
newButton.Enabled = false;
|
||||||
|
}
|
||||||
|
if (driver.Position > 1)
|
||||||
|
{
|
||||||
|
newButton.Text = driver.Name + " +" + Reader.ConvertMsToTime(driver.GapToLeader);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
newButton.Text = driver.Name;
|
||||||
|
}
|
||||||
|
|
||||||
|
newButton.Name = liveData[driverCount].Name;
|
||||||
|
newButton.TextAlign = ContentAlignment.MiddleLeft;
|
||||||
|
|
||||||
|
newButton.FlatStyle = FlatStyle.Popup;
|
||||||
|
|
||||||
|
newButton.Click += form1.btnDriver_Click;
|
||||||
|
|
||||||
|
buttons[driverCount] = newButton;
|
||||||
|
}
|
||||||
|
//Note : It could be better to have this directly in the same loop
|
||||||
|
foreach (Button button in buttons)
|
||||||
|
{
|
||||||
|
pnl.Controls.Add(button);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,10 +1,16 @@
|
|||||||
using System;
|
/// Author : Maxime Rohmer
|
||||||
|
/// Date : 30/05/2023
|
||||||
|
/// File : DriverData.cs
|
||||||
|
/// Brief : File containing classes that behave just like structures to store data about drivers
|
||||||
|
/// Version : Alpha 1.0
|
||||||
|
|
||||||
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
namespace Test_Merge
|
namespace TrackTrends
|
||||||
{
|
{
|
||||||
public class DriverData
|
public class DriverData
|
||||||
{
|
{
|
||||||
@@ -30,6 +36,9 @@ namespace Test_Merge
|
|||||||
Sector3 = sector3;
|
Sector3 = sector3;
|
||||||
CurrentTyre = tyre;
|
CurrentTyre = tyre;
|
||||||
}
|
}
|
||||||
|
/// <summary>
|
||||||
|
/// Creates a default driver data with empty values
|
||||||
|
/// </summary>
|
||||||
public DriverData()
|
public DriverData()
|
||||||
{
|
{
|
||||||
DRS = false;
|
DRS = false;
|
||||||
@@ -53,21 +62,21 @@ namespace Test_Merge
|
|||||||
//Position
|
//Position
|
||||||
result += "Position : " + Position + Environment.NewLine;
|
result += "Position : " + Position + Environment.NewLine;
|
||||||
//Gap
|
//Gap
|
||||||
result += "Gap to leader : " + OCRDecoder.ConvertMsToTime(GapToLeader) + Environment.NewLine;
|
result += "GapToLeader : " + Reader.ConvertMsToTime(GapToLeader) + Environment.NewLine;
|
||||||
//LapTime
|
//LapTime
|
||||||
result += "Lap time : " + OCRDecoder.ConvertMsToTime(LapTime) + Environment.NewLine;
|
result += "LapTime : " + Reader.ConvertMsToTime(LapTime) + Environment.NewLine;
|
||||||
//DRS
|
//DRS
|
||||||
result += "DRS : " + DRS + Environment.NewLine;
|
result += "DRS : " + DRS + Environment.NewLine;
|
||||||
//Tyres
|
//Tyres
|
||||||
result += "Uses " + CurrentTyre.Coumpound + " tyre " + CurrentTyre.NumberOfLaps + " laps old" + Environment.NewLine;
|
result += "Uses " + CurrentTyre.Coumpound + " tyre " + CurrentTyre.NumberOfLaps + " laps old" + Environment.NewLine;
|
||||||
//Name
|
//Name
|
||||||
result += "Driver name : " + Name + Environment.NewLine;
|
result += "DriverName : " + Name + Environment.NewLine;
|
||||||
//Sector 1
|
//Sector 1
|
||||||
result += "Sector 1 : " + OCRDecoder.ConvertMsToTime(Sector1) + Environment.NewLine;
|
result += "Sector1 : " + Reader.ConvertMsToTime(Sector1) + Environment.NewLine;
|
||||||
//Sector 1
|
//Sector 1
|
||||||
result += "Sector 2 : " + OCRDecoder.ConvertMsToTime(Sector2) + Environment.NewLine;
|
result += "Sector2 : " + Reader.ConvertMsToTime(Sector2) + Environment.NewLine;
|
||||||
//Sector 1
|
//Sector 1
|
||||||
result += "Sector 3 : " + OCRDecoder.ConvertMsToTime(Sector3) + Environment.NewLine;
|
result += "Sector3 : " + Reader.ConvertMsToTime(Sector3) + Environment.NewLine;
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
@@ -1,4 +1,10 @@
|
|||||||
using System;
|
/// Author : Maxime Rohmer
|
||||||
|
/// Date : 30/05/2023
|
||||||
|
/// File : DriverDrsWindow.cs
|
||||||
|
/// Brief : Window containing DRS related method and infos
|
||||||
|
/// Version : Alpha 1.0
|
||||||
|
|
||||||
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Drawing;
|
using System.Drawing;
|
||||||
using System.Drawing.Imaging;
|
using System.Drawing.Imaging;
|
||||||
@@ -7,17 +13,21 @@ using System.Text;
|
|||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Tesseract;
|
using Tesseract;
|
||||||
|
|
||||||
namespace Test_Merge
|
namespace TrackTrends
|
||||||
{
|
{
|
||||||
internal class DriverDrsWindow:Window
|
internal class DriverDrsWindow:Window
|
||||||
{
|
{
|
||||||
private static int EmptyDrsGreenValue = -1;
|
private static int EmptyDrsGreenValue = -1;
|
||||||
private static Random rnd = new Random();
|
private static Random rnd = new Random();
|
||||||
public DriverDrsWindow(Bitmap image, Rectangle bounds) : base(image, bounds)
|
public DriverDrsWindow(Bitmap image, Rectangle bounds,bool generateEngine = true) : base(image, bounds,generateEngine)
|
||||||
{
|
{
|
||||||
Name = "DRS";
|
Name = "DRS";
|
||||||
}
|
}
|
||||||
public override async Task<object> DecodePng()
|
/// <summary>
|
||||||
|
/// Method that will decode the content of the window
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>returns a boolean (true = DRS OPEN, false = DRS CLOSED)</returns>
|
||||||
|
public override object DecodePng()
|
||||||
{
|
{
|
||||||
bool result = false;
|
bool result = false;
|
||||||
int greenValue = GetGreenPixels();
|
int greenValue = GetGreenPixels();
|
||||||
@@ -29,6 +39,10 @@ namespace Test_Merge
|
|||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
/// <summary>
|
||||||
|
/// Method that will get the green pixel proportion in the image, this can be used to determin if the DRS has been actuated
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>The number of clearely green pixels</returns>
|
||||||
private unsafe int GetGreenPixels()
|
private unsafe int GetGreenPixels()
|
||||||
{
|
{
|
||||||
int tot = 0;
|
int tot = 0;
|
||||||
@@ -63,6 +77,10 @@ namespace Test_Merge
|
|||||||
|
|
||||||
return tot;
|
return tot;
|
||||||
}
|
}
|
||||||
|
/// <summary>
|
||||||
|
/// This method is used to lock on where exactly the DRS window is
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>Returns a rectangle containing the DRS</returns>
|
||||||
public Rectangle GetBox()
|
public Rectangle GetBox()
|
||||||
{
|
{
|
||||||
var tessImage = Pix.LoadFromMemory(ImageToByte(WindowImage));
|
var tessImage = Pix.LoadFromMemory(ImageToByte(WindowImage));
|
||||||
@@ -0,0 +1,32 @@
|
|||||||
|
/// Author : Maxime Rohmer
|
||||||
|
/// Date : 30/05/2023
|
||||||
|
/// File : DriverGapToLeaderWindow.cs
|
||||||
|
/// Brief : Window containing infos about the gap to the leader of a driver
|
||||||
|
/// Version : Alpha 1.0
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Drawing;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace TrackTrends
|
||||||
|
{
|
||||||
|
internal class DriverGapToLeaderWindow:Window
|
||||||
|
{
|
||||||
|
public DriverGapToLeaderWindow(Bitmap image, Rectangle bounds, bool generateEngine = true) : base(image, bounds,generateEngine)
|
||||||
|
{
|
||||||
|
Name = "GapToLeader";
|
||||||
|
}
|
||||||
|
/// <summary>
|
||||||
|
/// Decodes the gap to leader using Tesseract OCR
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>Returns the gap to the leader in miliseconds (int)</returns>
|
||||||
|
public override object DecodePng()
|
||||||
|
{
|
||||||
|
int result = GetTimeFromPng(WindowImage, OcrImage.WindowType.Gap, Engine);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,25 +1,31 @@
|
|||||||
using System;
|
/// Author : Maxime Rohmer
|
||||||
|
/// Date : 30/05/2023
|
||||||
|
/// File : DriverLapTimeWindow
|
||||||
|
/// Brief : Window containing infos about the lap time of a driver
|
||||||
|
/// Version : Alpha 1.0
|
||||||
|
|
||||||
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using System.Drawing;
|
using System.Drawing;
|
||||||
|
|
||||||
namespace Test_Merge
|
namespace TrackTrends
|
||||||
{
|
{
|
||||||
internal class DriverLapTimeWindow:Window
|
internal class DriverLapTimeWindow:Window
|
||||||
{
|
{
|
||||||
public DriverLapTimeWindow(Bitmap image, Rectangle bounds) : base(image, bounds)
|
public DriverLapTimeWindow(Bitmap image, Rectangle bounds, bool generateEngine = true) : base(image, bounds,generateEngine)
|
||||||
{
|
{
|
||||||
Name = "Lap time";
|
Name = "LapTime";
|
||||||
}
|
}
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Decodes the lap time contained in the image using OCR Tesseract
|
/// Decodes the lap time contained in the image using OCR Tesseract
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <returns>The laptime in int (ms)</returns>
|
/// <returns>The laptime in int (ms)</returns>
|
||||||
public override async Task<object> DecodePng()
|
public override object DecodePng()
|
||||||
{
|
{
|
||||||
int result = await GetTimeFromPng(WindowImage, OcrImage.WindowType.LapTime, Engine);
|
int result = GetTimeFromPng(WindowImage, OcrImage.WindowType.LapTime, Engine);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,28 +1,33 @@
|
|||||||
using System;
|
/// Author : Maxime Rohmer
|
||||||
|
/// Date : 30/05/2023
|
||||||
|
/// File : DriverNameWindow
|
||||||
|
/// Brief : Window containing infos about the name of the driver
|
||||||
|
/// Version : Alpha 1.0
|
||||||
|
|
||||||
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using System.Drawing;
|
using System.Drawing;
|
||||||
|
|
||||||
namespace Test_Merge
|
namespace TrackTrends
|
||||||
{
|
{
|
||||||
public class DriverNameWindow : Window
|
public class DriverNameWindow : Window
|
||||||
{
|
{
|
||||||
public static Random rnd = new Random();
|
public DriverNameWindow(Bitmap image, Rectangle bounds, bool generateEngine = true) : base(image, bounds,generateEngine)
|
||||||
public DriverNameWindow(Bitmap image, Rectangle bounds) : base(image, bounds)
|
|
||||||
{
|
{
|
||||||
Name = "Name";
|
Name = "Name";
|
||||||
}
|
}
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Decodes using OCR wich driver name is in the image
|
/// Decodes using OCR wich driver name is in the image
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="DriverList"></param>
|
/// <param name="DriverList">A list of all the names that can be on the image</param>
|
||||||
/// <returns>The driver name in string</returns>
|
/// <returns>a string representing the found driver name. It will be one of the ones given in the list</returns>
|
||||||
public override async Task<object> DecodePng(List<string> DriverList)
|
public override object DecodePng(List<string> DriverList)
|
||||||
{
|
{
|
||||||
string result = "";
|
string result = "";
|
||||||
result = await GetStringFromPng(WindowImage, Engine);
|
result = GetStringFromPng(WindowImage, Engine);
|
||||||
|
|
||||||
if (!IsADriver(DriverList, result))
|
if (!IsADriver(DriverList, result))
|
||||||
{
|
{
|
||||||
@@ -34,8 +39,8 @@ namespace Test_Merge
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Verifies that the name found in the OCR is a valid name
|
/// Verifies that the name found in the OCR is a valid name
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="driverList"></param>
|
/// <param name="driverList">The list of all the drivers name that can be found in the image</param>
|
||||||
/// <param name="potentialDriver"></param>
|
/// <param name="potentialDriver">The driver you want to be sure if it exists or not</param>
|
||||||
/// <returns>If ye or no the driver exists</returns>
|
/// <returns>If ye or no the driver exists</returns>
|
||||||
private static bool IsADriver(List<string> driverList, string potentialDriver)
|
private static bool IsADriver(List<string> driverList, string potentialDriver)
|
||||||
{
|
{
|
||||||
@@ -1,25 +1,31 @@
|
|||||||
using System;
|
/// Author : Maxime Rohmer
|
||||||
|
/// Date : 30/05/2023
|
||||||
|
/// File : DriverPositionWindow.cs
|
||||||
|
/// Brief : Window containing infos about the position of a driver.
|
||||||
|
/// Version : Alpha 1.0
|
||||||
|
|
||||||
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using System.Drawing;
|
using System.Drawing;
|
||||||
|
|
||||||
namespace Test_Merge
|
namespace TrackTrends
|
||||||
{
|
{
|
||||||
public class DriverPositionWindow:Window
|
public class DriverPositionWindow:Window
|
||||||
{
|
{
|
||||||
public DriverPositionWindow(Bitmap image, Rectangle bounds) : base(image, bounds)
|
public DriverPositionWindow(Bitmap image, Rectangle bounds, bool generateEngine = true) : base(image, bounds,generateEngine)
|
||||||
{
|
{
|
||||||
Name = "Position";
|
Name = "Position";
|
||||||
}
|
}
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Decodes the position number using Tesseract OCR
|
/// Decodes the position number using Tesseract OCR
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <returns>The position of the pilot in int</returns>
|
/// <returns>An int representing the position of the driver (should be between 1 and 20 included)</returns>
|
||||||
public override async Task<object> DecodePng()
|
public override object DecodePng()
|
||||||
{
|
{
|
||||||
string ocrResult = await GetStringFromPng(WindowImage, Engine, "0123456789");
|
string ocrResult = GetStringFromPng(WindowImage, Engine, "0123456789");
|
||||||
|
|
||||||
int position;
|
int position;
|
||||||
try
|
try
|
||||||
@@ -0,0 +1,32 @@
|
|||||||
|
/// Author : Maxime Rohmer
|
||||||
|
/// Date : 30/05/2023
|
||||||
|
/// File : DriverSectorWindow.cs
|
||||||
|
/// Brief : Window containing infos about a driver sector time. Can be the first second or third, does not matter.
|
||||||
|
/// Version : Alpha 1.0
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using System.Drawing;
|
||||||
|
|
||||||
|
namespace TrackTrends
|
||||||
|
{
|
||||||
|
internal class DriverSectorWindow:Window
|
||||||
|
{
|
||||||
|
public DriverSectorWindow(Bitmap image, Rectangle bounds, int sectorId, bool generateEngine = true) : base(image, bounds,generateEngine)
|
||||||
|
{
|
||||||
|
Name = "Sector"+sectorId;
|
||||||
|
}
|
||||||
|
/// <summary>
|
||||||
|
/// Decodes the sector
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>the sector time in int (ms)</returns>
|
||||||
|
public override object DecodePng()
|
||||||
|
{
|
||||||
|
int ocrResult = GetTimeFromPng(WindowImage, OcrImage.WindowType.Sector, Engine);
|
||||||
|
return ocrResult;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,17 +1,20 @@
|
|||||||
using System;
|
/// Author : Maxime Rohmer
|
||||||
|
/// Date : 30/05/2023
|
||||||
|
/// File : DriverTyresWindow.cs
|
||||||
|
/// Brief : Window containing infos about a driver's tyre
|
||||||
|
/// Version : Alpha 1.0
|
||||||
|
|
||||||
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using System.Drawing;
|
using System.Drawing;
|
||||||
|
|
||||||
namespace Test_Merge
|
namespace TrackTrends
|
||||||
{
|
{
|
||||||
public class DriverTyresWindow:Window
|
public class DriverTyresWindow:Window
|
||||||
{
|
{
|
||||||
private static Random rnd = new Random();
|
|
||||||
int seed = rnd.Next(0, 10000);
|
|
||||||
|
|
||||||
//Those are the colors I found but you can change them if they change in the future like in 2019
|
//Those are the colors I found but you can change them if they change in the future like in 2019
|
||||||
public static Color SOFT_TYRE_COLOR = Color.FromArgb(0xff, 0x00, 0x00);
|
public static Color SOFT_TYRE_COLOR = Color.FromArgb(0xff, 0x00, 0x00);
|
||||||
public static Color MEDIUM_TYRE_COLOR = Color.FromArgb(0xf5, 0xbf, 0x00);
|
public static Color MEDIUM_TYRE_COLOR = Color.FromArgb(0xf5, 0xbf, 0x00);
|
||||||
@@ -20,7 +23,7 @@ namespace Test_Merge
|
|||||||
public static Color WET_TYRE_COLOR = Color.FromArgb(0x27, 0x60, 0xa6);
|
public static Color WET_TYRE_COLOR = Color.FromArgb(0x27, 0x60, 0xa6);
|
||||||
public static Color EMPTY_COLOR = Color.FromArgb(0x20, 0x20, 0x20);
|
public static Color EMPTY_COLOR = Color.FromArgb(0x20, 0x20, 0x20);
|
||||||
|
|
||||||
public DriverTyresWindow(Bitmap image, Rectangle bounds) : base(image, bounds)
|
public DriverTyresWindow(Bitmap image, Rectangle bounds, bool generateEngine = true) : base(image, bounds,generateEngine)
|
||||||
{
|
{
|
||||||
Name = "Tyres";
|
Name = "Tyres";
|
||||||
}
|
}
|
||||||
@@ -28,22 +31,22 @@ namespace Test_Merge
|
|||||||
/// This will decode the content of the image
|
/// This will decode the content of the image
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <returns>And object containing what was on the image</returns>
|
/// <returns>And object containing what was on the image</returns>
|
||||||
public override async Task<object> DecodePng()
|
public override object DecodePng()
|
||||||
{
|
{
|
||||||
return await GetTyreInfos();
|
return GetTyreInfos();
|
||||||
}
|
}
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Method that will decode whats on the image and return the tyre infos it could manage to recover
|
/// Method that will decode whats on the image and return the tyre infos it could manage to recover
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <returns>A tyre object containing tyre infos</returns>
|
/// <returns>A tyre object containing tyre infos</returns>
|
||||||
private async Task<Tyre> GetTyreInfos()
|
private Tyre GetTyreInfos()
|
||||||
{
|
{
|
||||||
Bitmap tyreZone = GetSmallBitmapFromBigOne(WindowImage, FindTyreZone());
|
Bitmap tyreZone = GetSmallBitmapFromBigOne(WindowImage, FindTyreZone());
|
||||||
Tyre.Type type = Tyre.Type.Undefined;
|
Tyre.Type type = Tyre.Type.Undefined;
|
||||||
type = GetTyreTypeFromColor(OcrImage.GetAvgColorFromBitmap(tyreZone));
|
type = GetTyreTypeFromColor(OcrImage.GetAvgColorFromBitmap(tyreZone));
|
||||||
int laps = -1;
|
int laps = -1;
|
||||||
|
|
||||||
string number = await GetStringFromPng(tyreZone, Engine, "0123456789", OcrImage.WindowType.Tyre);
|
string number = GetStringFromPng(tyreZone, Engine, "0123456789", OcrImage.WindowType.Tyre);
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
laps = Convert.ToInt32(number);
|
laps = Convert.ToInt32(number);
|
||||||
@@ -53,7 +56,11 @@ namespace Test_Merge
|
|||||||
//We could not convert the number so its a letter so its 0 laps old
|
//We could not convert the number so its a letter so its 0 laps old
|
||||||
laps = 0;
|
laps = 0;
|
||||||
}
|
}
|
||||||
//tyreZone.Save(Reader.DEBUG_DUMP_FOLDER + "Tyre" + type + "Laps" + laps + '#' + rnd.Next(0, 1000) + ".png");
|
|
||||||
|
//71 is the most laps an f1 race is ever going to have (mexico) so any more would be considered as bad (and remember you cant go trough a full race without making at least one pitstop)
|
||||||
|
if (laps > 75)
|
||||||
|
laps = 0;
|
||||||
|
|
||||||
return new Tyre(type, laps);
|
return new Tyre(type, laps);
|
||||||
}
|
}
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -67,7 +74,7 @@ namespace Test_Merge
|
|||||||
int height = bmp.Height / 2;
|
int height = bmp.Height / 2;
|
||||||
Color limitColor = Color.FromArgb(0x50, 0x50, 0x50);
|
Color limitColor = Color.FromArgb(0x50, 0x50, 0x50);
|
||||||
Color currentColor = Color.FromArgb(0, 0, 0);
|
Color currentColor = Color.FromArgb(0, 0, 0);
|
||||||
|
//25F
|
||||||
Size newWindowSize = new Size(bmp.Height - Convert.ToInt32((float)bmp.Height / 100f * 25f), bmp.Height - Convert.ToInt32((float)bmp.Height / 100f * 35f));
|
Size newWindowSize = new Size(bmp.Height - Convert.ToInt32((float)bmp.Height / 100f * 25f), bmp.Height - Convert.ToInt32((float)bmp.Height / 100f * 35f));
|
||||||
|
|
||||||
while (currentColor.R <= limitColor.R && currentColor.G <= limitColor.G && currentColor.B <= limitColor.B && currentPosition > 0)
|
while (currentColor.R <= limitColor.R && currentColor.G <= limitColor.G && currentColor.B <= limitColor.B && currentPosition > 0)
|
||||||
@@ -0,0 +1,329 @@
|
|||||||
|
/// Author : Maxime Rohmer
|
||||||
|
/// Date : 30/05/2023
|
||||||
|
/// File : F1TVEmulator.cs
|
||||||
|
/// Brief : Class that contains methods to emulate a browser and navigate the F1TV website
|
||||||
|
/// Version : Alpha 1.0
|
||||||
|
|
||||||
|
using OpenQA.Selenium;
|
||||||
|
using OpenQA.Selenium.Firefox;
|
||||||
|
using OpenQA.Selenium.Interactions;
|
||||||
|
using OpenQA.Selenium.Support.UI;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Diagnostics;
|
||||||
|
using System.Drawing;
|
||||||
|
using System.IO;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace TrackTrends
|
||||||
|
{
|
||||||
|
internal class F1TVEmulator
|
||||||
|
{
|
||||||
|
public const string COOKIE_HOST = ".formula1.com";
|
||||||
|
public const string PYTHON_COOKIE_RETRIEVAL_FILENAME = "recoverCookiesCSV.py";
|
||||||
|
public const string GECKODRIVER_FILENAME = @"geckodriver-v0.27.0-win64\geckodriver.exe";
|
||||||
|
//BE CAREFULL IF YOU CHANGE IT HERE YOU NEED TO CHANGE IT IN THE PYTHON SCRIPT TOO
|
||||||
|
public const string COOKIES_CSV_FILENAME = "cookies.csv";
|
||||||
|
|
||||||
|
private FirefoxDriver Driver;
|
||||||
|
|
||||||
|
private bool _ready;
|
||||||
|
private string _grandPrixUrl;
|
||||||
|
public string GrandPrixUrl { get => _grandPrixUrl; private set => _grandPrixUrl = value; }
|
||||||
|
public bool Ready { get => _ready; set => _ready = value; }
|
||||||
|
public F1TVEmulator(string grandPrixUrl)
|
||||||
|
{
|
||||||
|
GrandPrixUrl = grandPrixUrl;
|
||||||
|
Ready = false;
|
||||||
|
}
|
||||||
|
/// <summary>
|
||||||
|
/// Will start the python programm that runs the Cookie Recovering
|
||||||
|
/// </summary>
|
||||||
|
private void StartCookieRecovering()
|
||||||
|
{
|
||||||
|
string scriptPath = PYTHON_COOKIE_RETRIEVAL_FILENAME;
|
||||||
|
Process process = new Process();
|
||||||
|
process.StartInfo.FileName = "python.exe";
|
||||||
|
process.StartInfo.Arguments = scriptPath;
|
||||||
|
process.StartInfo.UseShellExecute = false;
|
||||||
|
process.StartInfo.RedirectStandardOutput = true;
|
||||||
|
process.Start();
|
||||||
|
string output = process.StandardOutput.ReadToEnd();
|
||||||
|
process.WaitForExit();
|
||||||
|
}
|
||||||
|
/// <summary>
|
||||||
|
/// Method that will recover the needed cookies in the DB
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="host"> The host of the wanted cookie ex: ./formula1.com</param>
|
||||||
|
/// <param name="name">The name of the wanted cookie ex: login</param>
|
||||||
|
/// <returns>returns the value of the cookie if it has been found</returns>
|
||||||
|
/// <exception cref="InvalidOperationException"></exception>
|
||||||
|
public string GetCookie(string host, string name)
|
||||||
|
{
|
||||||
|
StartCookieRecovering();
|
||||||
|
string value = "";
|
||||||
|
List<Cookie> cookies = new List<Cookie>();
|
||||||
|
if (File.Exists(COOKIES_CSV_FILENAME))
|
||||||
|
{
|
||||||
|
using (var reader = new StreamReader(COOKIES_CSV_FILENAME))
|
||||||
|
{
|
||||||
|
// Read the header row and validate column order
|
||||||
|
string header = reader.ReadLine();
|
||||||
|
string[] expectedColumns = { "host_key", "name", "value", "path", "expires_utc", "is_secure", "is_httponly" };
|
||||||
|
string[] actualColumns = header.Split(',');
|
||||||
|
for (int i = 0; i < expectedColumns.Length; i++)
|
||||||
|
{
|
||||||
|
if (expectedColumns[i] != actualColumns[i])
|
||||||
|
{
|
||||||
|
throw new InvalidOperationException($"Expected column '{expectedColumns[i]}' at index {i} but found '{actualColumns[i]}'");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Read each data row and parse values into a Cookie object
|
||||||
|
while (!reader.EndOfStream)
|
||||||
|
{
|
||||||
|
string line = reader.ReadLine();
|
||||||
|
string[] fields = line.Split(',');
|
||||||
|
|
||||||
|
string hostname = fields[0];
|
||||||
|
string cookieName = fields[1];
|
||||||
|
|
||||||
|
if (hostname == host && cookieName == name)
|
||||||
|
{
|
||||||
|
value = fields[2];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
/// <summary>
|
||||||
|
/// Starts the headless browser
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>Error code 1xx</returns>
|
||||||
|
public async Task<int> Start()
|
||||||
|
{
|
||||||
|
Ready = false;
|
||||||
|
|
||||||
|
string loginCookieName = "login";
|
||||||
|
string loginSessionCookieName = "login-session";
|
||||||
|
string loginCookieValue = GetCookie(COOKIE_HOST, loginCookieName);
|
||||||
|
string loginSessionValue = GetCookie(COOKIE_HOST, loginSessionCookieName);
|
||||||
|
|
||||||
|
//Cookie retreival has gone wrong (usually its because of python not being installed properly)
|
||||||
|
if (loginCookieValue == "" || loginSessionValue == "")
|
||||||
|
return 100;
|
||||||
|
|
||||||
|
var service = FirefoxDriverService.CreateDefaultService(GECKODRIVER_FILENAME);
|
||||||
|
service.Host = "127.0.0.1";
|
||||||
|
service.Port = 5555;
|
||||||
|
|
||||||
|
FirefoxProfile profile = new FirefoxProfile();
|
||||||
|
FirefoxOptions options = new FirefoxOptions();
|
||||||
|
//profile.SetPreference("full-screen-api.ignore-widgets", true);
|
||||||
|
//profile.SetPreference("media.hardware-video-decoding.enabled", true);
|
||||||
|
//profile.SetPreference("full-screen-api.enabled", true);
|
||||||
|
options.Profile = profile;
|
||||||
|
profile.SetPreference("layout.css.devPixelsPerPx", "1.0");
|
||||||
|
|
||||||
|
options.AcceptInsecureCertificates = true;
|
||||||
|
options.AddArgument("--headless");
|
||||||
|
//options.AddArgument("--start-maximized");
|
||||||
|
//options.AddArgument("--window-size=1920x1080");
|
||||||
|
//options.AddArgument("--width=" + windowWidth);
|
||||||
|
//options.AddArgument("--height=" + windowHeight);
|
||||||
|
//options.AddArgument("-window-size=1920x1080");
|
||||||
|
//options.AddArgument("--width=1920");
|
||||||
|
//options.AddArgument("--height=1080");
|
||||||
|
//profile
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
Driver = new FirefoxDriver(service, options);
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
Ready = false;
|
||||||
|
return 101;
|
||||||
|
}
|
||||||
|
|
||||||
|
Actions actions = new Actions(Driver);
|
||||||
|
var loginCookie = new Cookie(loginCookieName, loginCookieValue, COOKIE_HOST, "/", DateTime.Now.AddDays(5));
|
||||||
|
var loginSessionCookie = new Cookie(loginSessionCookieName, loginSessionValue, COOKIE_HOST, "/", DateTime.Now.AddDays(5));
|
||||||
|
|
||||||
|
Driver.Navigate().GoToUrl("https://f1tv.formula1.com/");
|
||||||
|
|
||||||
|
Driver.Manage().Cookies.AddCookie(loginCookie);
|
||||||
|
Driver.Manage().Cookies.AddCookie(loginSessionCookie);
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
Driver.Navigate().GoToUrl(GrandPrixUrl);
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
//The url is not a valid url
|
||||||
|
Driver.Dispose();
|
||||||
|
return 103;
|
||||||
|
}
|
||||||
|
|
||||||
|
//Waits for the page to fully load
|
||||||
|
Driver.Manage().Timeouts().PageLoad = TimeSpan.FromSeconds(30);
|
||||||
|
|
||||||
|
//Removes the cookie prompt
|
||||||
|
try
|
||||||
|
{
|
||||||
|
IWebElement conscentButton = Driver.FindElement(By.Id("truste-consent-button"));
|
||||||
|
conscentButton.Click();
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
//Could not locate the cookie button
|
||||||
|
Screenshot("ERROR104");
|
||||||
|
Driver.Dispose();
|
||||||
|
return 104;
|
||||||
|
}
|
||||||
|
|
||||||
|
//Again waits for the page to fully load (when you accept cookies it takes a little time for the page to load)
|
||||||
|
//Cannot use The timeout because the feed loading is not really loading so there is not event or anything
|
||||||
|
Thread.Sleep(5000);
|
||||||
|
|
||||||
|
//Switches to the Data channel
|
||||||
|
try
|
||||||
|
{
|
||||||
|
IWebElement dataChannelButton = Driver.FindElement(By.ClassName("data-button"));
|
||||||
|
dataChannelButton.Click();
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
//If the data button does not exists its because the user is not connected
|
||||||
|
Screenshot("ERROR102");
|
||||||
|
Driver.Dispose();
|
||||||
|
return 102;
|
||||||
|
}
|
||||||
|
|
||||||
|
//Open settings
|
||||||
|
// Press the space key, this should make the setting button visible
|
||||||
|
// It does not matter if the feed is paused because when changing channel it autoplays
|
||||||
|
actions.SendKeys(OpenQA.Selenium.Keys.Space).Perform();
|
||||||
|
//Clicks on the settings Icon
|
||||||
|
|
||||||
|
int settingsClickTries = 0;
|
||||||
|
bool settingsClickSuccess = false;
|
||||||
|
while (settingsClickTries < 100 && !settingsClickSuccess)
|
||||||
|
{
|
||||||
|
Thread.Sleep(100);
|
||||||
|
try
|
||||||
|
{
|
||||||
|
IWebElement settingsButton = Driver.FindElement(By.ClassName("bmpui-ui-settingstogglebutton"));
|
||||||
|
settingsButton.Click();
|
||||||
|
IWebElement selectElement = Driver.FindElement(By.ClassName("bmpui-ui-videoqualityselectbox"));
|
||||||
|
SelectElement select = new SelectElement(selectElement);
|
||||||
|
IWebElement selectOption = selectElement.FindElement(By.CssSelector("option[value^='1080_']"));
|
||||||
|
selectOption.Click();
|
||||||
|
settingsClickSuccess = true;
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
//Sometimes it can crash because it could not get the options to show up in time. When it happens just retry
|
||||||
|
settingsClickSuccess = false;
|
||||||
|
settingsClickTries++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!settingsClickSuccess)
|
||||||
|
{
|
||||||
|
Screenshot("ERROR105");
|
||||||
|
Driver.Dispose();
|
||||||
|
return 105;
|
||||||
|
}
|
||||||
|
|
||||||
|
Screenshot("BEFOREFULLSCREEN");
|
||||||
|
|
||||||
|
//Makes the feed fullscreen
|
||||||
|
int fullScreenClickTries = 0;
|
||||||
|
bool fullScreenClickSuccess = false;
|
||||||
|
Driver.Manage().Window.Maximize();
|
||||||
|
//WebDriverWait wait = new WebDriverWait(Driver, TimeSpan.FromSeconds(10));
|
||||||
|
while (fullScreenClickTries < 100 && !fullScreenClickSuccess)
|
||||||
|
{
|
||||||
|
Thread.Sleep(150);
|
||||||
|
try
|
||||||
|
{
|
||||||
|
IWebElement fullScreenButton = Driver.FindElement(By.ClassName("bmpui-ui-fullscreentogglebutton"));
|
||||||
|
fullScreenButton.Click();
|
||||||
|
fullScreenClickSuccess = true;
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
fullScreenClickSuccess = false;
|
||||||
|
fullScreenClickTries++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!fullScreenClickSuccess)
|
||||||
|
{
|
||||||
|
Screenshot("ERROR106");
|
||||||
|
Driver.Dispose();
|
||||||
|
return 106;
|
||||||
|
}
|
||||||
|
|
||||||
|
Screenshot("AFTERFULLSCREEN");
|
||||||
|
|
||||||
|
//STARTUP FINISHED READY TO SCREENSHOT
|
||||||
|
Ready = true;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
/// <summary>
|
||||||
|
/// Takes a screenshot of what the headless browser is displaying
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="name">Optional ! The name of the picture so it can be saved</param>
|
||||||
|
/// <returns>Returns the screenshot in the bitmap format</returns>
|
||||||
|
public Bitmap Screenshot(string name = "TEST")
|
||||||
|
{
|
||||||
|
Bitmap result = new Bitmap(4242, 6969);
|
||||||
|
try
|
||||||
|
{
|
||||||
|
//Screenshot scrsht = ((ITakesScreenshot)Driver).GetScreenshot();
|
||||||
|
//profileriver.SetPreferencC:\Users\Moi\source\repos\Test_Merge\README.mde("layout.css.devPixelsPerPx", "1.0");
|
||||||
|
|
||||||
|
//Screenshot scrsht = Driver.GetFullPageScreenshot();
|
||||||
|
Screenshot scrsht = Driver.GetScreenshot();
|
||||||
|
|
||||||
|
byte[] screenshotBytes = Convert.FromBase64String(scrsht.AsBase64EncodedString);
|
||||||
|
MemoryStream stream = new MemoryStream(screenshotBytes);
|
||||||
|
|
||||||
|
result = new Bitmap(stream);
|
||||||
|
//result.Save(name + ".png");
|
||||||
|
scrsht.SaveAsFile(name + ".png");
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
//Nothing for now
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
/// <summary>
|
||||||
|
/// Stops the Emulation. Note: if you plan to start it again please use ResetDriver() instead
|
||||||
|
/// </summary>
|
||||||
|
public void Stop()
|
||||||
|
{
|
||||||
|
Ready = false;
|
||||||
|
if (Driver != null)
|
||||||
|
Driver.Dispose();
|
||||||
|
}
|
||||||
|
/// <summary>
|
||||||
|
/// Resets the emulation
|
||||||
|
/// </summary>
|
||||||
|
public void ResetDriver()
|
||||||
|
{
|
||||||
|
Ready = false;
|
||||||
|
if (Driver != null)
|
||||||
|
Driver.Dispose();
|
||||||
|
Driver = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Generated
+620
@@ -0,0 +1,620 @@
|
|||||||
|
namespace TrackTrends
|
||||||
|
{
|
||||||
|
partial class Main
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Required designer variable.
|
||||||
|
/// </summary>
|
||||||
|
private System.ComponentModel.IContainer components = null;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Clean up any resources being used.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
|
||||||
|
protected override void Dispose(bool disposing)
|
||||||
|
{
|
||||||
|
if (disposing && (components != null))
|
||||||
|
{
|
||||||
|
components.Dispose();
|
||||||
|
}
|
||||||
|
base.Dispose(disposing);
|
||||||
|
}
|
||||||
|
|
||||||
|
#region Windows Form Designer generated code
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Required method for Designer support - do not modify
|
||||||
|
/// the contents of this method with the code editor.
|
||||||
|
/// </summary>
|
||||||
|
private void InitializeComponent()
|
||||||
|
{
|
||||||
|
this.components = new System.ComponentModel.Container();
|
||||||
|
this.btnSettings = new System.Windows.Forms.Button();
|
||||||
|
this.btnStartDecoding = new System.Windows.Forms.Button();
|
||||||
|
this.pbxResult = new System.Windows.Forms.PictureBox();
|
||||||
|
this.btnStopUpdating = new System.Windows.Forms.Button();
|
||||||
|
this.btnResetEmulator = new System.Windows.Forms.Button();
|
||||||
|
this.lsbPresets = new System.Windows.Forms.ListBox();
|
||||||
|
this.gpbxControls = new System.Windows.Forms.GroupBox();
|
||||||
|
this.label7 = new System.Windows.Forms.Label();
|
||||||
|
this.tbxGpUrl = new System.Windows.Forms.TextBox();
|
||||||
|
this.label1 = new System.Windows.Forms.Label();
|
||||||
|
this.gpbxRanking = new System.Windows.Forms.GroupBox();
|
||||||
|
this.pnlLiveRanking = new System.Windows.Forms.Panel();
|
||||||
|
this.gpbxOvertakes = new System.Windows.Forms.GroupBox();
|
||||||
|
this.lsbOvertakes = new System.Windows.Forms.ListBox();
|
||||||
|
this.gpbxDriverInfos = new System.Windows.Forms.GroupBox();
|
||||||
|
this.pnlCover = new System.Windows.Forms.Panel();
|
||||||
|
this.lbl = new System.Windows.Forms.Label();
|
||||||
|
this.lblCurrentDriverDRS = new System.Windows.Forms.Label();
|
||||||
|
this.lblCurrentDriverTyreType = new System.Windows.Forms.Label();
|
||||||
|
this.label11 = new System.Windows.Forms.Label();
|
||||||
|
this.lblCurrentDriverPosition = new System.Windows.Forms.Label();
|
||||||
|
this.lblCurrentDriverGapToLeader = new System.Windows.Forms.Label();
|
||||||
|
this.label5 = new System.Windows.Forms.Label();
|
||||||
|
this.label8 = new System.Windows.Forms.Label();
|
||||||
|
this.lblCurrentDriverTyreAge = new System.Windows.Forms.Label();
|
||||||
|
this.label6 = new System.Windows.Forms.Label();
|
||||||
|
this.pnlCurrentDriverLapsHistory = new System.Windows.Forms.Panel();
|
||||||
|
this.lblCurrentDriverLapTime = new System.Windows.Forms.Label();
|
||||||
|
this.label4 = new System.Windows.Forms.Label();
|
||||||
|
this.lblCurrentDriverName = new System.Windows.Forms.Label();
|
||||||
|
this.gpbxLapTimes = new System.Windows.Forms.GroupBox();
|
||||||
|
this.pnlSlowest = new System.Windows.Forms.Panel();
|
||||||
|
this.label3 = new System.Windows.Forms.Label();
|
||||||
|
this.label2 = new System.Windows.Forms.Label();
|
||||||
|
this.pnlFastest = new System.Windows.Forms.Panel();
|
||||||
|
this.gpbxBattles = new System.Windows.Forms.GroupBox();
|
||||||
|
this.pnlBattles = new System.Windows.Forms.Panel();
|
||||||
|
this.label9 = new System.Windows.Forms.Label();
|
||||||
|
this.tip1 = new System.Windows.Forms.ToolTip(this.components);
|
||||||
|
((System.ComponentModel.ISupportInitialize)(this.pbxResult)).BeginInit();
|
||||||
|
this.gpbxControls.SuspendLayout();
|
||||||
|
this.gpbxRanking.SuspendLayout();
|
||||||
|
this.gpbxOvertakes.SuspendLayout();
|
||||||
|
this.gpbxDriverInfos.SuspendLayout();
|
||||||
|
this.pnlCover.SuspendLayout();
|
||||||
|
this.gpbxLapTimes.SuspendLayout();
|
||||||
|
this.gpbxBattles.SuspendLayout();
|
||||||
|
this.SuspendLayout();
|
||||||
|
//
|
||||||
|
// btnSettings
|
||||||
|
//
|
||||||
|
this.btnSettings.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(51)))), ((int)(((byte)(51)))), ((int)(((byte)(51)))));
|
||||||
|
this.btnSettings.FlatStyle = System.Windows.Forms.FlatStyle.Popup;
|
||||||
|
this.btnSettings.Font = new System.Drawing.Font("Microsoft Sans Serif", 10F);
|
||||||
|
this.btnSettings.Location = new System.Drawing.Point(9, 25);
|
||||||
|
this.btnSettings.Margin = new System.Windows.Forms.Padding(3, 4, 3, 4);
|
||||||
|
this.btnSettings.Name = "btnSettings";
|
||||||
|
this.btnSettings.Size = new System.Drawing.Size(111, 43);
|
||||||
|
this.btnSettings.TabIndex = 0;
|
||||||
|
this.btnSettings.Text = "Config";
|
||||||
|
this.btnSettings.UseVisualStyleBackColor = false;
|
||||||
|
this.btnSettings.Click += new System.EventHandler(this.btnSettings_Click);
|
||||||
|
//
|
||||||
|
// btnStartDecoding
|
||||||
|
//
|
||||||
|
this.btnStartDecoding.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(51)))), ((int)(((byte)(51)))), ((int)(((byte)(51)))));
|
||||||
|
this.btnStartDecoding.Enabled = false;
|
||||||
|
this.btnStartDecoding.FlatStyle = System.Windows.Forms.FlatStyle.Popup;
|
||||||
|
this.btnStartDecoding.Font = new System.Drawing.Font("Microsoft Sans Serif", 10F);
|
||||||
|
this.btnStartDecoding.Location = new System.Drawing.Point(9, 76);
|
||||||
|
this.btnStartDecoding.Margin = new System.Windows.Forms.Padding(3, 4, 3, 4);
|
||||||
|
this.btnStartDecoding.Name = "btnStartDecoding";
|
||||||
|
this.btnStartDecoding.Size = new System.Drawing.Size(112, 43);
|
||||||
|
this.btnStartDecoding.TabIndex = 2;
|
||||||
|
this.btnStartDecoding.Text = "Start";
|
||||||
|
this.btnStartDecoding.UseVisualStyleBackColor = false;
|
||||||
|
this.btnStartDecoding.Click += new System.EventHandler(this.btnUpdate_Click);
|
||||||
|
//
|
||||||
|
// pbxResult
|
||||||
|
//
|
||||||
|
this.pbxResult.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(51)))), ((int)(((byte)(51)))), ((int)(((byte)(51)))));
|
||||||
|
this.pbxResult.Location = new System.Drawing.Point(6, 296);
|
||||||
|
this.pbxResult.Margin = new System.Windows.Forms.Padding(3, 4, 3, 4);
|
||||||
|
this.pbxResult.Name = "pbxResult";
|
||||||
|
this.pbxResult.Size = new System.Drawing.Size(246, 139);
|
||||||
|
this.pbxResult.SizeMode = System.Windows.Forms.PictureBoxSizeMode.StretchImage;
|
||||||
|
this.pbxResult.TabIndex = 3;
|
||||||
|
this.pbxResult.TabStop = false;
|
||||||
|
//
|
||||||
|
// btnStopUpdating
|
||||||
|
//
|
||||||
|
this.btnStopUpdating.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(51)))), ((int)(((byte)(51)))), ((int)(((byte)(51)))));
|
||||||
|
this.btnStopUpdating.Enabled = false;
|
||||||
|
this.btnStopUpdating.FlatStyle = System.Windows.Forms.FlatStyle.Popup;
|
||||||
|
this.btnStopUpdating.Font = new System.Drawing.Font("Microsoft Sans Serif", 10F);
|
||||||
|
this.btnStopUpdating.Location = new System.Drawing.Point(142, 76);
|
||||||
|
this.btnStopUpdating.Margin = new System.Windows.Forms.Padding(3, 4, 3, 4);
|
||||||
|
this.btnStopUpdating.Name = "btnStopUpdating";
|
||||||
|
this.btnStopUpdating.Size = new System.Drawing.Size(110, 43);
|
||||||
|
this.btnStopUpdating.TabIndex = 4;
|
||||||
|
this.btnStopUpdating.Text = "Stop";
|
||||||
|
this.btnStopUpdating.UseVisualStyleBackColor = false;
|
||||||
|
this.btnStopUpdating.Click += new System.EventHandler(this.btnStopUpdating_Click);
|
||||||
|
//
|
||||||
|
// btnResetEmulator
|
||||||
|
//
|
||||||
|
this.btnResetEmulator.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(51)))), ((int)(((byte)(51)))), ((int)(((byte)(51)))));
|
||||||
|
this.btnResetEmulator.FlatStyle = System.Windows.Forms.FlatStyle.Popup;
|
||||||
|
this.btnResetEmulator.Font = new System.Drawing.Font("Microsoft Sans Serif", 10F);
|
||||||
|
this.btnResetEmulator.Location = new System.Drawing.Point(142, 25);
|
||||||
|
this.btnResetEmulator.Margin = new System.Windows.Forms.Padding(3, 4, 3, 4);
|
||||||
|
this.btnResetEmulator.Name = "btnResetEmulator";
|
||||||
|
this.btnResetEmulator.Size = new System.Drawing.Size(110, 43);
|
||||||
|
this.btnResetEmulator.TabIndex = 5;
|
||||||
|
this.btnResetEmulator.Text = "Launch";
|
||||||
|
this.btnResetEmulator.UseVisualStyleBackColor = false;
|
||||||
|
this.btnResetEmulator.Click += new System.EventHandler(this.button1_Click);
|
||||||
|
//
|
||||||
|
// lsbPresets
|
||||||
|
//
|
||||||
|
this.lsbPresets.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(51)))), ((int)(((byte)(51)))), ((int)(((byte)(51)))));
|
||||||
|
this.lsbPresets.BorderStyle = System.Windows.Forms.BorderStyle.None;
|
||||||
|
this.lsbPresets.Font = new System.Drawing.Font("Microsoft YaHei UI", 10F);
|
||||||
|
this.lsbPresets.ForeColor = System.Drawing.Color.FromArgb(((int)(((byte)(252)))), ((int)(((byte)(252)))), ((int)(((byte)(252)))));
|
||||||
|
this.lsbPresets.FormattingEnabled = true;
|
||||||
|
this.lsbPresets.ItemHeight = 23;
|
||||||
|
this.lsbPresets.Location = new System.Drawing.Point(9, 176);
|
||||||
|
this.lsbPresets.Margin = new System.Windows.Forms.Padding(3, 4, 3, 4);
|
||||||
|
this.lsbPresets.Name = "lsbPresets";
|
||||||
|
this.lsbPresets.Size = new System.Drawing.Size(243, 92);
|
||||||
|
this.lsbPresets.TabIndex = 6;
|
||||||
|
this.lsbPresets.SelectedIndexChanged += new System.EventHandler(this.lsbPresets_SelectedIndexChanged);
|
||||||
|
//
|
||||||
|
// gpbxControls
|
||||||
|
//
|
||||||
|
this.gpbxControls.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(79)))), ((int)(((byte)(79)))), ((int)(((byte)(79)))));
|
||||||
|
this.gpbxControls.Controls.Add(this.label7);
|
||||||
|
this.gpbxControls.Controls.Add(this.tbxGpUrl);
|
||||||
|
this.gpbxControls.Controls.Add(this.btnResetEmulator);
|
||||||
|
this.gpbxControls.Controls.Add(this.label1);
|
||||||
|
this.gpbxControls.Controls.Add(this.btnStopUpdating);
|
||||||
|
this.gpbxControls.Controls.Add(this.pbxResult);
|
||||||
|
this.gpbxControls.Controls.Add(this.btnStartDecoding);
|
||||||
|
this.gpbxControls.Controls.Add(this.lsbPresets);
|
||||||
|
this.gpbxControls.Controls.Add(this.btnSettings);
|
||||||
|
this.gpbxControls.ForeColor = System.Drawing.Color.FromArgb(((int)(((byte)(252)))), ((int)(((byte)(252)))), ((int)(((byte)(252)))));
|
||||||
|
this.gpbxControls.Location = new System.Drawing.Point(12, 56);
|
||||||
|
this.gpbxControls.Margin = new System.Windows.Forms.Padding(3, 4, 3, 4);
|
||||||
|
this.gpbxControls.Name = "gpbxControls";
|
||||||
|
this.gpbxControls.Padding = new System.Windows.Forms.Padding(3, 4, 3, 4);
|
||||||
|
this.gpbxControls.Size = new System.Drawing.Size(263, 450);
|
||||||
|
this.gpbxControls.TabIndex = 7;
|
||||||
|
this.gpbxControls.TabStop = false;
|
||||||
|
this.gpbxControls.Text = "Controls";
|
||||||
|
this.gpbxControls.Paint += new System.Windows.Forms.PaintEventHandler(this.removeBorders);
|
||||||
|
//
|
||||||
|
// label7
|
||||||
|
//
|
||||||
|
this.label7.AutoSize = true;
|
||||||
|
this.label7.Location = new System.Drawing.Point(6, 273);
|
||||||
|
this.label7.Name = "label7";
|
||||||
|
this.label7.Size = new System.Drawing.Size(56, 19);
|
||||||
|
this.label7.TabIndex = 9;
|
||||||
|
this.label7.Text = "Preview";
|
||||||
|
//
|
||||||
|
// tbxGpUrl
|
||||||
|
//
|
||||||
|
this.tbxGpUrl.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(51)))), ((int)(((byte)(51)))), ((int)(((byte)(51)))));
|
||||||
|
this.tbxGpUrl.BorderStyle = System.Windows.Forms.BorderStyle.None;
|
||||||
|
this.tbxGpUrl.Font = new System.Drawing.Font("Microsoft YaHei UI", 10.2F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
|
||||||
|
this.tbxGpUrl.ForeColor = System.Drawing.Color.FromArgb(((int)(((byte)(252)))), ((int)(((byte)(252)))), ((int)(((byte)(252)))));
|
||||||
|
this.tbxGpUrl.Location = new System.Drawing.Point(10, 146);
|
||||||
|
this.tbxGpUrl.Margin = new System.Windows.Forms.Padding(3, 4, 3, 4);
|
||||||
|
this.tbxGpUrl.Name = "tbxGpUrl";
|
||||||
|
this.tbxGpUrl.Size = new System.Drawing.Size(242, 22);
|
||||||
|
this.tbxGpUrl.TabIndex = 8;
|
||||||
|
this.tbxGpUrl.TextChanged += new System.EventHandler(this.textBox1_TextChanged);
|
||||||
|
//
|
||||||
|
// label1
|
||||||
|
//
|
||||||
|
this.label1.AutoSize = true;
|
||||||
|
this.label1.Location = new System.Drawing.Point(5, 123);
|
||||||
|
this.label1.Name = "label1";
|
||||||
|
this.label1.Size = new System.Drawing.Size(103, 19);
|
||||||
|
this.label1.TabIndex = 7;
|
||||||
|
this.label1.Text = "Grand Prix URL";
|
||||||
|
//
|
||||||
|
// gpbxRanking
|
||||||
|
//
|
||||||
|
this.gpbxRanking.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(79)))), ((int)(((byte)(79)))), ((int)(((byte)(79)))));
|
||||||
|
this.gpbxRanking.Controls.Add(this.pnlLiveRanking);
|
||||||
|
this.gpbxRanking.ForeColor = System.Drawing.Color.FromArgb(((int)(((byte)(252)))), ((int)(((byte)(252)))), ((int)(((byte)(252)))));
|
||||||
|
this.gpbxRanking.Location = new System.Drawing.Point(838, 9);
|
||||||
|
this.gpbxRanking.Margin = new System.Windows.Forms.Padding(3, 4, 3, 4);
|
||||||
|
this.gpbxRanking.Name = "gpbxRanking";
|
||||||
|
this.gpbxRanking.Padding = new System.Windows.Forms.Padding(3, 4, 3, 4);
|
||||||
|
this.gpbxRanking.Size = new System.Drawing.Size(314, 747);
|
||||||
|
this.gpbxRanking.TabIndex = 8;
|
||||||
|
this.gpbxRanking.TabStop = false;
|
||||||
|
this.gpbxRanking.Text = "Live Ranking";
|
||||||
|
this.gpbxRanking.Paint += new System.Windows.Forms.PaintEventHandler(this.removeBorders);
|
||||||
|
//
|
||||||
|
// pnlLiveRanking
|
||||||
|
//
|
||||||
|
this.pnlLiveRanking.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(51)))), ((int)(((byte)(51)))), ((int)(((byte)(51)))));
|
||||||
|
this.pnlLiveRanking.Location = new System.Drawing.Point(6, 25);
|
||||||
|
this.pnlLiveRanking.Margin = new System.Windows.Forms.Padding(3, 4, 3, 4);
|
||||||
|
this.pnlLiveRanking.Name = "pnlLiveRanking";
|
||||||
|
this.pnlLiveRanking.Size = new System.Drawing.Size(300, 714);
|
||||||
|
this.pnlLiveRanking.TabIndex = 0;
|
||||||
|
//
|
||||||
|
// gpbxOvertakes
|
||||||
|
//
|
||||||
|
this.gpbxOvertakes.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(79)))), ((int)(((byte)(79)))), ((int)(((byte)(79)))));
|
||||||
|
this.gpbxOvertakes.Controls.Add(this.lsbOvertakes);
|
||||||
|
this.gpbxOvertakes.ForeColor = System.Drawing.Color.FromArgb(((int)(((byte)(252)))), ((int)(((byte)(252)))), ((int)(((byte)(252)))));
|
||||||
|
this.gpbxOvertakes.Location = new System.Drawing.Point(12, 514);
|
||||||
|
this.gpbxOvertakes.Margin = new System.Windows.Forms.Padding(3, 4, 3, 4);
|
||||||
|
this.gpbxOvertakes.Name = "gpbxOvertakes";
|
||||||
|
this.gpbxOvertakes.Padding = new System.Windows.Forms.Padding(3, 4, 3, 4);
|
||||||
|
this.gpbxOvertakes.Size = new System.Drawing.Size(263, 242);
|
||||||
|
this.gpbxOvertakes.TabIndex = 9;
|
||||||
|
this.gpbxOvertakes.TabStop = false;
|
||||||
|
this.gpbxOvertakes.Text = "Overtakes";
|
||||||
|
this.gpbxOvertakes.Paint += new System.Windows.Forms.PaintEventHandler(this.removeBorders);
|
||||||
|
//
|
||||||
|
// lsbOvertakes
|
||||||
|
//
|
||||||
|
this.lsbOvertakes.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(51)))), ((int)(((byte)(51)))), ((int)(((byte)(51)))));
|
||||||
|
this.lsbOvertakes.BorderStyle = System.Windows.Forms.BorderStyle.None;
|
||||||
|
this.lsbOvertakes.ForeColor = System.Drawing.Color.FromArgb(((int)(((byte)(252)))), ((int)(((byte)(252)))), ((int)(((byte)(252)))));
|
||||||
|
this.lsbOvertakes.FormattingEnabled = true;
|
||||||
|
this.lsbOvertakes.ItemHeight = 19;
|
||||||
|
this.lsbOvertakes.Location = new System.Drawing.Point(6, 25);
|
||||||
|
this.lsbOvertakes.Margin = new System.Windows.Forms.Padding(3, 4, 3, 4);
|
||||||
|
this.lsbOvertakes.Name = "lsbOvertakes";
|
||||||
|
this.lsbOvertakes.Size = new System.Drawing.Size(246, 209);
|
||||||
|
this.lsbOvertakes.TabIndex = 0;
|
||||||
|
//
|
||||||
|
// gpbxDriverInfos
|
||||||
|
//
|
||||||
|
this.gpbxDriverInfos.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(79)))), ((int)(((byte)(79)))), ((int)(((byte)(79)))));
|
||||||
|
this.gpbxDriverInfos.Controls.Add(this.pnlCover);
|
||||||
|
this.gpbxDriverInfos.Controls.Add(this.lblCurrentDriverDRS);
|
||||||
|
this.gpbxDriverInfos.Controls.Add(this.lblCurrentDriverTyreType);
|
||||||
|
this.gpbxDriverInfos.Controls.Add(this.label11);
|
||||||
|
this.gpbxDriverInfos.Controls.Add(this.lblCurrentDriverPosition);
|
||||||
|
this.gpbxDriverInfos.Controls.Add(this.lblCurrentDriverGapToLeader);
|
||||||
|
this.gpbxDriverInfos.Controls.Add(this.label5);
|
||||||
|
this.gpbxDriverInfos.Controls.Add(this.label8);
|
||||||
|
this.gpbxDriverInfos.Controls.Add(this.lblCurrentDriverTyreAge);
|
||||||
|
this.gpbxDriverInfos.Controls.Add(this.label6);
|
||||||
|
this.gpbxDriverInfos.Controls.Add(this.pnlCurrentDriverLapsHistory);
|
||||||
|
this.gpbxDriverInfos.Controls.Add(this.lblCurrentDriverLapTime);
|
||||||
|
this.gpbxDriverInfos.Controls.Add(this.label4);
|
||||||
|
this.gpbxDriverInfos.Controls.Add(this.lblCurrentDriverName);
|
||||||
|
this.gpbxDriverInfos.ForeColor = System.Drawing.Color.FromArgb(((int)(((byte)(252)))), ((int)(((byte)(252)))), ((int)(((byte)(252)))));
|
||||||
|
this.gpbxDriverInfos.Location = new System.Drawing.Point(281, 514);
|
||||||
|
this.gpbxDriverInfos.Margin = new System.Windows.Forms.Padding(3, 4, 3, 4);
|
||||||
|
this.gpbxDriverInfos.Name = "gpbxDriverInfos";
|
||||||
|
this.gpbxDriverInfos.Padding = new System.Windows.Forms.Padding(3, 4, 3, 4);
|
||||||
|
this.gpbxDriverInfos.Size = new System.Drawing.Size(550, 242);
|
||||||
|
this.gpbxDriverInfos.TabIndex = 10;
|
||||||
|
this.gpbxDriverInfos.TabStop = false;
|
||||||
|
this.gpbxDriverInfos.Text = "Driver infos";
|
||||||
|
this.gpbxDriverInfos.Paint += new System.Windows.Forms.PaintEventHandler(this.removeBorders);
|
||||||
|
//
|
||||||
|
// pnlCover
|
||||||
|
//
|
||||||
|
this.pnlCover.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(79)))), ((int)(((byte)(79)))), ((int)(((byte)(79)))));
|
||||||
|
this.pnlCover.Controls.Add(this.lbl);
|
||||||
|
this.pnlCover.ForeColor = System.Drawing.Color.FromArgb(((int)(((byte)(252)))), ((int)(((byte)(252)))), ((int)(((byte)(252)))));
|
||||||
|
this.pnlCover.Location = new System.Drawing.Point(9, 19);
|
||||||
|
this.pnlCover.Name = "pnlCover";
|
||||||
|
this.pnlCover.Size = new System.Drawing.Size(535, 216);
|
||||||
|
this.pnlCover.TabIndex = 13;
|
||||||
|
//
|
||||||
|
// lbl
|
||||||
|
//
|
||||||
|
this.lbl.AutoSize = true;
|
||||||
|
this.lbl.Font = new System.Drawing.Font("Microsoft YaHei UI", 20F);
|
||||||
|
this.lbl.Location = new System.Drawing.Point(18, 90);
|
||||||
|
this.lbl.Name = "lbl";
|
||||||
|
this.lbl.Size = new System.Drawing.Size(497, 45);
|
||||||
|
this.lbl.TabIndex = 0;
|
||||||
|
this.lbl.Text = "Select a driver to see its infos";
|
||||||
|
//
|
||||||
|
// lblCurrentDriverDRS
|
||||||
|
//
|
||||||
|
this.lblCurrentDriverDRS.AutoSize = true;
|
||||||
|
this.lblCurrentDriverDRS.Font = new System.Drawing.Font("Microsoft YaHei UI", 12F);
|
||||||
|
this.lblCurrentDriverDRS.Location = new System.Drawing.Point(191, 192);
|
||||||
|
this.lblCurrentDriverDRS.Name = "lblCurrentDriverDRS";
|
||||||
|
this.lblCurrentDriverDRS.Size = new System.Drawing.Size(41, 27);
|
||||||
|
this.lblCurrentDriverDRS.TabIndex = 11;
|
||||||
|
this.lblCurrentDriverDRS.Text = "No";
|
||||||
|
//
|
||||||
|
// lblCurrentDriverTyreType
|
||||||
|
//
|
||||||
|
this.lblCurrentDriverTyreType.AutoSize = true;
|
||||||
|
this.lblCurrentDriverTyreType.Font = new System.Drawing.Font("Microsoft YaHei UI", 12F);
|
||||||
|
this.lblCurrentDriverTyreType.Location = new System.Drawing.Point(66, 155);
|
||||||
|
this.lblCurrentDriverTyreType.Name = "lblCurrentDriverTyreType";
|
||||||
|
this.lblCurrentDriverTyreType.Size = new System.Drawing.Size(111, 27);
|
||||||
|
this.lblCurrentDriverTyreType.TabIndex = 8;
|
||||||
|
this.lblCurrentDriverTyreType.Text = "Undefined";
|
||||||
|
//
|
||||||
|
// label11
|
||||||
|
//
|
||||||
|
this.label11.AutoSize = true;
|
||||||
|
this.label11.Font = new System.Drawing.Font("Microsoft YaHei UI", 12F);
|
||||||
|
this.label11.Location = new System.Drawing.Point(7, 192);
|
||||||
|
this.label11.Name = "label11";
|
||||||
|
this.label11.Size = new System.Drawing.Size(52, 27);
|
||||||
|
this.label11.TabIndex = 10;
|
||||||
|
this.label11.Text = "DRS";
|
||||||
|
//
|
||||||
|
// lblCurrentDriverPosition
|
||||||
|
//
|
||||||
|
this.lblCurrentDriverPosition.AutoSize = true;
|
||||||
|
this.lblCurrentDriverPosition.Font = new System.Drawing.Font("Microsoft YaHei UI", 16.2F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
|
||||||
|
this.lblCurrentDriverPosition.Location = new System.Drawing.Point(216, 21);
|
||||||
|
this.lblCurrentDriverPosition.Name = "lblCurrentDriverPosition";
|
||||||
|
this.lblCurrentDriverPosition.Size = new System.Drawing.Size(43, 36);
|
||||||
|
this.lblCurrentDriverPosition.TabIndex = 12;
|
||||||
|
this.lblCurrentDriverPosition.Text = "-1";
|
||||||
|
//
|
||||||
|
// lblCurrentDriverGapToLeader
|
||||||
|
//
|
||||||
|
this.lblCurrentDriverGapToLeader.AutoSize = true;
|
||||||
|
this.lblCurrentDriverGapToLeader.Font = new System.Drawing.Font("Microsoft YaHei UI", 12F);
|
||||||
|
this.lblCurrentDriverGapToLeader.Location = new System.Drawing.Point(191, 119);
|
||||||
|
this.lblCurrentDriverGapToLeader.Name = "lblCurrentDriverGapToLeader";
|
||||||
|
this.lblCurrentDriverGapToLeader.Size = new System.Drawing.Size(94, 27);
|
||||||
|
this.lblCurrentDriverGapToLeader.TabIndex = 6;
|
||||||
|
this.lblCurrentDriverGapToLeader.Text = "0:00.000";
|
||||||
|
//
|
||||||
|
// label5
|
||||||
|
//
|
||||||
|
this.label5.AutoSize = true;
|
||||||
|
this.label5.Font = new System.Drawing.Font("Microsoft YaHei UI", 12F);
|
||||||
|
this.label5.Location = new System.Drawing.Point(7, 119);
|
||||||
|
this.label5.Name = "label5";
|
||||||
|
this.label5.Size = new System.Drawing.Size(153, 27);
|
||||||
|
this.label5.TabIndex = 5;
|
||||||
|
this.label5.Text = "Gap to leader :";
|
||||||
|
//
|
||||||
|
// label8
|
||||||
|
//
|
||||||
|
this.label8.AutoSize = true;
|
||||||
|
this.label8.Font = new System.Drawing.Font("Microsoft YaHei UI", 12F);
|
||||||
|
this.label8.Location = new System.Drawing.Point(7, 155);
|
||||||
|
this.label8.Name = "label8";
|
||||||
|
this.label8.Size = new System.Drawing.Size(58, 27);
|
||||||
|
this.label8.TabIndex = 7;
|
||||||
|
this.label8.Text = "Tyre:";
|
||||||
|
//
|
||||||
|
// lblCurrentDriverTyreAge
|
||||||
|
//
|
||||||
|
this.lblCurrentDriverTyreAge.AutoSize = true;
|
||||||
|
this.lblCurrentDriverTyreAge.Font = new System.Drawing.Font("Microsoft YaHei UI", 12F);
|
||||||
|
this.lblCurrentDriverTyreAge.Location = new System.Drawing.Point(191, 155);
|
||||||
|
this.lblCurrentDriverTyreAge.Name = "lblCurrentDriverTyreAge";
|
||||||
|
this.lblCurrentDriverTyreAge.Size = new System.Drawing.Size(85, 27);
|
||||||
|
this.lblCurrentDriverTyreAge.TabIndex = 9;
|
||||||
|
this.lblCurrentDriverTyreAge.Text = "10 Laps";
|
||||||
|
//
|
||||||
|
// label6
|
||||||
|
//
|
||||||
|
this.label6.AutoSize = true;
|
||||||
|
this.label6.Font = new System.Drawing.Font("Microsoft YaHei UI", 12F);
|
||||||
|
this.label6.Location = new System.Drawing.Point(299, 30);
|
||||||
|
this.label6.Name = "label6";
|
||||||
|
this.label6.Size = new System.Drawing.Size(111, 27);
|
||||||
|
this.label6.TabIndex = 4;
|
||||||
|
this.label6.Text = "Last 5 laps";
|
||||||
|
//
|
||||||
|
// pnlCurrentDriverLapsHistory
|
||||||
|
//
|
||||||
|
this.pnlCurrentDriverLapsHistory.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(51)))), ((int)(((byte)(51)))), ((int)(((byte)(51)))));
|
||||||
|
this.pnlCurrentDriverLapsHistory.Location = new System.Drawing.Point(304, 65);
|
||||||
|
this.pnlCurrentDriverLapsHistory.Margin = new System.Windows.Forms.Padding(3, 4, 3, 4);
|
||||||
|
this.pnlCurrentDriverLapsHistory.Name = "pnlCurrentDriverLapsHistory";
|
||||||
|
this.pnlCurrentDriverLapsHistory.Size = new System.Drawing.Size(237, 169);
|
||||||
|
this.pnlCurrentDriverLapsHistory.TabIndex = 3;
|
||||||
|
//
|
||||||
|
// lblCurrentDriverLapTime
|
||||||
|
//
|
||||||
|
this.lblCurrentDriverLapTime.AutoSize = true;
|
||||||
|
this.lblCurrentDriverLapTime.Font = new System.Drawing.Font("Microsoft YaHei UI", 12F);
|
||||||
|
this.lblCurrentDriverLapTime.Location = new System.Drawing.Point(190, 83);
|
||||||
|
this.lblCurrentDriverLapTime.Name = "lblCurrentDriverLapTime";
|
||||||
|
this.lblCurrentDriverLapTime.Size = new System.Drawing.Size(94, 27);
|
||||||
|
this.lblCurrentDriverLapTime.TabIndex = 2;
|
||||||
|
this.lblCurrentDriverLapTime.Text = "0:00.000";
|
||||||
|
//
|
||||||
|
// label4
|
||||||
|
//
|
||||||
|
this.label4.AutoSize = true;
|
||||||
|
this.label4.Font = new System.Drawing.Font("Microsoft YaHei UI", 12F);
|
||||||
|
this.label4.Location = new System.Drawing.Point(6, 82);
|
||||||
|
this.label4.Name = "label4";
|
||||||
|
this.label4.Size = new System.Drawing.Size(105, 27);
|
||||||
|
this.label4.TabIndex = 1;
|
||||||
|
this.label4.Text = "Lap time :";
|
||||||
|
//
|
||||||
|
// lblCurrentDriverName
|
||||||
|
//
|
||||||
|
this.lblCurrentDriverName.AutoSize = true;
|
||||||
|
this.lblCurrentDriverName.Font = new System.Drawing.Font("Microsoft YaHei UI", 16.2F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
|
||||||
|
this.lblCurrentDriverName.Location = new System.Drawing.Point(6, 21);
|
||||||
|
this.lblCurrentDriverName.Name = "lblCurrentDriverName";
|
||||||
|
this.lblCurrentDriverName.Size = new System.Drawing.Size(178, 36);
|
||||||
|
this.lblCurrentDriverName.TabIndex = 0;
|
||||||
|
this.lblCurrentDriverName.Text = "Driver name";
|
||||||
|
//
|
||||||
|
// gpbxLapTimes
|
||||||
|
//
|
||||||
|
this.gpbxLapTimes.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(79)))), ((int)(((byte)(79)))), ((int)(((byte)(79)))));
|
||||||
|
this.gpbxLapTimes.Controls.Add(this.pnlSlowest);
|
||||||
|
this.gpbxLapTimes.Controls.Add(this.label3);
|
||||||
|
this.gpbxLapTimes.Controls.Add(this.label2);
|
||||||
|
this.gpbxLapTimes.Controls.Add(this.pnlFastest);
|
||||||
|
this.gpbxLapTimes.ForeColor = System.Drawing.Color.FromArgb(((int)(((byte)(252)))), ((int)(((byte)(252)))), ((int)(((byte)(252)))));
|
||||||
|
this.gpbxLapTimes.Location = new System.Drawing.Point(281, 9);
|
||||||
|
this.gpbxLapTimes.Margin = new System.Windows.Forms.Padding(3, 4, 3, 4);
|
||||||
|
this.gpbxLapTimes.Name = "gpbxLapTimes";
|
||||||
|
this.gpbxLapTimes.Padding = new System.Windows.Forms.Padding(3, 4, 3, 4);
|
||||||
|
this.gpbxLapTimes.Size = new System.Drawing.Size(550, 275);
|
||||||
|
this.gpbxLapTimes.TabIndex = 11;
|
||||||
|
this.gpbxLapTimes.TabStop = false;
|
||||||
|
this.gpbxLapTimes.Text = "Last five laps";
|
||||||
|
this.gpbxLapTimes.Paint += new System.Windows.Forms.PaintEventHandler(this.removeBorders);
|
||||||
|
//
|
||||||
|
// pnlSlowest
|
||||||
|
//
|
||||||
|
this.pnlSlowest.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(51)))), ((int)(((byte)(51)))), ((int)(((byte)(51)))));
|
||||||
|
this.pnlSlowest.Location = new System.Drawing.Point(280, 39);
|
||||||
|
this.pnlSlowest.Margin = new System.Windows.Forms.Padding(3, 4, 3, 4);
|
||||||
|
this.pnlSlowest.Name = "pnlSlowest";
|
||||||
|
this.pnlSlowest.Size = new System.Drawing.Size(264, 228);
|
||||||
|
this.pnlSlowest.TabIndex = 1;
|
||||||
|
//
|
||||||
|
// label3
|
||||||
|
//
|
||||||
|
this.label3.AutoSize = true;
|
||||||
|
this.label3.Location = new System.Drawing.Point(276, 16);
|
||||||
|
this.label3.Name = "label3";
|
||||||
|
this.label3.Size = new System.Drawing.Size(62, 19);
|
||||||
|
this.label3.TabIndex = 3;
|
||||||
|
this.label3.Text = "Slowests";
|
||||||
|
//
|
||||||
|
// label2
|
||||||
|
//
|
||||||
|
this.label2.AutoSize = true;
|
||||||
|
this.label2.Location = new System.Drawing.Point(6, 17);
|
||||||
|
this.label2.Name = "label2";
|
||||||
|
this.label2.Size = new System.Drawing.Size(58, 19);
|
||||||
|
this.label2.TabIndex = 2;
|
||||||
|
this.label2.Text = "Fastests";
|
||||||
|
//
|
||||||
|
// pnlFastest
|
||||||
|
//
|
||||||
|
this.pnlFastest.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(51)))), ((int)(((byte)(51)))), ((int)(((byte)(51)))));
|
||||||
|
this.pnlFastest.Location = new System.Drawing.Point(6, 39);
|
||||||
|
this.pnlFastest.Margin = new System.Windows.Forms.Padding(3, 4, 3, 4);
|
||||||
|
this.pnlFastest.Name = "pnlFastest";
|
||||||
|
this.pnlFastest.Size = new System.Drawing.Size(270, 228);
|
||||||
|
this.pnlFastest.TabIndex = 0;
|
||||||
|
//
|
||||||
|
// gpbxBattles
|
||||||
|
//
|
||||||
|
this.gpbxBattles.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(79)))), ((int)(((byte)(79)))), ((int)(((byte)(79)))));
|
||||||
|
this.gpbxBattles.Controls.Add(this.pnlBattles);
|
||||||
|
this.gpbxBattles.ForeColor = System.Drawing.Color.FromArgb(((int)(((byte)(252)))), ((int)(((byte)(252)))), ((int)(((byte)(252)))));
|
||||||
|
this.gpbxBattles.Location = new System.Drawing.Point(281, 292);
|
||||||
|
this.gpbxBattles.Margin = new System.Windows.Forms.Padding(3, 4, 3, 4);
|
||||||
|
this.gpbxBattles.Name = "gpbxBattles";
|
||||||
|
this.gpbxBattles.Padding = new System.Windows.Forms.Padding(3, 4, 3, 4);
|
||||||
|
this.gpbxBattles.Size = new System.Drawing.Size(550, 214);
|
||||||
|
this.gpbxBattles.TabIndex = 11;
|
||||||
|
this.gpbxBattles.TabStop = false;
|
||||||
|
this.gpbxBattles.Text = "Battles";
|
||||||
|
this.gpbxBattles.Paint += new System.Windows.Forms.PaintEventHandler(this.removeBorders);
|
||||||
|
//
|
||||||
|
// pnlBattles
|
||||||
|
//
|
||||||
|
this.pnlBattles.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(51)))), ((int)(((byte)(51)))), ((int)(((byte)(51)))));
|
||||||
|
this.pnlBattles.Location = new System.Drawing.Point(9, 25);
|
||||||
|
this.pnlBattles.Margin = new System.Windows.Forms.Padding(3, 4, 3, 4);
|
||||||
|
this.pnlBattles.Name = "pnlBattles";
|
||||||
|
this.pnlBattles.Size = new System.Drawing.Size(532, 181);
|
||||||
|
this.pnlBattles.TabIndex = 2;
|
||||||
|
//
|
||||||
|
// label9
|
||||||
|
//
|
||||||
|
this.label9.AutoSize = true;
|
||||||
|
this.label9.BackColor = System.Drawing.Color.Transparent;
|
||||||
|
this.label9.Font = new System.Drawing.Font("Microsoft YaHei UI", 19.8F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
|
||||||
|
this.label9.ForeColor = System.Drawing.Color.FromArgb(((int)(((byte)(252)))), ((int)(((byte)(252)))), ((int)(((byte)(252)))));
|
||||||
|
this.label9.Location = new System.Drawing.Point(33, 9);
|
||||||
|
this.label9.Name = "label9";
|
||||||
|
this.label9.Size = new System.Drawing.Size(221, 43);
|
||||||
|
this.label9.TabIndex = 12;
|
||||||
|
this.label9.Text = "Track Trends";
|
||||||
|
//
|
||||||
|
// Main
|
||||||
|
//
|
||||||
|
this.AutoScaleDimensions = new System.Drawing.SizeF(8F, 19F);
|
||||||
|
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
|
||||||
|
this.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(51)))), ((int)(((byte)(51)))), ((int)(((byte)(51)))));
|
||||||
|
this.ClientSize = new System.Drawing.Size(1164, 761);
|
||||||
|
this.Controls.Add(this.label9);
|
||||||
|
this.Controls.Add(this.gpbxBattles);
|
||||||
|
this.Controls.Add(this.gpbxLapTimes);
|
||||||
|
this.Controls.Add(this.gpbxDriverInfos);
|
||||||
|
this.Controls.Add(this.gpbxRanking);
|
||||||
|
this.Controls.Add(this.gpbxOvertakes);
|
||||||
|
this.Controls.Add(this.gpbxControls);
|
||||||
|
this.Font = new System.Drawing.Font("Microsoft YaHei UI", 7.8F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
|
||||||
|
this.Margin = new System.Windows.Forms.Padding(3, 4, 3, 4);
|
||||||
|
this.MinimumSize = new System.Drawing.Size(1182, 808);
|
||||||
|
this.Name = "Main";
|
||||||
|
this.StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen;
|
||||||
|
this.Text = "Track Trends";
|
||||||
|
this.FormClosing += new System.Windows.Forms.FormClosingEventHandler(this.Form1_FormClosing);
|
||||||
|
this.Load += new System.EventHandler(this.Form1_Load);
|
||||||
|
this.Resize += new System.EventHandler(this.Main_Resize);
|
||||||
|
((System.ComponentModel.ISupportInitialize)(this.pbxResult)).EndInit();
|
||||||
|
this.gpbxControls.ResumeLayout(false);
|
||||||
|
this.gpbxControls.PerformLayout();
|
||||||
|
this.gpbxRanking.ResumeLayout(false);
|
||||||
|
this.gpbxOvertakes.ResumeLayout(false);
|
||||||
|
this.gpbxDriverInfos.ResumeLayout(false);
|
||||||
|
this.gpbxDriverInfos.PerformLayout();
|
||||||
|
this.pnlCover.ResumeLayout(false);
|
||||||
|
this.pnlCover.PerformLayout();
|
||||||
|
this.gpbxLapTimes.ResumeLayout(false);
|
||||||
|
this.gpbxLapTimes.PerformLayout();
|
||||||
|
this.gpbxBattles.ResumeLayout(false);
|
||||||
|
this.ResumeLayout(false);
|
||||||
|
this.PerformLayout();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
private System.Windows.Forms.Button btnSettings;
|
||||||
|
private System.Windows.Forms.Button btnStartDecoding;
|
||||||
|
private System.Windows.Forms.PictureBox pbxResult;
|
||||||
|
private System.Windows.Forms.Button btnStopUpdating;
|
||||||
|
private System.Windows.Forms.Button btnResetEmulator;
|
||||||
|
private System.Windows.Forms.ListBox lsbPresets;
|
||||||
|
private System.Windows.Forms.GroupBox gpbxControls;
|
||||||
|
private System.Windows.Forms.TextBox tbxGpUrl;
|
||||||
|
private System.Windows.Forms.Label label1;
|
||||||
|
private System.Windows.Forms.GroupBox gpbxRanking;
|
||||||
|
private System.Windows.Forms.Panel pnlLiveRanking;
|
||||||
|
private System.Windows.Forms.GroupBox gpbxOvertakes;
|
||||||
|
private System.Windows.Forms.GroupBox gpbxDriverInfos;
|
||||||
|
private System.Windows.Forms.Label lblCurrentDriverPosition;
|
||||||
|
private System.Windows.Forms.Label lblCurrentDriverDRS;
|
||||||
|
private System.Windows.Forms.Label label11;
|
||||||
|
private System.Windows.Forms.Label lblCurrentDriverTyreAge;
|
||||||
|
private System.Windows.Forms.Label lblCurrentDriverTyreType;
|
||||||
|
private System.Windows.Forms.Label label8;
|
||||||
|
private System.Windows.Forms.Label lblCurrentDriverGapToLeader;
|
||||||
|
private System.Windows.Forms.Label label5;
|
||||||
|
private System.Windows.Forms.Label label6;
|
||||||
|
private System.Windows.Forms.Panel pnlCurrentDriverLapsHistory;
|
||||||
|
private System.Windows.Forms.Label lblCurrentDriverLapTime;
|
||||||
|
private System.Windows.Forms.Label label4;
|
||||||
|
private System.Windows.Forms.Label lblCurrentDriverName;
|
||||||
|
private System.Windows.Forms.GroupBox gpbxLapTimes;
|
||||||
|
private System.Windows.Forms.Label label3;
|
||||||
|
private System.Windows.Forms.Label label2;
|
||||||
|
private System.Windows.Forms.Panel pnlSlowest;
|
||||||
|
private System.Windows.Forms.Panel pnlFastest;
|
||||||
|
private System.Windows.Forms.GroupBox gpbxBattles;
|
||||||
|
private System.Windows.Forms.Panel pnlBattles;
|
||||||
|
private System.Windows.Forms.ListBox lsbOvertakes;
|
||||||
|
private System.Windows.Forms.Label label7;
|
||||||
|
private System.Windows.Forms.Label label9;
|
||||||
|
private System.Windows.Forms.ToolTip tip1;
|
||||||
|
private System.Windows.Forms.Panel pnlCover;
|
||||||
|
private System.Windows.Forms.Label lbl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,422 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.ComponentModel;
|
||||||
|
using System.Data;
|
||||||
|
using System.Diagnostics;
|
||||||
|
using System.Drawing;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using System.Windows.Forms;
|
||||||
|
using System.IO;
|
||||||
|
|
||||||
|
namespace TrackTrends
|
||||||
|
{
|
||||||
|
public partial class Main : Form
|
||||||
|
{
|
||||||
|
//private Reader Reader = null;
|
||||||
|
private F1TVEmulator Emulator = null;
|
||||||
|
private DataWrapper Wrapper = null;
|
||||||
|
private bool cancelRequested = false;
|
||||||
|
private SemaphoreSlim semaphore = new SemaphoreSlim(1);
|
||||||
|
|
||||||
|
string ConfigFile = "";
|
||||||
|
string GpUrl = "";
|
||||||
|
|
||||||
|
//For the responsive content
|
||||||
|
|
||||||
|
Size oldSize = new Size();
|
||||||
|
Size oldRankingSize = new Size();
|
||||||
|
Size oldLapTimesSize = new Size();
|
||||||
|
Size oldBattles = new Size();
|
||||||
|
|
||||||
|
Size oldPnlBattles = new Size();
|
||||||
|
Size oldPnlRankings = new Size();
|
||||||
|
Size oldPnlFastest = new Size();
|
||||||
|
Size oldPnlSlowest = new Size();
|
||||||
|
|
||||||
|
Point oldRankingPosition = new Point();
|
||||||
|
Point oldBattlePosition = new Point();
|
||||||
|
Point oldDriverInfoPosition = new Point();
|
||||||
|
|
||||||
|
Point olPnlFastestPosition = new Point();
|
||||||
|
Point oldPnlSlowestPosition = new Point();
|
||||||
|
|
||||||
|
public Main()
|
||||||
|
{
|
||||||
|
InitializeComponent();
|
||||||
|
}
|
||||||
|
public async void RefreshUI()
|
||||||
|
{
|
||||||
|
if (Directory.Exists(ConfigurationTool.CONFIGS_FOLDER_NAME))
|
||||||
|
{
|
||||||
|
lsbPresets.DataSource = null;
|
||||||
|
lsbPresets.DataSource = Directory.GetFiles(ConfigurationTool.CONFIGS_FOLDER_NAME);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
private async void btnSettings_Click(object sender, EventArgs e)
|
||||||
|
{
|
||||||
|
if (Emulator != null)
|
||||||
|
Emulator.ResetDriver();
|
||||||
|
|
||||||
|
btnStartDecoding.Enabled = false;
|
||||||
|
btnStopUpdating.Enabled = false;
|
||||||
|
btnResetEmulator.Text = "Launch";
|
||||||
|
|
||||||
|
Emulator = null;
|
||||||
|
Wrapper = null;
|
||||||
|
|
||||||
|
GC.Collect();
|
||||||
|
|
||||||
|
Settings settingsForm = new Settings();
|
||||||
|
settingsForm.ShowDialog();
|
||||||
|
RefreshUI();
|
||||||
|
//MessageBox.Show(settingsForm.GrandPrixUrl + Environment.NewLine + settingsForm.GrandPrixName + Environment.NewLine + settingsForm.GrandPrixYear);
|
||||||
|
if (settingsForm.GrandPrixUrl != "" && settingsForm.SelectedConfigFile != "")
|
||||||
|
{
|
||||||
|
GpUrl = settingsForm.GrandPrixUrl;
|
||||||
|
tbxGpUrl.Text = GpUrl;
|
||||||
|
if (File.Exists(settingsForm.SelectedConfigFile))
|
||||||
|
{
|
||||||
|
ConfigFile = settingsForm.SelectedConfigFile;
|
||||||
|
for(int i = 0; i < lsbPresets.Items.Count; i++)
|
||||||
|
{
|
||||||
|
if (lsbPresets.Items[i].ToString() == ConfigFile)
|
||||||
|
lsbPresets.SelectedIndex = i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
MessageBox.Show("The config file has not been found please return to the config and change it");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
//WE dont care anymore, the user will choose its Grand Prix himself in the main program
|
||||||
|
//MessageBox.Show("There is no URL for the Grand Prix you want to decode. Please return to the config and add a valid one");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private async void Form1_Load(object sender, EventArgs e)
|
||||||
|
{
|
||||||
|
//Those are the default values but they will need to be changed later when the configuration has been done
|
||||||
|
ConfigFile = "./Presets/Clean_4K_2023.json";
|
||||||
|
GpUrl = "https://f1tv.formula1.com/detail/1000006688/2023-azerbaijan-grand-prix?action=play";
|
||||||
|
|
||||||
|
tbxGpUrl.Text = GpUrl;
|
||||||
|
|
||||||
|
oldSize = this.Size;
|
||||||
|
oldRankingSize = gpbxRanking.Size;
|
||||||
|
oldLapTimesSize = gpbxLapTimes.Size;
|
||||||
|
oldBattles = gpbxBattles.Size;
|
||||||
|
|
||||||
|
oldPnlRankings = pnlLiveRanking.Size;
|
||||||
|
oldPnlBattles = pnlBattles.Size;
|
||||||
|
oldPnlFastest = pnlFastest.Size;
|
||||||
|
oldPnlSlowest = pnlSlowest.Size;
|
||||||
|
|
||||||
|
oldRankingPosition = gpbxRanking.Location;
|
||||||
|
oldBattlePosition = gpbxBattles.Location;
|
||||||
|
oldDriverInfoPosition = gpbxDriverInfos.Location;
|
||||||
|
|
||||||
|
olPnlFastestPosition = pnlFastest.Location;
|
||||||
|
oldPnlSlowestPosition = pnlSlowest.Location;
|
||||||
|
|
||||||
|
tip1.SetToolTip(btnResetEmulator, "Starts or restarts the emulator. You need to start this to use the app");
|
||||||
|
tip1.SetToolTip(btnSettings, "Opens the configuration menu");
|
||||||
|
tip1.SetToolTip(tbxGpUrl, "Insert the URL of the Grand Prix you want to track. Dont forget the \"?action=play\" at the end");
|
||||||
|
tip1.SetToolTip(lsbPresets, "Select a configuration preset to use with the decoding");
|
||||||
|
tip1.SetToolTip(pbxResult,"A preview of what the program sees. You should see the DATA page of the F1TV here");
|
||||||
|
tip1.SetToolTip(lsbOvertakes,"A list of all the activity. You can scroll to see the most recent overtakes");
|
||||||
|
tip1.SetToolTip(gpbxBattles,"The four first battles in the field. A battle is two drivers less than 3 seconds apart");
|
||||||
|
tip1.SetToolTip(gpbxLapTimes,"The fastest and slowest drivers on track at the moment. It takes the average lapTime of the last 5 laps to choose who is the fastes or the slowest");
|
||||||
|
|
||||||
|
RefreshUI();
|
||||||
|
}
|
||||||
|
|
||||||
|
private async void btnUpdate_Click(object sender, EventArgs e)
|
||||||
|
{
|
||||||
|
cancelRequested = false;
|
||||||
|
if (Emulator != null && Wrapper != null)
|
||||||
|
{
|
||||||
|
// Disable UI controls to prevent re-entrancy
|
||||||
|
btnResetEmulator.Enabled = false;
|
||||||
|
btnStartDecoding.Enabled = false;
|
||||||
|
btnStopUpdating.Enabled = true;
|
||||||
|
btnSettings.Enabled = false;
|
||||||
|
while (!cancelRequested)
|
||||||
|
{
|
||||||
|
await semaphore.WaitAsync();
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
// Start the time-consuming task on a separate thread
|
||||||
|
await Task.Run(async () =>
|
||||||
|
{
|
||||||
|
Stopwatch sw = new Stopwatch();
|
||||||
|
sw.Start();
|
||||||
|
|
||||||
|
Bitmap screen = Emulator.Screenshot();
|
||||||
|
screen.Save("HopefullyDataScreenshot.png");
|
||||||
|
|
||||||
|
Invoke((MethodInvoker)delegate
|
||||||
|
{
|
||||||
|
pbxResult.Image = (Bitmap)screen.Clone();
|
||||||
|
});
|
||||||
|
|
||||||
|
Wrapper.ChangeImage(screen);
|
||||||
|
int errorCode = Wrapper.Refresh();
|
||||||
|
|
||||||
|
sw.Stop();
|
||||||
|
// Task completed
|
||||||
|
Invoke((MethodInvoker)delegate
|
||||||
|
{
|
||||||
|
DisplayResults(errorCode, sw, screen);
|
||||||
|
DisplayBattles();
|
||||||
|
DisplayDeltas();
|
||||||
|
DisplayOvertakes();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
semaphore.Release();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Re-enable UI controls
|
||||||
|
btnStopUpdating.Text = "Stop";
|
||||||
|
btnStartDecoding.Enabled = true;
|
||||||
|
btnStopUpdating.Enabled = false;
|
||||||
|
btnResetEmulator.Enabled = true;
|
||||||
|
btnSettings.Enabled = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
private void DisplayOvertakes()
|
||||||
|
{
|
||||||
|
Wrapper.DisplayOvertakes(lsbOvertakes);
|
||||||
|
}
|
||||||
|
private void DisplayBattles()
|
||||||
|
{
|
||||||
|
Wrapper.DisplayBattles(pnlBattles, this);
|
||||||
|
}
|
||||||
|
private void DisplayDeltas()
|
||||||
|
{
|
||||||
|
Wrapper.DisplayTimesDeltas(pnlFastest, pnlSlowest, this);
|
||||||
|
}
|
||||||
|
private void Form1_FormClosing(object sender, FormClosingEventArgs e)
|
||||||
|
{
|
||||||
|
if (Emulator != null)
|
||||||
|
{
|
||||||
|
Emulator.Stop();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
private void DisplayResults(int errorCode, Stopwatch sw, Bitmap screen)
|
||||||
|
{
|
||||||
|
if (errorCode != 0)
|
||||||
|
{
|
||||||
|
cancelRequested = true;
|
||||||
|
MessageBox.Show("An error has occured while trying to recover data from live feed. This can happen sometimes. I would advise you to restart a few times. If the problem persists check your configuration.");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Wrapper.DisplayLiveRanking(pnlLiveRanking, this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void btnStopUpdating_Click(object sender, EventArgs e)
|
||||||
|
{
|
||||||
|
// Set the cancellation flag
|
||||||
|
cancelRequested = true;
|
||||||
|
btnStopUpdating.Enabled = false;
|
||||||
|
btnResetEmulator.Enabled = false;
|
||||||
|
btnStopUpdating.Text = "Stopping";
|
||||||
|
}
|
||||||
|
private async void button1_Click(object sender, EventArgs e)
|
||||||
|
{
|
||||||
|
lsbOvertakes.Items.Clear();
|
||||||
|
btnResetEmulator.Text = "Launching";
|
||||||
|
btnResetEmulator.Enabled = false;
|
||||||
|
btnSettings.Enabled = true;
|
||||||
|
btnStartDecoding.Enabled = false;
|
||||||
|
btnStopUpdating.Enabled = false;
|
||||||
|
btnSettings.Enabled = false;
|
||||||
|
int errorCode = -1;
|
||||||
|
await Task.Run(async () =>
|
||||||
|
{
|
||||||
|
if (Emulator != null)
|
||||||
|
Emulator.ResetDriver();
|
||||||
|
|
||||||
|
Emulator = null;
|
||||||
|
Wrapper = null;
|
||||||
|
|
||||||
|
GC.Collect();
|
||||||
|
|
||||||
|
Emulator = new F1TVEmulator(GpUrl);
|
||||||
|
errorCode = await Emulator.Start();
|
||||||
|
});
|
||||||
|
|
||||||
|
if (errorCode != 0)
|
||||||
|
{
|
||||||
|
string message = "";
|
||||||
|
switch (errorCode)
|
||||||
|
{
|
||||||
|
case 100:
|
||||||
|
message = "Error " + errorCode + " Could not recover cookies. It could be because of an improper installation of python or bad cookies in the chrome database. Please try to log on to the F1TV using chrome again";
|
||||||
|
break;
|
||||||
|
case 101:
|
||||||
|
message = "Error " + errorCode + " Could not start the driver. It could be because an other instance is runnin make sure you closed them all before trying again";
|
||||||
|
break;
|
||||||
|
case 102:
|
||||||
|
message = "Error " + errorCode + " Could not navigate on the F1TV site. Make sure the correct URL has been given and that you logged from chrome. It can take a few minutes to update";
|
||||||
|
break;
|
||||||
|
case 103:
|
||||||
|
message = "Error " + errorCode + " The url is not a valid url";
|
||||||
|
break;
|
||||||
|
case 104:
|
||||||
|
message = "Error " + errorCode + " The url is not a valid url";
|
||||||
|
break;
|
||||||
|
case 105:
|
||||||
|
message = "Error " + errorCode + " There has been an error trying to emulate button presses. Please try again";
|
||||||
|
break;
|
||||||
|
case 106:
|
||||||
|
message = "Error " + errorCode + " There has been an error trying to emulate button presses. Please try again";
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
message = "Could not start the emulator Error " + errorCode;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
MessageBox.Show(message);
|
||||||
|
|
||||||
|
btnResetEmulator.Enabled = true;
|
||||||
|
btnSettings.Enabled = true;
|
||||||
|
btnResetEmulator.Text = "Retry";
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Wrapper = new DataWrapper(ConfigFile, Emulator.Screenshot());
|
||||||
|
btnResetEmulator.Text = "Re launch";
|
||||||
|
btnResetEmulator.Enabled = true;
|
||||||
|
btnSettings.Enabled = true;
|
||||||
|
btnStartDecoding.Enabled = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
private void removeBorders(object sender, PaintEventArgs e)
|
||||||
|
{
|
||||||
|
GroupBox gpbx = (GroupBox)sender;
|
||||||
|
|
||||||
|
using (Pen pen = new Pen(gpbx.BackColor, 50))
|
||||||
|
{
|
||||||
|
e.Graphics.DrawRectangle(pen, 0, 0, gpbx.Width - 1, gpbx.Height - 1);
|
||||||
|
e.Graphics.DrawRectangle(pen, 0, 0, gpbx.Width - 1, gpbx.Height - 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
using (var brush = new SolidBrush(gpbx.ForeColor))
|
||||||
|
{
|
||||||
|
var textPosition = new Point(5, 0); // Adjust the X and Y values as needed
|
||||||
|
e.Graphics.DrawString(gpbx.Text, gpbx.Font, brush, textPosition);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
private void lsbPresets_SelectedIndexChanged(object sender, EventArgs e)
|
||||||
|
{
|
||||||
|
if (lsbPresets.SelectedIndex >= 0)
|
||||||
|
ConfigFile = lsbPresets.Items[lsbPresets.SelectedIndex].ToString();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void textBox1_TextChanged(object sender, EventArgs e)
|
||||||
|
{
|
||||||
|
if (tbxGpUrl.Text != "")
|
||||||
|
GpUrl = tbxGpUrl.Text;
|
||||||
|
}
|
||||||
|
public void btnDriver_Click(object sender, EventArgs e)
|
||||||
|
{
|
||||||
|
//Removes the cover
|
||||||
|
if (pnlCover.Visible = true)
|
||||||
|
pnlCover.Visible = false;
|
||||||
|
//Happens when a driver button has been clicked
|
||||||
|
//MessageBox.Show((sender as Button).Name + " has been selected");
|
||||||
|
Button btn = (sender as Button);
|
||||||
|
string[] parts = btn.Name.Split('_');
|
||||||
|
DriverData driver = Wrapper.GetFullDriverData(parts[0], pnlCurrentDriverLapsHistory, this);
|
||||||
|
lblCurrentDriverName.Text = driver.Name;
|
||||||
|
lblCurrentDriverPosition.Text = driver.Position.ToString();
|
||||||
|
lblCurrentDriverGapToLeader.Text = Reader.ConvertMsToTime(driver.GapToLeader);
|
||||||
|
lblCurrentDriverLapTime.Text = Reader.ConvertMsToTime(driver.LapTime);
|
||||||
|
lblCurrentDriverTyreAge.Text = driver.CurrentTyre.NumberOfLaps.ToString();
|
||||||
|
if (driver.DRS)
|
||||||
|
{
|
||||||
|
lblCurrentDriverDRS.Text = "Open";
|
||||||
|
lblCurrentDriverDRS.ForeColor = Color.FromArgb(0, 164, 46);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
lblCurrentDriverDRS.Text = "Closed";
|
||||||
|
lblCurrentDriverDRS.ForeColor = Color.Black;
|
||||||
|
}
|
||||||
|
switch (driver.CurrentTyre.Coumpound)
|
||||||
|
{
|
||||||
|
case Tyre.Type.Undefined:
|
||||||
|
lblCurrentDriverTyreType.Text = "uuuuh...";
|
||||||
|
lblCurrentDriverTyreType.ForeColor = Color.Violet;
|
||||||
|
break;
|
||||||
|
case Tyre.Type.Hard:
|
||||||
|
lblCurrentDriverTyreType.Text = "Hard";
|
||||||
|
lblCurrentDriverTyreType.ForeColor = Color.FromArgb(164, 165, 168);
|
||||||
|
break;
|
||||||
|
case Tyre.Type.Medium:
|
||||||
|
lblCurrentDriverTyreType.Text = "Medium";
|
||||||
|
lblCurrentDriverTyreType.ForeColor = Color.FromArgb(245, 191, 0);
|
||||||
|
break;
|
||||||
|
case Tyre.Type.Soft:
|
||||||
|
lblCurrentDriverTyreType.Text = "Soft";
|
||||||
|
lblCurrentDriverTyreType.ForeColor = Color.FromArgb(255, 0, 0);
|
||||||
|
break;
|
||||||
|
case Tyre.Type.Inter:
|
||||||
|
lblCurrentDriverTyreType.Text = "Intermediate";
|
||||||
|
lblCurrentDriverTyreType.ForeColor = Color.FromArgb(0, 164, 46);
|
||||||
|
break;
|
||||||
|
case Tyre.Type.Wet:
|
||||||
|
lblCurrentDriverTyreType.Text = "Wet";
|
||||||
|
lblCurrentDriverTyreType.ForeColor = Color.FromArgb(39, 96, 166);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public void btnLapTime_Click(object sender, EventArgs e)
|
||||||
|
{
|
||||||
|
//Happens when a lapTime has been clicked
|
||||||
|
Button btn = sender as Button;
|
||||||
|
string[] parts = btn.Name.Split('_');
|
||||||
|
Wrapper.DisplayLapTimeInfos(parts[0], Convert.ToInt32(parts[1]), btn.Text);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void Main_Resize(object sender, EventArgs e)
|
||||||
|
{
|
||||||
|
int xDiff = this.Width - oldSize.Width;
|
||||||
|
int yDiff = this.Height - oldSize.Height;
|
||||||
|
int padding = 10;
|
||||||
|
//This will take half the newly created space
|
||||||
|
gpbxRanking.Size = new Size(oldRankingSize.Width + xDiff / 2, oldRankingSize.Height + yDiff);
|
||||||
|
gpbxRanking.Location = new Point(oldRankingPosition.X + xDiff / 2, gpbxRanking.Location.Y);
|
||||||
|
//Will take half the new height and half the new height
|
||||||
|
gpbxLapTimes.Size = new Size(oldLapTimesSize.Width + xDiff / 2, oldLapTimesSize.Height + yDiff / 2);
|
||||||
|
//Will take half the new height and half the new width
|
||||||
|
gpbxBattles.Size = new Size(oldBattles.Width + xDiff / 2, oldBattles.Height + yDiff / 2);
|
||||||
|
gpbxBattles.Location = new Point(gpbxBattles.Location.X, oldBattlePosition.Y + yDiff / 2);
|
||||||
|
//The infos wont change width but will need to be centerd
|
||||||
|
Point startOfZone = new Point(gpbxOvertakes.Width + gpbxOvertakes.Location.X, gpbxOvertakes.Location.Y);
|
||||||
|
Point endOfZone = new Point(gpbxRanking.Location.X, gpbxOvertakes.Location.Y);
|
||||||
|
int totalWidth = endOfZone.X - startOfZone.X;
|
||||||
|
gpbxDriverInfos.Location = new Point(startOfZone.X + (totalWidth / 2 - gpbxDriverInfos.Width / 2), oldDriverInfoPosition.Y + yDiff);
|
||||||
|
//Now resizing internals
|
||||||
|
pnlFastest.Size = new Size(oldPnlFastest.Width + xDiff / 4,oldPnlFastest.Height + yDiff / 4);
|
||||||
|
pnlFastest.Location = new Point(olPnlFastestPosition.X,olPnlFastestPosition.Y + yDiff / 4);
|
||||||
|
|
||||||
|
pnlSlowest.Size = new Size(oldPnlSlowest.Width + xDiff / 4, oldPnlSlowest.Height + yDiff / 4);
|
||||||
|
pnlSlowest.Location = new Point(oldPnlSlowestPosition.X + xDiff / 4, oldPnlSlowestPosition.Y + yDiff / 4);
|
||||||
|
|
||||||
|
pnlBattles.Size = new Size(oldPnlBattles.Width + xDiff / 2,oldPnlBattles.Height + yDiff / 2);
|
||||||
|
|
||||||
|
pnlLiveRanking.Size = new Size(oldPnlRankings.Width + xDiff / 2,oldPnlRankings.Height + yDiff);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -117,4 +117,7 @@
|
|||||||
<resheader name="writer">
|
<resheader name="writer">
|
||||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||||
</resheader>
|
</resheader>
|
||||||
|
<metadata name="tip1.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
|
||||||
|
<value>17, 17</value>
|
||||||
|
</metadata>
|
||||||
</root>
|
</root>
|
||||||
@@ -1,11 +1,17 @@
|
|||||||
using System;
|
/// Author : Maxime Rohmer
|
||||||
|
/// Date : 30/05/2023
|
||||||
|
/// File : OcrImage.cs
|
||||||
|
/// Brief : Class containing all the methods used to enhance images for OCR
|
||||||
|
/// Version : Alpha 1.0
|
||||||
|
|
||||||
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using System.Drawing;
|
using System.Drawing;
|
||||||
using System.Drawing.Drawing2D;
|
using System.Drawing.Drawing2D;
|
||||||
using System.Drawing.Imaging;
|
using System.Drawing.Imaging;
|
||||||
|
|
||||||
namespace Test_Merge
|
namespace TrackTrends
|
||||||
{
|
{
|
||||||
public class OcrImage
|
public class OcrImage
|
||||||
{
|
{
|
||||||
@@ -35,31 +41,60 @@ namespace Test_Merge
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="type">The type of the window. Depending on it different enhancing features will be applied</param>
|
/// <param name="type">The type of the window. Depending on it different enhancing features will be applied</param>
|
||||||
/// <returns>The enhanced Bitmap</returns>
|
/// <returns>The enhanced Bitmap</returns>
|
||||||
public Bitmap Enhance(WindowType type = WindowType.Text)
|
public Bitmap Enhance(int id,WindowType type = WindowType.Text)
|
||||||
{
|
{
|
||||||
Bitmap outputBitmap = (Bitmap)InputBitmap.Clone();
|
Bitmap outputBitmap = (Bitmap)InputBitmap.Clone();
|
||||||
|
//Note : If you plan to activate all the comments that I used to debug the OCR I would advise to make sure that the debug folder exists
|
||||||
switch (type)
|
switch (type)
|
||||||
{
|
{
|
||||||
case WindowType.LapTime:
|
case WindowType.Gap:
|
||||||
outputBitmap = Tresholding(outputBitmap, 185);
|
//outputBitmap.Save(Window.GAPTOLEADER_DEBUG_FOLDER + @"\raw_" + id + ".png");
|
||||||
|
|
||||||
|
outputBitmap = Tresholding(outputBitmap, 165);
|
||||||
|
//outputBitmap.Save(Window.GAPTOLEADER_DEBUG_FOLDER + @"\treshold_" + id + ".png");
|
||||||
|
|
||||||
outputBitmap = Resize(outputBitmap, 2);
|
outputBitmap = Resize(outputBitmap, 2);
|
||||||
|
//outputBitmap.Save(Window.GAPTOLEADER_DEBUG_FOLDER + @"\resize_" + id + ".png");
|
||||||
|
|
||||||
outputBitmap = Dilatation(outputBitmap, 1);
|
outputBitmap = Dilatation(outputBitmap, 1);
|
||||||
outputBitmap = Erode(outputBitmap, 1);
|
//outputBitmap.Save(Window.GAPTOLEADER_DEBUG_FOLDER + @"\Final_dilatation_" + id + ".png");
|
||||||
|
break;
|
||||||
|
case WindowType.Sector:
|
||||||
|
//outputBitmap.Save(Window.SECTOR1_DEBUG_FOLDER + @"\raw_" + id + ".png");
|
||||||
|
|
||||||
|
outputBitmap = VanishOxyAction(outputBitmap);
|
||||||
|
//outputBitmap.Save(Window.SECTOR1_DEBUG_FOLDER + @"\vanish_" + id + ".png");
|
||||||
|
|
||||||
|
outputBitmap = Tresholding(outputBitmap, 150);
|
||||||
|
//outputBitmap.Save(Window.SECTOR1_DEBUG_FOLDER + @"\Final_treshold_" + id + ".png");
|
||||||
|
break;
|
||||||
|
case WindowType.LapTime:
|
||||||
|
//outputBitmap.Save(Window.LAPTIME_DEBUG_FOLDER + @"\raw_" + id + ".png");
|
||||||
|
|
||||||
|
outputBitmap = Tresholding(outputBitmap,185);
|
||||||
|
//outputBitmap.Save(Window.LAPTIME_DEBUG_FOLDER + @"\Treshold_" + id + ".png");
|
||||||
|
|
||||||
|
outputBitmap = SobelEdgeDetection(outputBitmap);
|
||||||
|
//outputBitmap.Save(Window.LAPTIME_DEBUG_FOLDER + @"\SobelDetection_" + id + ".png");
|
||||||
break;
|
break;
|
||||||
case WindowType.Text:
|
case WindowType.Text:
|
||||||
outputBitmap = InvertColors(outputBitmap);
|
//outputBitmap.Save(Window.STRING_DEBUG_FOLDER + @"\raw_" + id + ".png");
|
||||||
|
|
||||||
outputBitmap = Tresholding(outputBitmap, 165);
|
outputBitmap = Tresholding(outputBitmap, 165);
|
||||||
outputBitmap = Resize(outputBitmap, 2);
|
//outputBitmap.Save(Window.STRING_DEBUG_FOLDER + @"\Final_treshold_" + id + ".png");
|
||||||
outputBitmap = Dilatation(outputBitmap, 1);
|
|
||||||
break;
|
break;
|
||||||
case WindowType.Tyre:
|
case WindowType.Tyre:
|
||||||
|
//outputBitmap.Save(Window.TYRE_DEBUG_FOLDER + @"\raw_" + id + ".png");
|
||||||
|
|
||||||
outputBitmap = RemoveUseless(outputBitmap);
|
outputBitmap = RemoveUseless(outputBitmap);
|
||||||
outputBitmap = Resize(outputBitmap, 4);
|
//outputBitmap.Save(Window.TYRE_DEBUG_FOLDER + @"\uselessRemoved_" + id + ".png");
|
||||||
|
|
||||||
outputBitmap = Dilatation(outputBitmap, 1);
|
outputBitmap = Dilatation(outputBitmap, 1);
|
||||||
|
//outputBitmap.Save(Window.TYRE_DEBUG_FOLDER + @"\Final_dilatation_" + id + ".png");
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
outputBitmap = Tresholding(outputBitmap, 165);
|
outputBitmap = Tresholding(outputBitmap, 165);
|
||||||
outputBitmap = Resize(outputBitmap, 4);
|
outputBitmap = Resize(outputBitmap, 2);
|
||||||
outputBitmap = Erode(outputBitmap, 1);
|
outputBitmap = Erode(outputBitmap, 1);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -93,10 +128,115 @@ namespace Test_Merge
|
|||||||
//Those a specific values to correct the weights so its more pleasing to the human eye
|
//Those a specific values to correct the weights so its more pleasing to the human eye
|
||||||
int gray = (int)(red * 0.3 + green * 0.59 + blue * 0.11);
|
int gray = (int)(red * 0.3 + green * 0.59 + blue * 0.11);
|
||||||
|
|
||||||
|
//This is not a proper treshold method but it is helping the sobel edge detection
|
||||||
|
if(gray <= F1TV_BACKGROUND_TRESHOLD.R)
|
||||||
|
{
|
||||||
|
pixel[0] = pixel[1] = pixel[2] = 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
pixel[0] = pixel[1] = pixel[2] = (byte)gray;
|
pixel[0] = pixel[1] = pixel[2] = (byte)gray;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
inputBitmap.UnlockBits(bmpData);
|
||||||
|
|
||||||
|
return inputBitmap;
|
||||||
|
}
|
||||||
|
/// <summary>
|
||||||
|
/// Method that uses the Sobel Edge detection to outline the edges of the characters to help with the OCR
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="grayscaleImage">The image with the sobel edge detection used</param>
|
||||||
|
/// <returns></returns>
|
||||||
|
private Bitmap SobelEdgeDetection(Bitmap grayscaleImage)
|
||||||
|
{
|
||||||
|
// Create a new bitmap for the edges
|
||||||
|
Bitmap edgesImage = new Bitmap(grayscaleImage.Width, grayscaleImage.Height);
|
||||||
|
|
||||||
|
// Define the Sobel operators
|
||||||
|
// Its just a matrix that we will use on the all image
|
||||||
|
int[,] sobelX = { { -1, 0, 1 }, { -2, 0, 2 }, { -1, 0, 1 } };
|
||||||
|
int[,] sobelY = { { -1, -2, -1 }, { 0, 0, 0 }, { 1, 2, 1 } };
|
||||||
|
|
||||||
|
// Apply the Sobel operators and normalize the gradients
|
||||||
|
// NOTE: I dont know how easy or hard it would be to make this paralel but it could be a good idea to do so if possible.
|
||||||
|
for (int y = 1; y < grayscaleImage.Height - 1; y++)
|
||||||
|
{
|
||||||
|
for (int x = 1; x < grayscaleImage.Width - 1; x++)
|
||||||
|
{
|
||||||
|
int gradientX = CalculateGradient(grayscaleImage, sobelX, x, y);
|
||||||
|
int gradientY = CalculateGradient(grayscaleImage, sobelY, x, y);
|
||||||
|
int gradient = (int)Math.Sqrt(gradientX * gradientX + gradientY * gradientY);
|
||||||
|
|
||||||
|
// Normalize the gradient value
|
||||||
|
// In some rare cases the value can exceed 255 so we limit it with the Math.Min method
|
||||||
|
gradient = Math.Min(255, Math.Max(0, gradient));
|
||||||
|
|
||||||
|
edgesImage.SetPixel(x, y, Color.FromArgb(gradient, gradient, gradient));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return edgesImage;
|
||||||
|
}
|
||||||
|
/// <summary>
|
||||||
|
/// Method that's here to be used by the sobel edge detection method (Chat GPT has been used for parts of this method)
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="grayscaleImage">The input image with the grayscale processing already done</param>
|
||||||
|
/// <param name="sobelOperator">The matrix to apply</param>
|
||||||
|
/// <param name="x"></param>
|
||||||
|
/// <param name="y"></param>
|
||||||
|
/// <returns>Returns the processed gradient</returns>
|
||||||
|
private int CalculateGradient(Bitmap grayscaleImage, int[,] sobelOperator, int x, int y)
|
||||||
|
{
|
||||||
|
int gradient = 0;
|
||||||
|
|
||||||
|
for (int j = -1; j <= 1; j++)
|
||||||
|
{
|
||||||
|
for (int i = -1; i <= 1; i++)
|
||||||
|
{
|
||||||
|
int pixelX = grayscaleImage.GetPixel(x + i, y + j).R;
|
||||||
|
gradient += sobelOperator[j + 1, i + 1] * pixelX;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return gradient;
|
||||||
|
}
|
||||||
|
/// <summary>
|
||||||
|
/// Method that is used to whiten an image. Ignore the funny name. Its used to prevent colored text to trouble the OCR when it uses grayscaling
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="inputBitmap">The bitmap to vanish</param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public static Bitmap VanishOxyAction(Bitmap inputBitmap)
|
||||||
|
{
|
||||||
|
Rectangle rect = new Rectangle(0, 0, inputBitmap.Width, inputBitmap.Height);
|
||||||
|
BitmapData bmpData = inputBitmap.LockBits(rect, ImageLockMode.ReadWrite, inputBitmap.PixelFormat);
|
||||||
|
int bytesPerPixel = Bitmap.GetPixelFormatSize(inputBitmap.PixelFormat) / 8;
|
||||||
|
|
||||||
|
unsafe
|
||||||
|
{
|
||||||
|
//Note : MAKE THIS PARALELL OMG WY DID I LEFT IT LIKE THAT
|
||||||
|
byte* ptr = (byte*)bmpData.Scan0.ToPointer();
|
||||||
|
for (int y = 0; y < inputBitmap.Height; y++)
|
||||||
|
{
|
||||||
|
byte* currentLine = ptr + (y * bmpData.Stride);
|
||||||
|
for (int x = 0; x < inputBitmap.Width; x++)
|
||||||
|
{
|
||||||
|
byte* pixel = currentLine + (x * bytesPerPixel);
|
||||||
|
|
||||||
|
int blue = (int)pixel[0];
|
||||||
|
int green = (int)pixel[1];
|
||||||
|
int red = (int)pixel[2];
|
||||||
|
|
||||||
|
int max = Math.Max(Math.Max(blue, green), red);
|
||||||
|
|
||||||
|
if (max > 255 / 3)
|
||||||
|
max = 255;
|
||||||
|
|
||||||
|
pixel[0] = pixel[1] = pixel[2] = (byte)max;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
inputBitmap.UnlockBits(bmpData);
|
inputBitmap.UnlockBits(bmpData);
|
||||||
|
|
||||||
return inputBitmap;
|
return inputBitmap;
|
||||||
@@ -261,7 +401,7 @@ namespace Test_Merge
|
|||||||
int G = pixel[1];
|
int G = pixel[1];
|
||||||
int R = pixel[2];
|
int R = pixel[2];
|
||||||
|
|
||||||
if (R >= F1TV_BACKGROUND_TRESHOLD.R + 15 || G >= F1TV_BACKGROUND_TRESHOLD.G + 15 || B >= F1TV_BACKGROUND_TRESHOLD.B + 15)
|
if (R >= F1TV_BACKGROUND_TRESHOLD.R +25|| G >= F1TV_BACKGROUND_TRESHOLD.G +25|| B >= F1TV_BACKGROUND_TRESHOLD.B +25)
|
||||||
{
|
{
|
||||||
pixel[0] = 0xFF;
|
pixel[0] = 0xFF;
|
||||||
pixel[1] = 0xFF;
|
pixel[1] = 0xFF;
|
||||||
@@ -318,7 +458,7 @@ namespace Test_Merge
|
|||||||
}
|
}
|
||||||
inputBitmap.UnlockBits(bmpData);
|
inputBitmap.UnlockBits(bmpData);
|
||||||
|
|
||||||
return Color.FromArgb(255, Convert.ToInt32((float)totR / (float)totPixels), Convert.ToInt32((float)totG / (float)totPixels), Convert.ToInt32((float)totB / (float)totPixels));
|
return Color.FromArgb(255,Math.Min(Convert.ToInt32((float)totR / (float)totPixels),255), Math.Min(Convert.ToInt32((float)totG / (float)totPixels),255), Math.Min(Convert.ToInt32((float)totB / (float)totPixels),255));
|
||||||
}
|
}
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// This method simply inverts all the colors in a Bitmap
|
/// This method simply inverts all the colors in a Bitmap
|
||||||
@@ -4,7 +4,7 @@ using System.Linq;
|
|||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using System.Windows.Forms;
|
using System.Windows.Forms;
|
||||||
|
|
||||||
namespace Test_Merge
|
namespace TrackTrends
|
||||||
{
|
{
|
||||||
internal static class Program
|
internal static class Program
|
||||||
{
|
{
|
||||||
@@ -16,7 +16,7 @@ namespace Test_Merge
|
|||||||
{
|
{
|
||||||
Application.EnableVisualStyles();
|
Application.EnableVisualStyles();
|
||||||
Application.SetCompatibleTextRenderingDefault(false);
|
Application.SetCompatibleTextRenderingDefault(false);
|
||||||
Application.Run(new Form1());
|
Application.Run(new Main());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Generated
@@ -0,0 +1,338 @@
|
|||||||
|
/// Author : Maxime Rohmer
|
||||||
|
/// Date : 30/05/2023
|
||||||
|
/// File : Reader.cs
|
||||||
|
/// Brief : Class used to Read the config file for the OCR
|
||||||
|
/// Version : Alpha 1.0
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using System.Drawing;
|
||||||
|
using System.Windows.Forms;
|
||||||
|
using System.IO;
|
||||||
|
using System.Text.Json;
|
||||||
|
|
||||||
|
namespace TrackTrends
|
||||||
|
{
|
||||||
|
public class Reader
|
||||||
|
{
|
||||||
|
const int NUMBER_OF_DRIVERS = 20;
|
||||||
|
public List<string> Drivers;
|
||||||
|
public List<Zone> MainZones;
|
||||||
|
|
||||||
|
private SqliteStorage _storage;
|
||||||
|
private List<DriverData>[] DriverDataLogs = new List<DriverData>[NUMBER_OF_DRIVERS];
|
||||||
|
private int[] DriverLaps = new int[NUMBER_OF_DRIVERS];
|
||||||
|
|
||||||
|
public SqliteStorage Storage { get => _storage; private set => _storage = value; }
|
||||||
|
|
||||||
|
public Reader(string configFile, Bitmap image, bool loadOCR = true)
|
||||||
|
{
|
||||||
|
Storage = new SqliteStorage();
|
||||||
|
MainZones = Load(image, configFile, ref Drivers, loadOCR);
|
||||||
|
}
|
||||||
|
/// <summary>
|
||||||
|
/// Method that reads the JSON config file and create all the Zones and Windows
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="imageNumber">The image #id on wich you want to create the zones on</param>
|
||||||
|
public List<Zone> Load(Bitmap image, string configFilePath, ref List<string> driverListToFill, bool LoadOCR)
|
||||||
|
{
|
||||||
|
// Note : You may wonder why in the H... I have all the zones and windows stored in a JSON file and not just for example the first and the last
|
||||||
|
// Its because they are not perfectly aligned to each others and every zone has his own alignement to the main image
|
||||||
|
List<Zone> mainZones = new List<Zone>();
|
||||||
|
Bitmap fullImage = image;
|
||||||
|
Zone mainZone;
|
||||||
|
|
||||||
|
for (int i = 0; i < NUMBER_OF_DRIVERS; i++)
|
||||||
|
{
|
||||||
|
DriverDataLogs[i] = new List<DriverData>();
|
||||||
|
DriverLaps[i] = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
string jsonString = File.ReadAllText(configFilePath);
|
||||||
|
|
||||||
|
JsonDocument document = JsonDocument.Parse(jsonString);
|
||||||
|
|
||||||
|
JsonElement root = document.RootElement;
|
||||||
|
|
||||||
|
mainZones = new List<Zone>();
|
||||||
|
driverListToFill = new List<string>();
|
||||||
|
|
||||||
|
JsonElement main = root.GetProperty("Main");
|
||||||
|
|
||||||
|
int x = main.GetProperty("x").GetInt32();
|
||||||
|
int y = main.GetProperty("y").GetInt32();
|
||||||
|
int width = main.GetProperty("width").GetInt32();
|
||||||
|
int height = main.GetProperty("height").GetInt32();
|
||||||
|
|
||||||
|
mainZone = new Zone(fullImage, new Rectangle(x, y, width, height), "Main");
|
||||||
|
|
||||||
|
mainZone.ResetWindows();
|
||||||
|
mainZone.ResetZones();
|
||||||
|
|
||||||
|
JsonElement driverZones = main.GetProperty("DriverZones");
|
||||||
|
|
||||||
|
foreach (JsonElement driverZoneElement in driverZones.EnumerateArray())
|
||||||
|
{
|
||||||
|
string name = driverZoneElement.GetProperty("name").GetString();
|
||||||
|
int driverX = driverZoneElement.GetProperty("x").GetInt32() + mainZone.Bounds.X;
|
||||||
|
int driverY = driverZoneElement.GetProperty("y").GetInt32() + mainZone.Bounds.Y;
|
||||||
|
int driverWidth = driverZoneElement.GetProperty("width").GetInt32();
|
||||||
|
int driverHeight = driverZoneElement.GetProperty("height").GetInt32();
|
||||||
|
|
||||||
|
Zone driverZone = new Zone(fullImage, new Rectangle(driverX, driverY, driverWidth, driverHeight), "Driver");
|
||||||
|
|
||||||
|
JsonElement windowsElement = driverZoneElement.GetProperty("Windows");
|
||||||
|
|
||||||
|
//string[] windowNames = new string[] { "Position","GapToLeader","LapTime","DRS","Tyres","Name","Sector1","Sector2","Sector3" };
|
||||||
|
|
||||||
|
foreach (JsonElement windowElement in windowsElement.EnumerateArray())
|
||||||
|
{
|
||||||
|
//Position
|
||||||
|
JsonElement posEl = windowElement.GetProperty("Position");
|
||||||
|
DriverPositionWindow positionWindow = new DriverPositionWindow(driverZone.ZoneImage,
|
||||||
|
new Rectangle(
|
||||||
|
posEl.GetProperty("x").GetInt32(),
|
||||||
|
posEl.GetProperty("y").GetInt32(),
|
||||||
|
posEl.GetProperty("width").GetInt32(),
|
||||||
|
posEl.GetProperty("height").GetInt32()),
|
||||||
|
LoadOCR);
|
||||||
|
|
||||||
|
//GapToLeader
|
||||||
|
JsonElement gapEl = windowElement.GetProperty("GapToLeader");
|
||||||
|
DriverGapToLeaderWindow gapWindow = new DriverGapToLeaderWindow(driverZone.ZoneImage,
|
||||||
|
new Rectangle(
|
||||||
|
gapEl.GetProperty("x").GetInt32(),
|
||||||
|
gapEl.GetProperty("y").GetInt32(),
|
||||||
|
gapEl.GetProperty("width").GetInt32(),
|
||||||
|
gapEl.GetProperty("height").GetInt32()),
|
||||||
|
LoadOCR);
|
||||||
|
|
||||||
|
//LapTime
|
||||||
|
JsonElement lapEl = windowElement.GetProperty("LapTime");
|
||||||
|
DriverLapTimeWindow lapWindow = new DriverLapTimeWindow(driverZone.ZoneImage,
|
||||||
|
new Rectangle(
|
||||||
|
lapEl.GetProperty("x").GetInt32(),
|
||||||
|
lapEl.GetProperty("y").GetInt32(),
|
||||||
|
lapEl.GetProperty("width").GetInt32(),
|
||||||
|
lapEl.GetProperty("height").GetInt32()),
|
||||||
|
LoadOCR);
|
||||||
|
|
||||||
|
//DRS
|
||||||
|
JsonElement drsEl = windowElement.GetProperty("DRS");
|
||||||
|
DriverDrsWindow drsWindow = new DriverDrsWindow(driverZone.ZoneImage,
|
||||||
|
new Rectangle(
|
||||||
|
drsEl.GetProperty("x").GetInt32(),
|
||||||
|
drsEl.GetProperty("y").GetInt32(),
|
||||||
|
drsEl.GetProperty("width").GetInt32(),
|
||||||
|
drsEl.GetProperty("height").GetInt32()),
|
||||||
|
LoadOCR);
|
||||||
|
|
||||||
|
//Tyre
|
||||||
|
JsonElement tyresEl = windowElement.GetProperty("Tyres");
|
||||||
|
DriverTyresWindow tyreWindow = new DriverTyresWindow(driverZone.ZoneImage,
|
||||||
|
new Rectangle(
|
||||||
|
tyresEl.GetProperty("x").GetInt32(),
|
||||||
|
tyresEl.GetProperty("y").GetInt32(),
|
||||||
|
tyresEl.GetProperty("width").GetInt32(),
|
||||||
|
tyresEl.GetProperty("height").GetInt32()),
|
||||||
|
LoadOCR);
|
||||||
|
|
||||||
|
//Name
|
||||||
|
JsonElement nameEl = windowElement.GetProperty("Name");
|
||||||
|
DriverNameWindow nameWindow = new DriverNameWindow(driverZone.ZoneImage,
|
||||||
|
new Rectangle(
|
||||||
|
nameEl.GetProperty("x").GetInt32(),
|
||||||
|
nameEl.GetProperty("y").GetInt32(),
|
||||||
|
nameEl.GetProperty("width").GetInt32(),
|
||||||
|
nameEl.GetProperty("height").GetInt32()),
|
||||||
|
LoadOCR);
|
||||||
|
|
||||||
|
//Sector1
|
||||||
|
JsonElement sec1El = windowElement.GetProperty("Sector1");
|
||||||
|
DriverSectorWindow sec1Window = new DriverSectorWindow(driverZone.ZoneImage,
|
||||||
|
new Rectangle(
|
||||||
|
sec1El.GetProperty("x").GetInt32(),
|
||||||
|
sec1El.GetProperty("y").GetInt32(),
|
||||||
|
sec1El.GetProperty("width").GetInt32(),
|
||||||
|
sec1El.GetProperty("height").GetInt32()),
|
||||||
|
1, LoadOCR);
|
||||||
|
|
||||||
|
//Sector2
|
||||||
|
JsonElement sec2El = windowElement.GetProperty("Sector2");
|
||||||
|
DriverSectorWindow sec2Window = new DriverSectorWindow(driverZone.ZoneImage,
|
||||||
|
new Rectangle(
|
||||||
|
sec2El.GetProperty("x").GetInt32(),
|
||||||
|
sec2El.GetProperty("y").GetInt32(),
|
||||||
|
sec2El.GetProperty("width").GetInt32(),
|
||||||
|
sec2El.GetProperty("height").GetInt32()),
|
||||||
|
2, LoadOCR);
|
||||||
|
|
||||||
|
//Sector3
|
||||||
|
JsonElement sec3El = windowElement.GetProperty("Sector3");
|
||||||
|
DriverSectorWindow sec3Window = new DriverSectorWindow(driverZone.ZoneImage,
|
||||||
|
new Rectangle(
|
||||||
|
sec3El.GetProperty("x").GetInt32(),
|
||||||
|
sec3El.GetProperty("y").GetInt32(),
|
||||||
|
sec3El.GetProperty("width").GetInt32(),
|
||||||
|
sec3El.GetProperty("height").GetInt32()),
|
||||||
|
3, LoadOCR);
|
||||||
|
|
||||||
|
driverZone.AddWindow(positionWindow);
|
||||||
|
driverZone.AddWindow(gapWindow);
|
||||||
|
driverZone.AddWindow(lapWindow);
|
||||||
|
driverZone.AddWindow(drsWindow);
|
||||||
|
driverZone.AddWindow(tyreWindow);
|
||||||
|
driverZone.AddWindow(nameWindow);
|
||||||
|
driverZone.AddWindow(sec1Window);
|
||||||
|
driverZone.AddWindow(sec2Window);
|
||||||
|
driverZone.AddWindow(sec3Window);
|
||||||
|
}
|
||||||
|
mainZone.AddZone(driverZone);
|
||||||
|
}
|
||||||
|
|
||||||
|
JsonElement driversElement = main.GetProperty("Drivers");
|
||||||
|
foreach (JsonElement driverElement in driversElement.EnumerateArray())
|
||||||
|
{
|
||||||
|
string driverName = driverElement.GetString();
|
||||||
|
driverListToFill.Add(driverName);
|
||||||
|
Storage.AddDriver(driverName);
|
||||||
|
}
|
||||||
|
|
||||||
|
mainZones.Add(mainZone);
|
||||||
|
}
|
||||||
|
catch (IOException ex)
|
||||||
|
{
|
||||||
|
MessageBox.Show("Error reading JSON file: " + ex.Message);
|
||||||
|
}
|
||||||
|
catch (JsonException ex)
|
||||||
|
{
|
||||||
|
MessageBox.Show("Invalid JSON format: " + ex.Message);
|
||||||
|
}
|
||||||
|
int driverID = 0;
|
||||||
|
foreach (Zone z in mainZones[0].Zones)
|
||||||
|
{
|
||||||
|
driverID++;
|
||||||
|
z.ZoneImage.Save("LoadedDriver" + driverID + ".png");
|
||||||
|
}
|
||||||
|
return mainZones;
|
||||||
|
}
|
||||||
|
/// <summary>
|
||||||
|
/// Method that calls all the zones and windows to get the content they can find on the image to display them
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="idImage">The id of the image we are working with</param>
|
||||||
|
/// <returns>a string representation of all the returns</returns>
|
||||||
|
public List<DriverData> Decode(List<Zone> mainZones, List<string> drivers)
|
||||||
|
{
|
||||||
|
List<DriverData> mainResults = new List<DriverData>();
|
||||||
|
//Decode
|
||||||
|
for (int mainZoneId = 0; mainZoneId < mainZones.Count; mainZoneId++)
|
||||||
|
{
|
||||||
|
switch (mainZoneId)
|
||||||
|
{
|
||||||
|
case 0:
|
||||||
|
//object lockObject = new object();
|
||||||
|
//Main Zone
|
||||||
|
Parallel.For(0, mainZones[mainZoneId].Zones.Count, async i =>
|
||||||
|
//for (int i = 0; i < mainZones[mainZoneId].Zones.Count; i++)
|
||||||
|
{
|
||||||
|
DriverData data = mainZones[mainZoneId].Zones[i].Decode(new List<string>(drivers));
|
||||||
|
mainResults.Add(data);
|
||||||
|
DriverDataLogs[i].Add(data);
|
||||||
|
|
||||||
|
if (data.Position != -1 && DriverDataLogs[i].Count > 1)
|
||||||
|
{
|
||||||
|
//Tries to fix the tyres
|
||||||
|
if (data.CurrentTyre.NumberOfLaps > DriverDataLogs[i][DriverDataLogs[i].Count - 2].CurrentTyre.NumberOfLaps + 3)
|
||||||
|
data.CurrentTyre.NumberOfLaps = DriverDataLogs[i][DriverDataLogs[i].Count - 2].CurrentTyre.NumberOfLaps + 1;
|
||||||
|
|
||||||
|
//Checking if its a new lap
|
||||||
|
//If the third sector is filled but it was'nt the last time, then it means that a new Lap has been started
|
||||||
|
//Lap detection can be f***ed if the OCR takes so much time that an entire sector can be raced without us knowing.
|
||||||
|
if (
|
||||||
|
DriverDataLogs[i][DriverDataLogs[i].Count - 1].Sector3 != 0
|
||||||
|
&& DriverDataLogs[i][DriverDataLogs[i].Count - 2].Sector3 == 0
|
||||||
|
&& DriverDataLogs[i][DriverDataLogs[i].Count - 2].Position != -1
|
||||||
|
&& DriverDataLogs[i][DriverDataLogs[i].Count - 1].Position != -1)
|
||||||
|
{
|
||||||
|
DriverData stats = new DriverData();
|
||||||
|
stats = DriverDataLogs[i][DriverDataLogs[i].Count - 1];
|
||||||
|
DriverLaps[i]++;
|
||||||
|
Storage.AddDriverStat(stats, DriverLaps[i]);
|
||||||
|
}
|
||||||
|
//Checking if its a pitstop
|
||||||
|
//Forget this the best way to know if a tyre has been changed is if the number of laps is zero
|
||||||
|
if (data.CurrentTyre.Coumpound != Tyre.Type.Undefined && data.CurrentTyre.NumberOfLaps == 0 && DriverDataLogs[i][DriverDataLogs[i].Count - 2].CurrentTyre.NumberOfLaps != 0)
|
||||||
|
{
|
||||||
|
Storage.AddPitstop(data.Name, DriverLaps[i] - 1, data.CurrentTyre.Coumpound.ToString());
|
||||||
|
//Driver laps -1 because it would take AT LEAST one lap for this program to detect a pitstop
|
||||||
|
}
|
||||||
|
}
|
||||||
|
DriverDataLogs[i].Add(data);
|
||||||
|
});
|
||||||
|
break;
|
||||||
|
//Next there could be a Title Zone and TrackInfoZone
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//mainResults = mainResults.OrderBy(driver => driver.Position >= 0).ThenBy(driver => driver.Position).ToList();
|
||||||
|
mainResults = mainResults.OrderBy(driver => driver.Position).ToList();
|
||||||
|
return mainResults;
|
||||||
|
}
|
||||||
|
/// <summary>
|
||||||
|
/// Changes the image in all of the zones wich then will do the same for theyre own subzones and windows
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="Image">The new Image from the F1TV data channel</param>
|
||||||
|
public void ChangeImage(Bitmap Image)
|
||||||
|
{
|
||||||
|
foreach (Zone z in MainZones)
|
||||||
|
{
|
||||||
|
z.Image = Image;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/// <summary>
|
||||||
|
/// Method that can be used to convert an amount of miliseconds into a more readable human form
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="amountOfMs">The given amount of miliseconds ton convert</param>
|
||||||
|
/// <returns>A human readable string that represents the ms</returns>
|
||||||
|
public static string ConvertMsToTime(int amountOfMs)
|
||||||
|
{
|
||||||
|
//Convert.ToInt32 would round upand I dont want that
|
||||||
|
int minuts = (int)((float)amountOfMs / (1000f * 60f));
|
||||||
|
int seconds = (int)((amountOfMs - (minuts * 60f * 1000f)) / 1000);
|
||||||
|
int ms = amountOfMs - ((minuts * 60 * 1000) + (seconds * 1000));
|
||||||
|
|
||||||
|
return minuts + ":" + seconds.ToString("00") + ":" + ms.ToString("000");
|
||||||
|
}
|
||||||
|
/// <summary>
|
||||||
|
/// Old method that can draw on an image where the windows and zones are created. mostly used for debugging
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="idImage">the #id of the image we are working with</param>
|
||||||
|
/// <returns>the drawed bitmap</returns>
|
||||||
|
public Bitmap Draw(Bitmap image, List<Zone> mainZones)
|
||||||
|
{
|
||||||
|
|
||||||
|
Graphics g = Graphics.FromImage(image);
|
||||||
|
|
||||||
|
foreach (Zone z in mainZones)
|
||||||
|
{
|
||||||
|
int count = 0;
|
||||||
|
foreach (Zone zz in z.Zones)
|
||||||
|
{
|
||||||
|
g.DrawRectangle(Pens.Red, z.Bounds);
|
||||||
|
foreach (Window w in zz.Windows)
|
||||||
|
{
|
||||||
|
g.DrawRectangle(Pens.Blue, new Rectangle(z.Bounds.X + zz.Bounds.X, z.Bounds.Y + zz.Bounds.Y, zz.Bounds.Width, zz.Bounds.Height));
|
||||||
|
}
|
||||||
|
|
||||||
|
count++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return image;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Generated
+494
@@ -0,0 +1,494 @@
|
|||||||
|
namespace TrackTrends
|
||||||
|
{
|
||||||
|
partial class Settings
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Required designer variable.
|
||||||
|
/// </summary>
|
||||||
|
private System.ComponentModel.IContainer components = null;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Clean up any resources being used.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
|
||||||
|
protected override void Dispose(bool disposing)
|
||||||
|
{
|
||||||
|
if (disposing && (components != null))
|
||||||
|
{
|
||||||
|
components.Dispose();
|
||||||
|
}
|
||||||
|
base.Dispose(disposing);
|
||||||
|
}
|
||||||
|
|
||||||
|
#region Windows Form Designer generated code
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Required method for Designer support - do not modify
|
||||||
|
/// the contents of this method with the code editor.
|
||||||
|
/// </summary>
|
||||||
|
private void InitializeComponent()
|
||||||
|
{
|
||||||
|
this.components = new System.ComponentModel.Container();
|
||||||
|
this.label1 = new System.Windows.Forms.Label();
|
||||||
|
this.label2 = new System.Windows.Forms.Label();
|
||||||
|
this.gpbxRaceSettings = new System.Windows.Forms.GroupBox();
|
||||||
|
this.tbxGpUrl = new System.Windows.Forms.TextBox();
|
||||||
|
this.gpbxDriverList = new System.Windows.Forms.GroupBox();
|
||||||
|
this.lsbDrivers = new System.Windows.Forms.ListBox();
|
||||||
|
this.btnRemoveDriver = new System.Windows.Forms.Button();
|
||||||
|
this.btnAddDriver = new System.Windows.Forms.Button();
|
||||||
|
this.tbxDriverName = new System.Windows.Forms.TextBox();
|
||||||
|
this.gpbxPreview = new System.Windows.Forms.GroupBox();
|
||||||
|
this.lblWindowsRemaining = new System.Windows.Forms.Label();
|
||||||
|
this.btnResetDriver = new System.Windows.Forms.Button();
|
||||||
|
this.btnRefresh = new System.Windows.Forms.Button();
|
||||||
|
this.lblWindowPointsRemaining = new System.Windows.Forms.Label();
|
||||||
|
this.lblZonePointsRemaning = new System.Windows.Forms.Label();
|
||||||
|
this.btnCreateWindow = new System.Windows.Forms.Button();
|
||||||
|
this.pbxPreview = new System.Windows.Forms.PictureBox();
|
||||||
|
this.btnCreatZone = new System.Windows.Forms.Button();
|
||||||
|
this.gpbxWindowPreview = new System.Windows.Forms.GroupBox();
|
||||||
|
this.pbxWindowPreview = new System.Windows.Forms.PictureBox();
|
||||||
|
this.btnLoadPreset = new System.Windows.Forms.Button();
|
||||||
|
this.lsbPresets = new System.Windows.Forms.ListBox();
|
||||||
|
this.tbxPresetName = new System.Windows.Forms.TextBox();
|
||||||
|
this.btnSavePreset = new System.Windows.Forms.Button();
|
||||||
|
this.gpbxPresets = new System.Windows.Forms.GroupBox();
|
||||||
|
this.btnDeletePreset = new System.Windows.Forms.Button();
|
||||||
|
this.tip1 = new System.Windows.Forms.ToolTip(this.components);
|
||||||
|
this.gpbxRaceSettings.SuspendLayout();
|
||||||
|
this.gpbxDriverList.SuspendLayout();
|
||||||
|
this.gpbxPreview.SuspendLayout();
|
||||||
|
((System.ComponentModel.ISupportInitialize)(this.pbxPreview)).BeginInit();
|
||||||
|
this.gpbxWindowPreview.SuspendLayout();
|
||||||
|
((System.ComponentModel.ISupportInitialize)(this.pbxWindowPreview)).BeginInit();
|
||||||
|
this.gpbxPresets.SuspendLayout();
|
||||||
|
this.SuspendLayout();
|
||||||
|
//
|
||||||
|
// label1
|
||||||
|
//
|
||||||
|
this.label1.AutoSize = true;
|
||||||
|
this.label1.Font = new System.Drawing.Font("Microsoft YaHei UI", 19.8F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
|
||||||
|
this.label1.ForeColor = System.Drawing.Color.White;
|
||||||
|
this.label1.Location = new System.Drawing.Point(12, 14);
|
||||||
|
this.label1.Name = "label1";
|
||||||
|
this.label1.Size = new System.Drawing.Size(309, 43);
|
||||||
|
this.label1.TabIndex = 0;
|
||||||
|
this.label1.Text = "Configuration tool";
|
||||||
|
//
|
||||||
|
// label2
|
||||||
|
//
|
||||||
|
this.label2.AutoSize = true;
|
||||||
|
this.label2.Font = new System.Drawing.Font("Microsoft YaHei UI", 10.2F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
|
||||||
|
this.label2.ForeColor = System.Drawing.Color.White;
|
||||||
|
this.label2.Location = new System.Drawing.Point(3, 25);
|
||||||
|
this.label2.Name = "label2";
|
||||||
|
this.label2.Size = new System.Drawing.Size(132, 23);
|
||||||
|
this.label2.TabIndex = 1;
|
||||||
|
this.label2.Text = "Grand Prix URL";
|
||||||
|
//
|
||||||
|
// gpbxRaceSettings
|
||||||
|
//
|
||||||
|
this.gpbxRaceSettings.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));
|
||||||
|
this.gpbxRaceSettings.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(79)))), ((int)(((byte)(79)))), ((int)(((byte)(79)))));
|
||||||
|
this.gpbxRaceSettings.Controls.Add(this.tbxGpUrl);
|
||||||
|
this.gpbxRaceSettings.Controls.Add(this.label2);
|
||||||
|
this.gpbxRaceSettings.Font = new System.Drawing.Font("Microsoft YaHei UI", 10.2F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
|
||||||
|
this.gpbxRaceSettings.ForeColor = System.Drawing.Color.White;
|
||||||
|
this.gpbxRaceSettings.Location = new System.Drawing.Point(733, 9);
|
||||||
|
this.gpbxRaceSettings.Name = "gpbxRaceSettings";
|
||||||
|
this.gpbxRaceSettings.Padding = new System.Windows.Forms.Padding(0);
|
||||||
|
this.gpbxRaceSettings.Size = new System.Drawing.Size(521, 58);
|
||||||
|
this.gpbxRaceSettings.TabIndex = 2;
|
||||||
|
this.gpbxRaceSettings.TabStop = false;
|
||||||
|
this.gpbxRaceSettings.Text = "RaceSettings";
|
||||||
|
this.gpbxRaceSettings.Paint += new System.Windows.Forms.PaintEventHandler(this.removeBorders);
|
||||||
|
//
|
||||||
|
// tbxGpUrl
|
||||||
|
//
|
||||||
|
this.tbxGpUrl.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(51)))), ((int)(((byte)(51)))), ((int)(((byte)(51)))));
|
||||||
|
this.tbxGpUrl.BorderStyle = System.Windows.Forms.BorderStyle.None;
|
||||||
|
this.tbxGpUrl.Font = new System.Drawing.Font("Microsoft YaHei UI", 10.2F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
|
||||||
|
this.tbxGpUrl.ForeColor = System.Drawing.Color.White;
|
||||||
|
this.tbxGpUrl.Location = new System.Drawing.Point(141, 25);
|
||||||
|
this.tbxGpUrl.Name = "tbxGpUrl";
|
||||||
|
this.tbxGpUrl.Size = new System.Drawing.Size(367, 22);
|
||||||
|
this.tbxGpUrl.TabIndex = 4;
|
||||||
|
this.tbxGpUrl.TextChanged += new System.EventHandler(this.tbxGpUrl_TextChanged);
|
||||||
|
//
|
||||||
|
// gpbxDriverList
|
||||||
|
//
|
||||||
|
this.gpbxDriverList.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));
|
||||||
|
this.gpbxDriverList.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(79)))), ((int)(((byte)(79)))), ((int)(((byte)(79)))));
|
||||||
|
this.gpbxDriverList.Controls.Add(this.lsbDrivers);
|
||||||
|
this.gpbxDriverList.Controls.Add(this.btnRemoveDriver);
|
||||||
|
this.gpbxDriverList.Controls.Add(this.btnAddDriver);
|
||||||
|
this.gpbxDriverList.Controls.Add(this.tbxDriverName);
|
||||||
|
this.gpbxDriverList.FlatStyle = System.Windows.Forms.FlatStyle.Popup;
|
||||||
|
this.gpbxDriverList.Font = new System.Drawing.Font("Microsoft YaHei UI", 10F);
|
||||||
|
this.gpbxDriverList.ForeColor = System.Drawing.Color.White;
|
||||||
|
this.gpbxDriverList.Location = new System.Drawing.Point(995, 73);
|
||||||
|
this.gpbxDriverList.Name = "gpbxDriverList";
|
||||||
|
this.gpbxDriverList.Padding = new System.Windows.Forms.Padding(0);
|
||||||
|
this.gpbxDriverList.Size = new System.Drawing.Size(259, 269);
|
||||||
|
this.gpbxDriverList.TabIndex = 3;
|
||||||
|
this.gpbxDriverList.TabStop = false;
|
||||||
|
this.gpbxDriverList.Text = "DriverList";
|
||||||
|
this.gpbxDriverList.Paint += new System.Windows.Forms.PaintEventHandler(this.removeBorders);
|
||||||
|
//
|
||||||
|
// lsbDrivers
|
||||||
|
//
|
||||||
|
this.lsbDrivers.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(51)))), ((int)(((byte)(51)))), ((int)(((byte)(51)))));
|
||||||
|
this.lsbDrivers.BorderStyle = System.Windows.Forms.BorderStyle.None;
|
||||||
|
this.lsbDrivers.Font = new System.Drawing.Font("Microsoft YaHei UI", 10F);
|
||||||
|
this.lsbDrivers.ForeColor = System.Drawing.Color.FromArgb(((int)(((byte)(252)))), ((int)(((byte)(252)))), ((int)(((byte)(252)))));
|
||||||
|
this.lsbDrivers.FormattingEnabled = true;
|
||||||
|
this.lsbDrivers.ItemHeight = 23;
|
||||||
|
this.lsbDrivers.Location = new System.Drawing.Point(10, 23);
|
||||||
|
this.lsbDrivers.Name = "lsbDrivers";
|
||||||
|
this.lsbDrivers.Size = new System.Drawing.Size(243, 138);
|
||||||
|
this.lsbDrivers.TabIndex = 10;
|
||||||
|
//
|
||||||
|
// btnRemoveDriver
|
||||||
|
//
|
||||||
|
this.btnRemoveDriver.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(51)))), ((int)(((byte)(51)))), ((int)(((byte)(51)))));
|
||||||
|
this.btnRemoveDriver.FlatStyle = System.Windows.Forms.FlatStyle.Popup;
|
||||||
|
this.btnRemoveDriver.Font = new System.Drawing.Font("Microsoft YaHei UI", 10.2F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
|
||||||
|
this.btnRemoveDriver.ForeColor = System.Drawing.Color.White;
|
||||||
|
this.btnRemoveDriver.Location = new System.Drawing.Point(132, 167);
|
||||||
|
this.btnRemoveDriver.Name = "btnRemoveDriver";
|
||||||
|
this.btnRemoveDriver.Size = new System.Drawing.Size(121, 62);
|
||||||
|
this.btnRemoveDriver.TabIndex = 9;
|
||||||
|
this.btnRemoveDriver.Text = "Remove";
|
||||||
|
this.btnRemoveDriver.UseVisualStyleBackColor = false;
|
||||||
|
this.btnRemoveDriver.Click += new System.EventHandler(this.btnRemoveDriver_Click);
|
||||||
|
//
|
||||||
|
// btnAddDriver
|
||||||
|
//
|
||||||
|
this.btnAddDriver.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(51)))), ((int)(((byte)(51)))), ((int)(((byte)(51)))));
|
||||||
|
this.btnAddDriver.FlatStyle = System.Windows.Forms.FlatStyle.Popup;
|
||||||
|
this.btnAddDriver.Font = new System.Drawing.Font("Microsoft YaHei UI", 10.2F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
|
||||||
|
this.btnAddDriver.ForeColor = System.Drawing.Color.White;
|
||||||
|
this.btnAddDriver.Location = new System.Drawing.Point(10, 167);
|
||||||
|
this.btnAddDriver.Name = "btnAddDriver";
|
||||||
|
this.btnAddDriver.Size = new System.Drawing.Size(116, 62);
|
||||||
|
this.btnAddDriver.TabIndex = 8;
|
||||||
|
this.btnAddDriver.Text = "Add";
|
||||||
|
this.btnAddDriver.UseVisualStyleBackColor = false;
|
||||||
|
this.btnAddDriver.Click += new System.EventHandler(this.btnAddDriver_Click);
|
||||||
|
//
|
||||||
|
// tbxDriverName
|
||||||
|
//
|
||||||
|
this.tbxDriverName.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(51)))), ((int)(((byte)(51)))), ((int)(((byte)(51)))));
|
||||||
|
this.tbxDriverName.BorderStyle = System.Windows.Forms.BorderStyle.None;
|
||||||
|
this.tbxDriverName.Font = new System.Drawing.Font("Microsoft YaHei UI", 11F);
|
||||||
|
this.tbxDriverName.ForeColor = System.Drawing.Color.FromArgb(((int)(((byte)(252)))), ((int)(((byte)(252)))), ((int)(((byte)(252)))));
|
||||||
|
this.tbxDriverName.Location = new System.Drawing.Point(10, 235);
|
||||||
|
this.tbxDriverName.Name = "tbxDriverName";
|
||||||
|
this.tbxDriverName.Size = new System.Drawing.Size(243, 24);
|
||||||
|
this.tbxDriverName.TabIndex = 7;
|
||||||
|
//
|
||||||
|
// gpbxPreview
|
||||||
|
//
|
||||||
|
this.gpbxPreview.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(79)))), ((int)(((byte)(79)))), ((int)(((byte)(79)))));
|
||||||
|
this.gpbxPreview.Controls.Add(this.lblWindowsRemaining);
|
||||||
|
this.gpbxPreview.Controls.Add(this.btnResetDriver);
|
||||||
|
this.gpbxPreview.Controls.Add(this.btnRefresh);
|
||||||
|
this.gpbxPreview.Controls.Add(this.lblWindowPointsRemaining);
|
||||||
|
this.gpbxPreview.Controls.Add(this.lblZonePointsRemaning);
|
||||||
|
this.gpbxPreview.Controls.Add(this.btnCreateWindow);
|
||||||
|
this.gpbxPreview.Controls.Add(this.pbxPreview);
|
||||||
|
this.gpbxPreview.Controls.Add(this.btnCreatZone);
|
||||||
|
this.gpbxPreview.FlatStyle = System.Windows.Forms.FlatStyle.Flat;
|
||||||
|
this.gpbxPreview.Font = new System.Drawing.Font("Microsoft YaHei UI", 10F);
|
||||||
|
this.gpbxPreview.ForeColor = System.Drawing.Color.White;
|
||||||
|
this.gpbxPreview.Location = new System.Drawing.Point(18, 73);
|
||||||
|
this.gpbxPreview.Name = "gpbxPreview";
|
||||||
|
this.gpbxPreview.Padding = new System.Windows.Forms.Padding(0);
|
||||||
|
this.gpbxPreview.Size = new System.Drawing.Size(968, 608);
|
||||||
|
this.gpbxPreview.TabIndex = 4;
|
||||||
|
this.gpbxPreview.TabStop = false;
|
||||||
|
this.gpbxPreview.Text = "Preview";
|
||||||
|
this.gpbxPreview.Paint += new System.Windows.Forms.PaintEventHandler(this.removeBorders);
|
||||||
|
//
|
||||||
|
// lblWindowsRemaining
|
||||||
|
//
|
||||||
|
this.lblWindowsRemaining.AutoSize = true;
|
||||||
|
this.lblWindowsRemaining.BackColor = System.Drawing.Color.Transparent;
|
||||||
|
this.lblWindowsRemaining.ForeColor = System.Drawing.Color.White;
|
||||||
|
this.lblWindowsRemaining.Location = new System.Drawing.Point(215, 82);
|
||||||
|
this.lblWindowsRemaining.Name = "lblWindowsRemaining";
|
||||||
|
this.lblWindowsRemaining.Size = new System.Drawing.Size(183, 23);
|
||||||
|
this.lblWindowsRemaining.TabIndex = 6;
|
||||||
|
this.lblWindowsRemaining.Text = "7 windows remaining";
|
||||||
|
//
|
||||||
|
// btnResetDriver
|
||||||
|
//
|
||||||
|
this.btnResetDriver.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));
|
||||||
|
this.btnResetDriver.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(51)))), ((int)(((byte)(51)))), ((int)(((byte)(51)))));
|
||||||
|
this.btnResetDriver.Enabled = false;
|
||||||
|
this.btnResetDriver.FlatStyle = System.Windows.Forms.FlatStyle.Popup;
|
||||||
|
this.btnResetDriver.ForeColor = System.Drawing.Color.White;
|
||||||
|
this.btnResetDriver.Location = new System.Drawing.Point(748, 20);
|
||||||
|
this.btnResetDriver.Name = "btnResetDriver";
|
||||||
|
this.btnResetDriver.Size = new System.Drawing.Size(211, 33);
|
||||||
|
this.btnResetDriver.TabIndex = 2;
|
||||||
|
this.btnResetDriver.Text = "Reset the emulator";
|
||||||
|
this.btnResetDriver.UseVisualStyleBackColor = false;
|
||||||
|
this.btnResetDriver.Click += new System.EventHandler(this.btnResetDriver_Click);
|
||||||
|
//
|
||||||
|
// btnRefresh
|
||||||
|
//
|
||||||
|
this.btnRefresh.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));
|
||||||
|
this.btnRefresh.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(51)))), ((int)(((byte)(51)))), ((int)(((byte)(51)))));
|
||||||
|
this.btnRefresh.FlatStyle = System.Windows.Forms.FlatStyle.Popup;
|
||||||
|
this.btnRefresh.ForeColor = System.Drawing.Color.White;
|
||||||
|
this.btnRefresh.Location = new System.Drawing.Point(549, 20);
|
||||||
|
this.btnRefresh.Name = "btnRefresh";
|
||||||
|
this.btnRefresh.Size = new System.Drawing.Size(193, 33);
|
||||||
|
this.btnRefresh.TabIndex = 1;
|
||||||
|
this.btnRefresh.Text = "Start the browser";
|
||||||
|
this.btnRefresh.UseVisualStyleBackColor = false;
|
||||||
|
this.btnRefresh.Click += new System.EventHandler(this.btnRefresh_Click);
|
||||||
|
//
|
||||||
|
// lblWindowPointsRemaining
|
||||||
|
//
|
||||||
|
this.lblWindowPointsRemaining.AutoSize = true;
|
||||||
|
this.lblWindowPointsRemaining.ForeColor = System.Drawing.Color.White;
|
||||||
|
this.lblWindowPointsRemaining.Location = new System.Drawing.Point(215, 59);
|
||||||
|
this.lblWindowPointsRemaining.Name = "lblWindowPointsRemaining";
|
||||||
|
this.lblWindowPointsRemaining.Size = new System.Drawing.Size(163, 23);
|
||||||
|
this.lblWindowPointsRemaining.TabIndex = 4;
|
||||||
|
this.lblWindowPointsRemaining.Text = "0 points remaining";
|
||||||
|
//
|
||||||
|
// lblZonePointsRemaning
|
||||||
|
//
|
||||||
|
this.lblZonePointsRemaning.AutoSize = true;
|
||||||
|
this.lblZonePointsRemaning.ForeColor = System.Drawing.Color.White;
|
||||||
|
this.lblZonePointsRemaning.Location = new System.Drawing.Point(19, 59);
|
||||||
|
this.lblZonePointsRemaning.Name = "lblZonePointsRemaning";
|
||||||
|
this.lblZonePointsRemaning.Size = new System.Drawing.Size(163, 23);
|
||||||
|
this.lblZonePointsRemaning.TabIndex = 5;
|
||||||
|
this.lblZonePointsRemaning.Text = "0 points remaining";
|
||||||
|
//
|
||||||
|
// btnCreateWindow
|
||||||
|
//
|
||||||
|
this.btnCreateWindow.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(51)))), ((int)(((byte)(51)))), ((int)(((byte)(51)))));
|
||||||
|
this.btnCreateWindow.Enabled = false;
|
||||||
|
this.btnCreateWindow.FlatStyle = System.Windows.Forms.FlatStyle.Popup;
|
||||||
|
this.btnCreateWindow.ForeColor = System.Drawing.Color.White;
|
||||||
|
this.btnCreateWindow.Location = new System.Drawing.Point(213, 23);
|
||||||
|
this.btnCreateWindow.Name = "btnCreateWindow";
|
||||||
|
this.btnCreateWindow.Size = new System.Drawing.Size(201, 33);
|
||||||
|
this.btnCreateWindow.TabIndex = 2;
|
||||||
|
this.btnCreateWindow.Text = "Create the windows";
|
||||||
|
this.btnCreateWindow.UseVisualStyleBackColor = false;
|
||||||
|
this.btnCreateWindow.Click += new System.EventHandler(this.btnCreateWindow_Click);
|
||||||
|
//
|
||||||
|
// pbxPreview
|
||||||
|
//
|
||||||
|
this.pbxPreview.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(51)))), ((int)(((byte)(51)))), ((int)(((byte)(51)))));
|
||||||
|
this.pbxPreview.Location = new System.Drawing.Point(10, 62);
|
||||||
|
this.pbxPreview.Name = "pbxPreview";
|
||||||
|
this.pbxPreview.Size = new System.Drawing.Size(950, 540);
|
||||||
|
this.pbxPreview.SizeMode = System.Windows.Forms.PictureBoxSizeMode.StretchImage;
|
||||||
|
this.pbxPreview.TabIndex = 0;
|
||||||
|
this.pbxPreview.TabStop = false;
|
||||||
|
this.pbxPreview.Click += new System.EventHandler(this.pbxMain_Click);
|
||||||
|
this.pbxPreview.MouseClick += new System.Windows.Forms.MouseEventHandler(this.pbxMain_MouseClick);
|
||||||
|
//
|
||||||
|
// btnCreatZone
|
||||||
|
//
|
||||||
|
this.btnCreatZone.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(51)))), ((int)(((byte)(51)))), ((int)(((byte)(51)))));
|
||||||
|
this.btnCreatZone.Enabled = false;
|
||||||
|
this.btnCreatZone.FlatStyle = System.Windows.Forms.FlatStyle.Popup;
|
||||||
|
this.btnCreatZone.ForeColor = System.Drawing.Color.White;
|
||||||
|
this.btnCreatZone.Location = new System.Drawing.Point(6, 23);
|
||||||
|
this.btnCreatZone.Name = "btnCreatZone";
|
||||||
|
this.btnCreatZone.Size = new System.Drawing.Size(201, 33);
|
||||||
|
this.btnCreatZone.TabIndex = 1;
|
||||||
|
this.btnCreatZone.Text = "Create the main zone";
|
||||||
|
this.btnCreatZone.UseVisualStyleBackColor = false;
|
||||||
|
this.btnCreatZone.Click += new System.EventHandler(this.btnCreatZone_Click);
|
||||||
|
//
|
||||||
|
// gpbxWindowPreview
|
||||||
|
//
|
||||||
|
this.gpbxWindowPreview.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)));
|
||||||
|
this.gpbxWindowPreview.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(79)))), ((int)(((byte)(79)))), ((int)(((byte)(79)))));
|
||||||
|
this.gpbxWindowPreview.Controls.Add(this.pbxWindowPreview);
|
||||||
|
this.gpbxWindowPreview.FlatStyle = System.Windows.Forms.FlatStyle.Popup;
|
||||||
|
this.gpbxWindowPreview.Font = new System.Drawing.Font("Microsoft YaHei UI", 10F);
|
||||||
|
this.gpbxWindowPreview.ForeColor = System.Drawing.Color.White;
|
||||||
|
this.gpbxWindowPreview.Location = new System.Drawing.Point(18, 688);
|
||||||
|
this.gpbxWindowPreview.Name = "gpbxWindowPreview";
|
||||||
|
this.gpbxWindowPreview.Padding = new System.Windows.Forms.Padding(0);
|
||||||
|
this.gpbxWindowPreview.Size = new System.Drawing.Size(1237, 88);
|
||||||
|
this.gpbxWindowPreview.TabIndex = 5;
|
||||||
|
this.gpbxWindowPreview.TabStop = false;
|
||||||
|
this.gpbxWindowPreview.Text = "DriverZonePreview";
|
||||||
|
this.gpbxWindowPreview.Paint += new System.Windows.Forms.PaintEventHandler(this.removeBorders);
|
||||||
|
//
|
||||||
|
// pbxWindowPreview
|
||||||
|
//
|
||||||
|
this.pbxWindowPreview.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(51)))), ((int)(((byte)(51)))), ((int)(((byte)(51)))));
|
||||||
|
this.pbxWindowPreview.Location = new System.Drawing.Point(6, 30);
|
||||||
|
this.pbxWindowPreview.Name = "pbxWindowPreview";
|
||||||
|
this.pbxWindowPreview.Size = new System.Drawing.Size(1225, 50);
|
||||||
|
this.pbxWindowPreview.SizeMode = System.Windows.Forms.PictureBoxSizeMode.StretchImage;
|
||||||
|
this.pbxWindowPreview.TabIndex = 0;
|
||||||
|
this.pbxWindowPreview.TabStop = false;
|
||||||
|
this.pbxWindowPreview.Click += new System.EventHandler(this.pbxDriverZone_Click);
|
||||||
|
this.pbxWindowPreview.MouseClick += new System.Windows.Forms.MouseEventHandler(this.pbxDriverZone_MouseClick);
|
||||||
|
//
|
||||||
|
// btnLoadPreset
|
||||||
|
//
|
||||||
|
this.btnLoadPreset.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(51)))), ((int)(((byte)(51)))), ((int)(((byte)(51)))));
|
||||||
|
this.btnLoadPreset.FlatStyle = System.Windows.Forms.FlatStyle.Popup;
|
||||||
|
this.btnLoadPreset.ForeColor = System.Drawing.Color.White;
|
||||||
|
this.btnLoadPreset.Location = new System.Drawing.Point(10, 213);
|
||||||
|
this.btnLoadPreset.Name = "btnLoadPreset";
|
||||||
|
this.btnLoadPreset.Size = new System.Drawing.Size(243, 40);
|
||||||
|
this.btnLoadPreset.TabIndex = 10;
|
||||||
|
this.btnLoadPreset.Text = "Load the preset";
|
||||||
|
this.btnLoadPreset.UseVisualStyleBackColor = false;
|
||||||
|
this.btnLoadPreset.Click += new System.EventHandler(this.btnLoadPreset_Click);
|
||||||
|
//
|
||||||
|
// lsbPresets
|
||||||
|
//
|
||||||
|
this.lsbPresets.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(51)))), ((int)(((byte)(51)))), ((int)(((byte)(51)))));
|
||||||
|
this.lsbPresets.BorderStyle = System.Windows.Forms.BorderStyle.None;
|
||||||
|
this.lsbPresets.Font = new System.Drawing.Font("Microsoft YaHei UI", 10F);
|
||||||
|
this.lsbPresets.ForeColor = System.Drawing.Color.FromArgb(((int)(((byte)(252)))), ((int)(((byte)(252)))), ((int)(((byte)(252)))));
|
||||||
|
this.lsbPresets.FormattingEnabled = true;
|
||||||
|
this.lsbPresets.ItemHeight = 23;
|
||||||
|
this.lsbPresets.Location = new System.Drawing.Point(10, 23);
|
||||||
|
this.lsbPresets.Name = "lsbPresets";
|
||||||
|
this.lsbPresets.Size = new System.Drawing.Size(243, 138);
|
||||||
|
this.lsbPresets.TabIndex = 8;
|
||||||
|
this.lsbPresets.SelectedIndexChanged += new System.EventHandler(this.lsbPresets_SelectedIndexChanged);
|
||||||
|
//
|
||||||
|
// tbxPresetName
|
||||||
|
//
|
||||||
|
this.tbxPresetName.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(51)))), ((int)(((byte)(51)))), ((int)(((byte)(51)))));
|
||||||
|
this.tbxPresetName.BorderStyle = System.Windows.Forms.BorderStyle.None;
|
||||||
|
this.tbxPresetName.Font = new System.Drawing.Font("Microsoft YaHei UI", 11F);
|
||||||
|
this.tbxPresetName.ForeColor = System.Drawing.Color.White;
|
||||||
|
this.tbxPresetName.Location = new System.Drawing.Point(10, 303);
|
||||||
|
this.tbxPresetName.Name = "tbxPresetName";
|
||||||
|
this.tbxPresetName.Size = new System.Drawing.Size(243, 24);
|
||||||
|
this.tbxPresetName.TabIndex = 7;
|
||||||
|
//
|
||||||
|
// btnSavePreset
|
||||||
|
//
|
||||||
|
this.btnSavePreset.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(51)))), ((int)(((byte)(51)))), ((int)(((byte)(51)))));
|
||||||
|
this.btnSavePreset.FlatStyle = System.Windows.Forms.FlatStyle.Popup;
|
||||||
|
this.btnSavePreset.ForeColor = System.Drawing.Color.White;
|
||||||
|
this.btnSavePreset.Location = new System.Drawing.Point(10, 259);
|
||||||
|
this.btnSavePreset.Name = "btnSavePreset";
|
||||||
|
this.btnSavePreset.Size = new System.Drawing.Size(243, 40);
|
||||||
|
this.btnSavePreset.TabIndex = 7;
|
||||||
|
this.btnSavePreset.Text = "Save current preset";
|
||||||
|
this.btnSavePreset.UseVisualStyleBackColor = false;
|
||||||
|
this.btnSavePreset.Click += new System.EventHandler(this.btnSavePreset_Click);
|
||||||
|
//
|
||||||
|
// gpbxPresets
|
||||||
|
//
|
||||||
|
this.gpbxPresets.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));
|
||||||
|
this.gpbxPresets.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(79)))), ((int)(((byte)(79)))), ((int)(((byte)(79)))));
|
||||||
|
this.gpbxPresets.Controls.Add(this.btnSavePreset);
|
||||||
|
this.gpbxPresets.Controls.Add(this.btnDeletePreset);
|
||||||
|
this.gpbxPresets.Controls.Add(this.tbxPresetName);
|
||||||
|
this.gpbxPresets.Controls.Add(this.btnLoadPreset);
|
||||||
|
this.gpbxPresets.Controls.Add(this.lsbPresets);
|
||||||
|
this.gpbxPresets.FlatStyle = System.Windows.Forms.FlatStyle.Popup;
|
||||||
|
this.gpbxPresets.Font = new System.Drawing.Font("Microsoft YaHei UI", 10F);
|
||||||
|
this.gpbxPresets.ForeColor = System.Drawing.Color.White;
|
||||||
|
this.gpbxPresets.Location = new System.Drawing.Point(995, 348);
|
||||||
|
this.gpbxPresets.Name = "gpbxPresets";
|
||||||
|
this.gpbxPresets.Padding = new System.Windows.Forms.Padding(0);
|
||||||
|
this.gpbxPresets.Size = new System.Drawing.Size(259, 333);
|
||||||
|
this.gpbxPresets.TabIndex = 6;
|
||||||
|
this.gpbxPresets.TabStop = false;
|
||||||
|
this.gpbxPresets.Text = "Presets";
|
||||||
|
this.gpbxPresets.Paint += new System.Windows.Forms.PaintEventHandler(this.removeBorders);
|
||||||
|
//
|
||||||
|
// btnDeletePreset
|
||||||
|
//
|
||||||
|
this.btnDeletePreset.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(51)))), ((int)(((byte)(51)))), ((int)(((byte)(51)))));
|
||||||
|
this.btnDeletePreset.FlatStyle = System.Windows.Forms.FlatStyle.Popup;
|
||||||
|
this.btnDeletePreset.ForeColor = System.Drawing.Color.White;
|
||||||
|
this.btnDeletePreset.Location = new System.Drawing.Point(10, 167);
|
||||||
|
this.btnDeletePreset.Name = "btnDeletePreset";
|
||||||
|
this.btnDeletePreset.Size = new System.Drawing.Size(243, 40);
|
||||||
|
this.btnDeletePreset.TabIndex = 11;
|
||||||
|
this.btnDeletePreset.Text = "Delete the preset";
|
||||||
|
this.btnDeletePreset.UseVisualStyleBackColor = false;
|
||||||
|
this.btnDeletePreset.Click += new System.EventHandler(this.btnDeletePreset_Click);
|
||||||
|
//
|
||||||
|
// Settings
|
||||||
|
//
|
||||||
|
this.AutoScaleDimensions = new System.Drawing.SizeF(8F, 19F);
|
||||||
|
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
|
||||||
|
this.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(51)))), ((int)(((byte)(51)))), ((int)(((byte)(51)))));
|
||||||
|
this.ClientSize = new System.Drawing.Size(1266, 788);
|
||||||
|
this.Controls.Add(this.gpbxPresets);
|
||||||
|
this.Controls.Add(this.gpbxWindowPreview);
|
||||||
|
this.Controls.Add(this.gpbxPreview);
|
||||||
|
this.Controls.Add(this.gpbxDriverList);
|
||||||
|
this.Controls.Add(this.label1);
|
||||||
|
this.Controls.Add(this.gpbxRaceSettings);
|
||||||
|
this.Font = new System.Drawing.Font("Microsoft YaHei UI", 7.8F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
|
||||||
|
this.Margin = new System.Windows.Forms.Padding(3, 4, 3, 4);
|
||||||
|
this.MinimumSize = new System.Drawing.Size(1284, 835);
|
||||||
|
this.Name = "Settings";
|
||||||
|
this.StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen;
|
||||||
|
this.Text = "Settings";
|
||||||
|
this.FormClosing += new System.Windows.Forms.FormClosingEventHandler(this.Settings_FormClosing);
|
||||||
|
this.Resize += new System.EventHandler(this.Settings_Resize);
|
||||||
|
this.gpbxRaceSettings.ResumeLayout(false);
|
||||||
|
this.gpbxRaceSettings.PerformLayout();
|
||||||
|
this.gpbxDriverList.ResumeLayout(false);
|
||||||
|
this.gpbxDriverList.PerformLayout();
|
||||||
|
this.gpbxPreview.ResumeLayout(false);
|
||||||
|
this.gpbxPreview.PerformLayout();
|
||||||
|
((System.ComponentModel.ISupportInitialize)(this.pbxPreview)).EndInit();
|
||||||
|
this.gpbxWindowPreview.ResumeLayout(false);
|
||||||
|
((System.ComponentModel.ISupportInitialize)(this.pbxWindowPreview)).EndInit();
|
||||||
|
this.gpbxPresets.ResumeLayout(false);
|
||||||
|
this.gpbxPresets.PerformLayout();
|
||||||
|
this.ResumeLayout(false);
|
||||||
|
this.PerformLayout();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
private System.Windows.Forms.Label label1;
|
||||||
|
private System.Windows.Forms.Label label2;
|
||||||
|
private System.Windows.Forms.GroupBox gpbxRaceSettings;
|
||||||
|
private System.Windows.Forms.TextBox tbxGpUrl;
|
||||||
|
private System.Windows.Forms.GroupBox gpbxDriverList;
|
||||||
|
private System.Windows.Forms.ListBox lsbDrivers;
|
||||||
|
private System.Windows.Forms.Button btnRemoveDriver;
|
||||||
|
private System.Windows.Forms.Button btnAddDriver;
|
||||||
|
private System.Windows.Forms.TextBox tbxDriverName;
|
||||||
|
private System.Windows.Forms.GroupBox gpbxPreview;
|
||||||
|
private System.Windows.Forms.PictureBox pbxPreview;
|
||||||
|
private System.Windows.Forms.GroupBox gpbxWindowPreview;
|
||||||
|
private System.Windows.Forms.PictureBox pbxWindowPreview;
|
||||||
|
private System.Windows.Forms.Button btnCreateWindow;
|
||||||
|
private System.Windows.Forms.Button btnCreatZone;
|
||||||
|
private System.Windows.Forms.ListBox lsbPresets;
|
||||||
|
private System.Windows.Forms.TextBox tbxPresetName;
|
||||||
|
private System.Windows.Forms.Button btnSavePreset;
|
||||||
|
private System.Windows.Forms.Label lblWindowsRemaining;
|
||||||
|
private System.Windows.Forms.Label lblZonePointsRemaning;
|
||||||
|
private System.Windows.Forms.Label lblWindowPointsRemaining;
|
||||||
|
private System.Windows.Forms.Button btnRefresh;
|
||||||
|
private System.Windows.Forms.Button btnResetDriver;
|
||||||
|
private System.Windows.Forms.Button btnLoadPreset;
|
||||||
|
private System.Windows.Forms.GroupBox gpbxPresets;
|
||||||
|
private System.Windows.Forms.Button btnDeletePreset;
|
||||||
|
private System.Windows.Forms.ToolTip tip1;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -7,14 +7,15 @@ using System.Linq;
|
|||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using System.Windows.Forms;
|
using System.Windows.Forms;
|
||||||
|
using System.IO;
|
||||||
|
using TrackTrends;
|
||||||
|
|
||||||
namespace Test_Merge
|
namespace TrackTrends
|
||||||
{
|
{
|
||||||
public partial class Settings : Form
|
public partial class Settings : Form
|
||||||
{
|
{
|
||||||
private string _grandPrixUrl = "";
|
private string _grandPrixUrl = "";
|
||||||
private string _grandPrixName = "";
|
private string _selectedConfigFile;
|
||||||
private int _grandPrixYear = 2000;
|
|
||||||
private List<string> _driverList = new List<string>();
|
private List<string> _driverList = new List<string>();
|
||||||
|
|
||||||
private F1TVEmulator Emulator = null;
|
private F1TVEmulator Emulator = null;
|
||||||
@@ -31,9 +32,16 @@ namespace Test_Merge
|
|||||||
List<Rectangle> WindowsToAdd = new List<Rectangle>();
|
List<Rectangle> WindowsToAdd = new List<Rectangle>();
|
||||||
|
|
||||||
public string GrandPrixUrl { get => _grandPrixUrl; private set => _grandPrixUrl = value; }
|
public string GrandPrixUrl { get => _grandPrixUrl; private set => _grandPrixUrl = value; }
|
||||||
public string GrandPrixName { get => _grandPrixName; private set => _grandPrixName = value; }
|
|
||||||
public int GrandPrixYear { get => _grandPrixYear; private set => _grandPrixYear = value; }
|
|
||||||
public List<string> DriverList { get => _driverList; private set => _driverList = value; }
|
public List<string> DriverList { get => _driverList; private set => _driverList = value; }
|
||||||
|
public string SelectedConfigFile { get => _selectedConfigFile; private set => _selectedConfigFile = value; }
|
||||||
|
|
||||||
|
//For the responsive content
|
||||||
|
Size oldSize = new Size();
|
||||||
|
Size oldGpbxPreviewSize = new Size();
|
||||||
|
Size oldGpbxWindowPreviewSize = new Size();
|
||||||
|
|
||||||
|
Size oldPbxPreviewSize = new Size();
|
||||||
|
Size oldPbxWindowPreviewSize = new Size();
|
||||||
|
|
||||||
public Settings()
|
public Settings()
|
||||||
{
|
{
|
||||||
@@ -43,12 +51,31 @@ namespace Test_Merge
|
|||||||
private void Load()
|
private void Load()
|
||||||
{
|
{
|
||||||
RefreshUI();
|
RefreshUI();
|
||||||
|
oldSize = this.Size;
|
||||||
|
oldGpbxPreviewSize = gpbxPreview.Size;
|
||||||
|
oldGpbxWindowPreviewSize = gpbxWindowPreview.Size;
|
||||||
|
oldPbxPreviewSize = pbxPreview.Size;
|
||||||
|
oldPbxWindowPreviewSize = pbxWindowPreview.Size;
|
||||||
|
|
||||||
|
tip1.SetToolTip(btnCreatZone, "After clicking you can select two points in the image to set the bounds of the important data");
|
||||||
|
tip1.SetToolTip(btnCreateWindow, "After clicking this you will have to select all the windows that are important on the lower image. Refer to the documentation for more infos");
|
||||||
|
tip1.SetToolTip(btnRefresh, "Starts the emulator or refreshes the images if its already running");
|
||||||
|
tip1.SetToolTip(btnResetDriver, "Resets the driver if something went wrong or if you want to test an other URL");
|
||||||
|
tip1.SetToolTip(lsbDrivers, "The drivers that are on the image. Non-Case sensitive");
|
||||||
|
tip1.SetToolTip(tbxPresetName, "The name of the preset you want to save");
|
||||||
|
tip1.SetToolTip(pbxPreview, "What the emulator returns");
|
||||||
|
tip1.SetToolTip(pbxWindowPreview, "One of the driver zones that the program managed to slice from the main zone");
|
||||||
}
|
}
|
||||||
private void RefreshUI()
|
private void RefreshUI()
|
||||||
{
|
{
|
||||||
lsbDrivers.DataSource = null;
|
lsbDrivers.DataSource = null;
|
||||||
lsbDrivers.DataSource = DriverList;
|
lsbDrivers.DataSource = DriverList;
|
||||||
|
|
||||||
|
if (Directory.Exists(ConfigurationTool.CONFIGS_FOLDER_NAME))
|
||||||
|
{
|
||||||
|
lsbPresets.DataSource = null;
|
||||||
|
lsbPresets.DataSource = Directory.GetFiles(ConfigurationTool.CONFIGS_FOLDER_NAME);
|
||||||
|
}
|
||||||
if (CreatingZone)
|
if (CreatingZone)
|
||||||
{
|
{
|
||||||
if (ZoneP1 == new Point(-1, -1))
|
if (ZoneP1 == new Point(-1, -1))
|
||||||
@@ -84,14 +111,15 @@ namespace Test_Merge
|
|||||||
}
|
}
|
||||||
if (Config != null)
|
if (Config != null)
|
||||||
{
|
{
|
||||||
pbxMain.Image = Config.MainZone.Draw();
|
pbxPreview.Image = Config.MainZone.Draw();
|
||||||
pbxDriverZone.Image = Config.MainZone.Zones[0].ZoneImage;
|
if (Config.MainZone.Zones.Count > 0)
|
||||||
|
pbxWindowPreview.Image = Config.MainZone.Zones[0].Draw();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
private void CreateNewZone(Point p1, Point p2)
|
private void CreateNewZone(Point p1, Point p2)
|
||||||
{
|
{
|
||||||
Rectangle dimensions = CreateAbsoluteRectangle(p1, p2);
|
Rectangle dimensions = CreateAbsoluteRectangle(p1, p2);
|
||||||
Config = new ConfigurationTool((Bitmap)pbxMain.Image, dimensions);
|
Config = new ConfigurationTool((Bitmap)pbxPreview.Image, dimensions);
|
||||||
RefreshUI();
|
RefreshUI();
|
||||||
}
|
}
|
||||||
private void CreateWindows(List<Rectangle> dimensions)
|
private void CreateWindows(List<Rectangle> dimensions)
|
||||||
@@ -106,29 +134,11 @@ namespace Test_Merge
|
|||||||
GrandPrixUrl = tbxGpUrl.Text;
|
GrandPrixUrl = tbxGpUrl.Text;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void tbxGpName_TextChanged(object sender, EventArgs e)
|
|
||||||
{
|
|
||||||
GrandPrixName = tbxGpName.Text;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void tbxGpYear_TextChanged(object sender, EventArgs e)
|
|
||||||
{
|
|
||||||
int year;
|
|
||||||
try
|
|
||||||
{
|
|
||||||
year = Convert.ToInt32(tbxGpYear.Text);
|
|
||||||
}
|
|
||||||
catch
|
|
||||||
{
|
|
||||||
year = 1545;
|
|
||||||
}
|
|
||||||
GrandPrixYear = year;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void btnAddDriver_Click(object sender, EventArgs e)
|
private void btnAddDriver_Click(object sender, EventArgs e)
|
||||||
{
|
{
|
||||||
string newDriver = tbxDriverName.Text;
|
string newDriver = tbxDriverName.Text;
|
||||||
DriverList.Add(newDriver);
|
DriverList.Add(newDriver);
|
||||||
|
tbxDriverName.Text = "";
|
||||||
RefreshUI();
|
RefreshUI();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -150,13 +160,17 @@ namespace Test_Merge
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
CreatingZone = true;
|
CreatingZone = true;
|
||||||
|
|
||||||
|
if (Config != null)
|
||||||
|
Config.ResetMainZone();
|
||||||
|
|
||||||
if (CreatingWindow)
|
if (CreatingWindow)
|
||||||
SwitchWindowCreation();
|
SwitchWindowCreation();
|
||||||
|
|
||||||
if (Emulator != null && Emulator.Ready)
|
if (Emulator != null && Emulator.Ready)
|
||||||
{
|
{
|
||||||
Config = null;
|
Config = null;
|
||||||
pbxMain.Image = Emulator.Screenshot();
|
pbxPreview.Image = Emulator.Screenshot();
|
||||||
}
|
}
|
||||||
|
|
||||||
ZoneP1 = new Point(-1, -1);
|
ZoneP1 = new Point(-1, -1);
|
||||||
@@ -176,6 +190,9 @@ namespace Test_Merge
|
|||||||
{
|
{
|
||||||
CreatingWindow = true;
|
CreatingWindow = true;
|
||||||
|
|
||||||
|
if (Config != null)
|
||||||
|
Config.ResetWindows();
|
||||||
|
|
||||||
if (CreatingZone)
|
if (CreatingZone)
|
||||||
SwitchZoneCreation();
|
SwitchZoneCreation();
|
||||||
|
|
||||||
@@ -194,19 +211,17 @@ namespace Test_Merge
|
|||||||
{
|
{
|
||||||
SwitchWindowCreation();
|
SwitchWindowCreation();
|
||||||
}
|
}
|
||||||
private void pbxMain_Click(object sender, EventArgs e)
|
private void pbxMain_MouseClick(object sender, MouseEventArgs e)
|
||||||
{
|
{
|
||||||
if (CreatingZone && pbxMain.Image != null)
|
if (CreatingZone && pbxPreview.Image != null)
|
||||||
{
|
{
|
||||||
Point coordinates = pbxMain.PointToClient(new Point(MousePosition.X, MousePosition.Y));
|
//Point coordinates = pbxMain.PointToClient(new Point(MousePosition.X, MousePosition.Y));
|
||||||
float xOffset = (float)pbxMain.Image.Width / (float)pbxMain.Width;
|
Point coordinates = e.Location;
|
||||||
float yOffset = (float)pbxMain.Image.Height / (float)pbxMain.Height;
|
float xOffset = (float)pbxPreview.Image.Width / (float)pbxPreview.Width;
|
||||||
|
float yOffset = (float)pbxPreview.Image.Height / (float)pbxPreview.Height;
|
||||||
Point newPoint = new Point(Convert.ToInt32((float)coordinates.X * xOffset), Convert.ToInt32((float)coordinates.Y * yOffset));
|
Point newPoint = new Point(Convert.ToInt32((float)coordinates.X * xOffset), Convert.ToInt32((float)coordinates.Y * yOffset));
|
||||||
|
|
||||||
//Point newPoint = new Point(coordinates.X - pbxMain.Left, coordinates.Y - pbxMain.Top);
|
//MessageBox.Show("Coordinates" + Environment.NewLine + "Old : " + coordinates.ToString() + Environment.NewLine + "New : " + newPoint.ToString());
|
||||||
//newPoint = new Point(Convert.ToInt32((float)newPoint.X * xOffset),Convert.ToInt32((float)newPoint.Y * yOffset));
|
|
||||||
|
|
||||||
MessageBox.Show("Coordinates" + Environment.NewLine + "Old : " + coordinates.ToString() + Environment.NewLine + "New : " + newPoint.ToString());
|
|
||||||
|
|
||||||
if (ZoneP1 == new Point(-1, -1))
|
if (ZoneP1 == new Point(-1, -1))
|
||||||
{
|
{
|
||||||
@@ -215,34 +230,24 @@ namespace Test_Merge
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
ZoneP2 = newPoint;
|
ZoneP2 = newPoint;
|
||||||
|
|
||||||
/*
|
|
||||||
//Correction
|
|
||||||
if(ZoneP1.Y > ZoneP2.Y)
|
|
||||||
{
|
|
||||||
ZoneP1 = new Point(ZoneP1.X,ZoneP1.Y + pbxMain.Top);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
ZoneP2 = new Point(ZoneP2.X, ZoneP2.Y - pbxMain.Top);
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
|
||||||
CreateNewZone(ZoneP1, ZoneP2);
|
CreateNewZone(ZoneP1, ZoneP2);
|
||||||
SwitchZoneCreation();
|
SwitchZoneCreation();
|
||||||
}
|
}
|
||||||
RefreshUI();
|
RefreshUI();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
private void pbxMain_Click(object sender, EventArgs e)
|
||||||
private void pbxDriverZone_Click(object sender, EventArgs e)
|
|
||||||
{
|
{
|
||||||
if (CreatingWindow && pbxDriverZone.Image != null)
|
//Not the right one to use visibly
|
||||||
|
}
|
||||||
|
private void pbxDriverZone_MouseClick(object sender, MouseEventArgs e)
|
||||||
{
|
{
|
||||||
Point coordinates = pbxDriverZone.PointToClient(new Point(MousePosition.X, MousePosition.Y));
|
if (CreatingWindow && pbxWindowPreview.Image != null)
|
||||||
|
{
|
||||||
|
Point coordinates = e.Location;
|
||||||
|
|
||||||
float xOffset = (float)pbxDriverZone.Image.Width / (float)pbxDriverZone.Width;
|
float xOffset = (float)pbxWindowPreview.Image.Width / (float)pbxWindowPreview.Width;
|
||||||
float yOffset = (float)pbxDriverZone.Image.Height / (float)pbxDriverZone.Height;
|
float yOffset = (float)pbxWindowPreview.Image.Height / (float)pbxWindowPreview.Height;
|
||||||
|
|
||||||
Point newPoint = new Point(Convert.ToInt32((float)coordinates.X * xOffset), Convert.ToInt32((float)coordinates.Y * yOffset));
|
Point newPoint = new Point(Convert.ToInt32((float)coordinates.X * xOffset), Convert.ToInt32((float)coordinates.Y * yOffset));
|
||||||
|
|
||||||
@@ -262,12 +267,19 @@ namespace Test_Merge
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
WindowP1 = new Point(WindowP1.X, 0);
|
||||||
|
WindowP2 = new Point(WindowP2.X, pbxWindowPreview.Image.Height);
|
||||||
CreateWindows(WindowsToAdd);
|
CreateWindows(WindowsToAdd);
|
||||||
|
SwitchWindowCreation();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
RefreshUI();
|
RefreshUI();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
private void pbxDriverZone_Click(object sender, EventArgs e)
|
||||||
|
{
|
||||||
|
//Not the right one to use visibly
|
||||||
|
}
|
||||||
private Rectangle CreateAbsoluteRectangle(Point p1, Point p2)
|
private Rectangle CreateAbsoluteRectangle(Point p1, Point p2)
|
||||||
{
|
{
|
||||||
Point newP1 = new Point();
|
Point newP1 = new Point();
|
||||||
@@ -300,6 +312,9 @@ namespace Test_Merge
|
|||||||
private async void btnRefresh_Click(object sender, EventArgs e)
|
private async void btnRefresh_Click(object sender, EventArgs e)
|
||||||
{
|
{
|
||||||
btnRefresh.Enabled = false;
|
btnRefresh.Enabled = false;
|
||||||
|
btnCreatZone.Enabled = false;
|
||||||
|
btnCreateWindow.Enabled = false;
|
||||||
|
btnResetDriver.Enabled = false;
|
||||||
if (Emulator == null || Emulator.GrandPrixUrl != tbxGpUrl.Text)
|
if (Emulator == null || Emulator.GrandPrixUrl != tbxGpUrl.Text)
|
||||||
{
|
{
|
||||||
Emulator = new F1TVEmulator(tbxGpUrl.Text);
|
Emulator = new F1TVEmulator(tbxGpUrl.Text);
|
||||||
@@ -314,6 +329,9 @@ namespace Test_Merge
|
|||||||
string message;
|
string message;
|
||||||
switch (errorCode)
|
switch (errorCode)
|
||||||
{
|
{
|
||||||
|
case 100:
|
||||||
|
message = "Error " + errorCode + " Could not recover cookies. It could be because of an improper installation of python or bad cookies in the chrome database. Please try to log on to the F1TV using chrome again";
|
||||||
|
break;
|
||||||
case 101:
|
case 101:
|
||||||
message = "Error " + errorCode + " Could not start the driver. It could be because an other instance is runnin make sure you closed them all before trying again";
|
message = "Error " + errorCode + " Could not start the driver. It could be because an other instance is runnin make sure you closed them all before trying again";
|
||||||
break;
|
break;
|
||||||
@@ -329,6 +347,9 @@ namespace Test_Merge
|
|||||||
case 105:
|
case 105:
|
||||||
message = "Error " + errorCode + " There has been an error trying to emulate button presses. Please try again";
|
message = "Error " + errorCode + " There has been an error trying to emulate button presses. Please try again";
|
||||||
break;
|
break;
|
||||||
|
case 106:
|
||||||
|
message = "Error " + errorCode + " There has been an error trying to emulate button presses. Please try again";
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
message = "Could not start the emulator Error " + errorCode;
|
message = "Could not start the emulator Error " + errorCode;
|
||||||
break;
|
break;
|
||||||
@@ -337,14 +358,18 @@ namespace Test_Merge
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
pbxMain.Image = Emulator.Screenshot();
|
pbxPreview.Image = Emulator.Screenshot();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
pbxMain.Image = Emulator.Screenshot();
|
pbxPreview.Image = Emulator.Screenshot();
|
||||||
}
|
}
|
||||||
btnRefresh.Enabled = true;
|
btnRefresh.Enabled = true;
|
||||||
|
btnCreatZone.Enabled = true;
|
||||||
|
btnCreateWindow.Enabled = true;
|
||||||
|
btnResetDriver.Enabled = true;
|
||||||
|
btnRefresh.Text = "Get a newer image";
|
||||||
}
|
}
|
||||||
|
|
||||||
private void Settings_FormClosing(object sender, FormClosingEventArgs e)
|
private void Settings_FormClosing(object sender, FormClosingEventArgs e)
|
||||||
@@ -353,6 +378,100 @@ namespace Test_Merge
|
|||||||
{
|
{
|
||||||
Emulator.Stop();
|
Emulator.Stop();
|
||||||
}
|
}
|
||||||
|
Emulator = null;
|
||||||
|
GC.Collect();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void btnResetDriver_Click(object sender, EventArgs e)
|
||||||
|
{
|
||||||
|
if (Emulator != null)
|
||||||
|
{
|
||||||
|
Emulator.ResetDriver();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void btnSavePreset_Click(object sender, EventArgs e)
|
||||||
|
{
|
||||||
|
string presetName = tbxPresetName.Text;
|
||||||
|
if (Config != null)
|
||||||
|
{
|
||||||
|
Config.SaveToJson(DriverList, presetName);
|
||||||
|
}
|
||||||
|
RefreshUI();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void lsbPresets_SelectedIndexChanged(object sender, EventArgs e)
|
||||||
|
{
|
||||||
|
SelectedConfigFile = (string)lsbPresets.Items[lsbPresets.SelectedIndex];
|
||||||
|
}
|
||||||
|
|
||||||
|
private void btnLoadPreset_Click(object sender, EventArgs e)
|
||||||
|
{
|
||||||
|
//MessageBox.Show(lsbPresets.SelectedIndex.ToString());
|
||||||
|
if (lsbPresets.SelectedIndex >= 0 && pbxPreview.Image != null)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
string fileName = lsbPresets.Items[lsbPresets.SelectedIndex].ToString();
|
||||||
|
Reader reader = new Reader(fileName, (Bitmap)pbxPreview.Image, false);
|
||||||
|
//MainZones #0 is the big main zone containing driver zones
|
||||||
|
Config = new ConfigurationTool((Bitmap)pbxPreview.Image, reader.MainZones[0].Bounds);
|
||||||
|
Config.MainZone = reader.MainZones[0];
|
||||||
|
DriverList = reader.Drivers;
|
||||||
|
SelectedConfigFile = fileName;
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
MessageBox.Show("Could not load the settings error :" + ex);
|
||||||
|
}
|
||||||
|
RefreshUI();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void Settings_Resize(object sender, EventArgs e)
|
||||||
|
{
|
||||||
|
int xDiff = this.Width - oldSize.Width;
|
||||||
|
int yDiff = this.Height - oldSize.Height;
|
||||||
|
|
||||||
|
gpbxPreview.Size = new Size(oldGpbxPreviewSize.Width + xDiff, oldGpbxPreviewSize.Height + yDiff);
|
||||||
|
gpbxWindowPreview.Size = new Size(oldGpbxWindowPreviewSize.Width + xDiff, oldGpbxWindowPreviewSize.Height);
|
||||||
|
pbxPreview.Size = new Size(oldPbxPreviewSize.Width + xDiff, oldPbxPreviewSize.Height + yDiff);
|
||||||
|
pbxWindowPreview.Size = new Size(oldPbxWindowPreviewSize.Width + xDiff, oldPbxWindowPreviewSize.Height);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void btnDeletePreset_Click(object sender, EventArgs e)
|
||||||
|
{
|
||||||
|
int selectedIndex = lsbPresets.SelectedIndex;
|
||||||
|
if (selectedIndex >= 0)
|
||||||
|
{
|
||||||
|
string fileName = lsbPresets.Items[selectedIndex].ToString();
|
||||||
|
if (File.Exists(fileName))
|
||||||
|
{
|
||||||
|
File.Delete(fileName);
|
||||||
|
RefreshUI();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
MessageBox.Show("Could not delete the preset because it does not exists");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void removeBorders(object sender, PaintEventArgs e)
|
||||||
|
{
|
||||||
|
GroupBox gpbx = (GroupBox)sender;
|
||||||
|
|
||||||
|
using (Pen pen = new Pen(gpbx.BackColor, 50))
|
||||||
|
{
|
||||||
|
e.Graphics.DrawRectangle(pen, 0, 0, gpbx.Width - 1, gpbx.Height - 1);
|
||||||
|
e.Graphics.DrawRectangle(pen, 0, 0, gpbx.Width - 1, gpbx.Height - 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
using (var brush = new SolidBrush(gpbx.ForeColor))
|
||||||
|
{
|
||||||
|
var textPosition = new Point(5, 0); // Adjust the X and Y values as needed
|
||||||
|
e.Graphics.DrawString(gpbx.Text, gpbx.Font, brush, textPosition);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -117,4 +117,7 @@
|
|||||||
<resheader name="writer">
|
<resheader name="writer">
|
||||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||||
</resheader>
|
</resheader>
|
||||||
|
<metadata name="tip1.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
|
||||||
|
<value>17, 17</value>
|
||||||
|
</metadata>
|
||||||
</root>
|
</root>
|
||||||
@@ -0,0 +1,262 @@
|
|||||||
|
/// Author : Maxime Rohmer
|
||||||
|
/// Date : 30/05/2023
|
||||||
|
/// File : SqliteStorage.cs
|
||||||
|
/// Brief : Class that controls the sqlite database
|
||||||
|
/// Version : Alpha 1.0
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using System.Data.SQLite;
|
||||||
|
using System.IO;
|
||||||
|
using System.Windows.Forms;
|
||||||
|
|
||||||
|
namespace TrackTrends
|
||||||
|
{
|
||||||
|
public class SqliteStorage
|
||||||
|
{
|
||||||
|
private const string DATABASE_FOLDER = "./Data";
|
||||||
|
private const string DATABASE_FILE = "/database.sqlite";
|
||||||
|
private const string CONNECTION_STRING = "Data Source=" + DATABASE_FOLDER + DATABASE_FILE + ";Version=3;";
|
||||||
|
|
||||||
|
private SQLiteConnection Connection;
|
||||||
|
/// <summary>
|
||||||
|
/// Creates a new Sqlite Storage and initialize the database
|
||||||
|
/// </summary>
|
||||||
|
public SqliteStorage()
|
||||||
|
{
|
||||||
|
Load();
|
||||||
|
}
|
||||||
|
/// <summary>
|
||||||
|
/// Loads a fresh new Database or create a new one if it does not exist.
|
||||||
|
/// </summary>
|
||||||
|
private void Load()
|
||||||
|
{
|
||||||
|
if (!Directory.Exists(DATABASE_FOLDER))
|
||||||
|
Directory.CreateDirectory(DATABASE_FOLDER);
|
||||||
|
|
||||||
|
if (!File.Exists(DATABASE_FOLDER + DATABASE_FILE))
|
||||||
|
{
|
||||||
|
SQLiteConnection.CreateFile(DATABASE_FOLDER + DATABASE_FILE);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
//We are not using the existing DataBase
|
||||||
|
File.Delete(DATABASE_FOLDER + DATABASE_FILE);
|
||||||
|
}
|
||||||
|
|
||||||
|
Connection = new SQLiteConnection(CONNECTION_STRING);
|
||||||
|
Connection.Open();
|
||||||
|
|
||||||
|
//Create the drivers table
|
||||||
|
string createDriversTableQuery = @"CREATE TABLE IF NOT EXISTS Drivers
|
||||||
|
(ID INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||||
|
Name VARCHAR NOT NULL);";
|
||||||
|
using (var command = new SQLiteCommand(createDriversTableQuery, Connection))
|
||||||
|
{
|
||||||
|
command.ExecuteNonQuery();
|
||||||
|
}
|
||||||
|
|
||||||
|
//Create the drivers table
|
||||||
|
string createPitstopTableQuery = @"CREATE TABLE Pitstops
|
||||||
|
(Lap INTEGER NOT NULL,
|
||||||
|
DriverID INTEGER NOT NULL,
|
||||||
|
Tyre VARCHAR,
|
||||||
|
PRIMARY KEY (Lap,DriverID));";
|
||||||
|
using (var command = new SQLiteCommand(createPitstopTableQuery, Connection))
|
||||||
|
{
|
||||||
|
command.ExecuteNonQuery();
|
||||||
|
}
|
||||||
|
|
||||||
|
//Create the stats
|
||||||
|
string createStatsTableQuery = @"CREATE TABLE IF NOT EXISTS Stats
|
||||||
|
(Lap INTEGER NOT NULL,
|
||||||
|
DriverID INTEGER NOT NULL,
|
||||||
|
Tyre VARCHAR NOT NULL,
|
||||||
|
LapTime INTEGER NOT NULL,
|
||||||
|
Sector1 INTEGER NOT NULL,
|
||||||
|
Sector2 INTEGER NOT NULL,
|
||||||
|
Sector3 INTEGER NOT NULL,
|
||||||
|
GapToLeader INTEGER NOT NULL,
|
||||||
|
Position INTEGER NOT NULL,
|
||||||
|
PRIMARY KEY (Lap, DriverID));";
|
||||||
|
using (var command = new SQLiteCommand(createStatsTableQuery, Connection))
|
||||||
|
{
|
||||||
|
command.ExecuteNonQuery();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/// <summary>
|
||||||
|
/// Adds a driver into the drivers table. Meant to be used at the start of the programm
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="name">The name of the driver. (non case sensitive)</param>
|
||||||
|
public void AddDriver(string name)
|
||||||
|
{
|
||||||
|
string insertQuery = "INSERT INTO Drivers (Name) VALUES (@name);";
|
||||||
|
|
||||||
|
using (var command = new SQLiteCommand(insertQuery,Connection))
|
||||||
|
{
|
||||||
|
command.Parameters.AddWithValue("@Name",name);
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
command.ExecuteNonQuery();
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
//MessageBox.Show("An error has occured while trying to insert a new driver into de Database");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/// <summary>
|
||||||
|
/// Searches for a driver and returns its id if it has been found
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="name">Name of the driver (non case sensitive)</param>
|
||||||
|
/// <returns></returns>
|
||||||
|
private int GetDriverID(string name)
|
||||||
|
{
|
||||||
|
string selectQuery = "SELECT ID FROM Drivers where Name LIKE @driverName";
|
||||||
|
int result = 0;
|
||||||
|
using (var command = new SQLiteCommand(selectQuery,Connection))
|
||||||
|
{
|
||||||
|
command.Parameters.AddWithValue("@driverName",name);
|
||||||
|
try
|
||||||
|
{
|
||||||
|
using (var reader = command.ExecuteReader())
|
||||||
|
{
|
||||||
|
while (reader.Read())
|
||||||
|
{
|
||||||
|
result = reader.GetInt32(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
//MessageBox.Show("There has been an error while trying to retrieve the ID of a Driver from the database");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the sectors from a lapTime. Sectors are subdivisions of a laptime (could be usefull to validate one or the other)
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="driverName">The name of the driver who has done the lap</param>
|
||||||
|
/// <param name="lap">The lap at wich the driver has done the time</param>
|
||||||
|
/// <returns>A list of the different sectors time in int (ms)</returns>
|
||||||
|
public List<int> GetSectorsFromLapTime(string driverName,int lap)
|
||||||
|
{
|
||||||
|
int driverId = GetDriverID(driverName);
|
||||||
|
string selectQuery = "SELECT Sector1,Sector2,Sector3 FROM Stats WHERE DriverID = @driverID AND Lap = @lap";
|
||||||
|
List<int> result = new List<int>();
|
||||||
|
using (var command = new SQLiteCommand(selectQuery, Connection))
|
||||||
|
{
|
||||||
|
command.Parameters.AddWithValue("@driverID", driverId);
|
||||||
|
command.Parameters.AddWithValue("@lap", lap);
|
||||||
|
try
|
||||||
|
{
|
||||||
|
SQLiteDataReader reader = command.ExecuteReader();
|
||||||
|
while (reader.Read())
|
||||||
|
{
|
||||||
|
result.Add(reader.GetInt32(0));
|
||||||
|
result.Add(reader.GetInt32(1));
|
||||||
|
result.Add(reader.GetInt32(2));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
//MessageBox.Show("There has been an error while trying to retrieve the ID of a Driver from the database");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
/// <summary>
|
||||||
|
/// Get the laptime history of a driver
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="driverName">The name of the driver</param>
|
||||||
|
/// <param name="numberOfLaptimes">The number of lapTimes you want</param>
|
||||||
|
/// <returns>A list of tuples with the lap and the laptime. It will only return the amount it found so even if you ask 5 expect getting less or even 0</returns>
|
||||||
|
public List<(int LapTime, int Lap)> GetDriverLaptimes(string driverName,int numberOfLaptimes)
|
||||||
|
{
|
||||||
|
int driverId = GetDriverID(driverName);
|
||||||
|
List<(int LapTime, int Lap)> lapData = new List<(int LapTime, int Lap)>();
|
||||||
|
string selectQuery = "Select LapTime,Lap from Stats WHERE DriverID = @driverID ORDER BY Lap DESC LIMIT @limit";
|
||||||
|
using (var command = new SQLiteCommand(selectQuery, Connection))
|
||||||
|
{
|
||||||
|
command.Parameters.AddWithValue("@driverID", driverId);
|
||||||
|
command.Parameters.AddWithValue("@limit", numberOfLaptimes);
|
||||||
|
try
|
||||||
|
{
|
||||||
|
SQLiteDataReader reader = command.ExecuteReader();
|
||||||
|
while (reader.Read())
|
||||||
|
{
|
||||||
|
int lapTime = reader.GetInt32(0);
|
||||||
|
int lap = reader.GetInt32(1);
|
||||||
|
lapData.Add((lapTime, lap));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
//MessageBox.Show("There has been an error while trying to retrieve the ID of a Driver from the database");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return lapData;
|
||||||
|
}
|
||||||
|
/// <summary>
|
||||||
|
/// Add a pitstop into the db
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="driverName">The name of the driver who made his pitstop</param>
|
||||||
|
/// <param name="lap">The lap where he stopped</param>
|
||||||
|
/// <param name="tyre">The tyre he took out</param>
|
||||||
|
public void AddPitstop(string driverName,int lap,string tyre)
|
||||||
|
{
|
||||||
|
string insertQuery = "INSERT INTO Pitstops (Lap,DriverID,Tyre) VALUES (@Lap,@DriverID,@Tyre)";
|
||||||
|
|
||||||
|
using (var command = new SQLiteCommand(insertQuery,Connection))
|
||||||
|
{
|
||||||
|
command.Parameters.AddWithValue("@Lap",lap);
|
||||||
|
command.Parameters.AddWithValue("@DriverID",GetDriverID(driverName));
|
||||||
|
command.Parameters.AddWithValue("@Tyre",tyre);
|
||||||
|
try
|
||||||
|
{
|
||||||
|
command.ExecuteNonQuery();
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
//MessageBox.Show("An error has occured while trying to insert a new pitstop into the DB" + Environment.NewLine + "Request :"+ command.ToString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/// <summary>
|
||||||
|
/// Adds drivers info into the DB (it should only be once per lap)
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="data">The Driver data</param>
|
||||||
|
/// <param name="lap">The lap from wich the datas are from</param>
|
||||||
|
public void AddDriverStat(DriverData data,int lap)
|
||||||
|
{
|
||||||
|
string insertQuery = "INSERT INTO Stats (Lap,DriverID,Tyre,LapTime,Sector1,Sector2,Sector3,GapToLeader,Position) VALUES (@Lap,@DriverID,@Tyre,@LapTime,@Sector1,@Sector2,@Sector3,@GapToLeader,@Position);";
|
||||||
|
|
||||||
|
using (var command = new SQLiteCommand(insertQuery,Connection))
|
||||||
|
{
|
||||||
|
command.Parameters.AddWithValue("@Lap",lap);
|
||||||
|
command.Parameters.AddWithValue("@DriverID",GetDriverID(data.Name));
|
||||||
|
command.Parameters.AddWithValue("@Tyre",data.CurrentTyre.Coumpound.ToString());
|
||||||
|
command.Parameters.AddWithValue("@LapTime",data.LapTime);
|
||||||
|
command.Parameters.AddWithValue("@Sector1",data.Sector1);
|
||||||
|
command.Parameters.AddWithValue("@Sector2", data.Sector2);
|
||||||
|
command.Parameters.AddWithValue("@Sector3", data.Sector3);
|
||||||
|
command.Parameters.AddWithValue("@GapToLeader", data.GapToLeader);
|
||||||
|
command.Parameters.AddWithValue("@Position", data.Position);
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
command.ExecuteNonQuery();
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
//MessageBox.Show("An error has occured while trying to insert infos about a driver");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,13 +1,14 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||||
|
<Import Project="..\packages\EntityFramework.6.4.4\build\EntityFramework.props" Condition="Exists('..\packages\EntityFramework.6.4.4\build\EntityFramework.props')" />
|
||||||
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
|
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
||||||
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
|
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
|
||||||
<ProjectGuid>{F6694884-3B45-4017-9C9A-A0AFFC508245}</ProjectGuid>
|
<ProjectGuid>{F6694884-3B45-4017-9C9A-A0AFFC508245}</ProjectGuid>
|
||||||
<OutputType>WinExe</OutputType>
|
<OutputType>WinExe</OutputType>
|
||||||
<RootNamespace>Test_Merge</RootNamespace>
|
<RootNamespace>TrackTrends</RootNamespace>
|
||||||
<AssemblyName>Test_Merge</AssemblyName>
|
<AssemblyName>TrackTrends</AssemblyName>
|
||||||
<TargetFrameworkVersion>v4.7.2</TargetFrameworkVersion>
|
<TargetFrameworkVersion>v4.7.2</TargetFrameworkVersion>
|
||||||
<FileAlignment>512</FileAlignment>
|
<FileAlignment>512</FileAlignment>
|
||||||
<AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
|
<AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
|
||||||
@@ -36,6 +37,12 @@
|
|||||||
<WarningLevel>4</WarningLevel>
|
<WarningLevel>4</WarningLevel>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
<Reference Include="EntityFramework, Version=6.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089, processorArchitecture=MSIL">
|
||||||
|
<HintPath>..\packages\EntityFramework.6.4.4\lib\net45\EntityFramework.dll</HintPath>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="EntityFramework.SqlServer, Version=6.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089, processorArchitecture=MSIL">
|
||||||
|
<HintPath>..\packages\EntityFramework.6.4.4\lib\net45\EntityFramework.SqlServer.dll</HintPath>
|
||||||
|
</Reference>
|
||||||
<Reference Include="Microsoft.Bcl.AsyncInterfaces, Version=7.0.0.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
|
<Reference Include="Microsoft.Bcl.AsyncInterfaces, Version=7.0.0.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
|
||||||
<HintPath>..\packages\Microsoft.Bcl.AsyncInterfaces.7.0.0\lib\net462\Microsoft.Bcl.AsyncInterfaces.dll</HintPath>
|
<HintPath>..\packages\Microsoft.Bcl.AsyncInterfaces.7.0.0\lib\net462\Microsoft.Bcl.AsyncInterfaces.dll</HintPath>
|
||||||
</Reference>
|
</Reference>
|
||||||
@@ -43,7 +50,17 @@
|
|||||||
<Reference Include="System.Buffers, Version=4.0.3.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
|
<Reference Include="System.Buffers, Version=4.0.3.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
|
||||||
<HintPath>..\packages\System.Buffers.4.5.1\lib\net461\System.Buffers.dll</HintPath>
|
<HintPath>..\packages\System.Buffers.4.5.1\lib\net461\System.Buffers.dll</HintPath>
|
||||||
</Reference>
|
</Reference>
|
||||||
|
<Reference Include="System.ComponentModel.DataAnnotations" />
|
||||||
<Reference Include="System.Core" />
|
<Reference Include="System.Core" />
|
||||||
|
<Reference Include="System.Data.SQLite, Version=1.0.117.0, Culture=neutral, PublicKeyToken=db937bc2d44ff139, processorArchitecture=MSIL">
|
||||||
|
<HintPath>..\packages\Stub.System.Data.SQLite.Core.NetFramework.1.0.117.0\lib\net46\System.Data.SQLite.dll</HintPath>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="System.Data.SQLite.EF6, Version=1.0.117.0, Culture=neutral, PublicKeyToken=db937bc2d44ff139, processorArchitecture=MSIL">
|
||||||
|
<HintPath>..\packages\System.Data.SQLite.EF6.1.0.117.0\lib\net46\System.Data.SQLite.EF6.dll</HintPath>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="System.Data.SQLite.Linq, Version=1.0.117.0, Culture=neutral, PublicKeyToken=db937bc2d44ff139, processorArchitecture=MSIL">
|
||||||
|
<HintPath>..\packages\System.Data.SQLite.Linq.1.0.117.0\lib\net46\System.Data.SQLite.Linq.dll</HintPath>
|
||||||
|
</Reference>
|
||||||
<Reference Include="System.Memory, Version=4.0.1.2, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
|
<Reference Include="System.Memory, Version=4.0.1.2, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
|
||||||
<HintPath>..\packages\System.Memory.4.5.5\lib\net461\System.Memory.dll</HintPath>
|
<HintPath>..\packages\System.Memory.4.5.5\lib\net461\System.Memory.dll</HintPath>
|
||||||
</Reference>
|
</Reference>
|
||||||
@@ -87,6 +104,7 @@
|
|||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Compile Include="ConfigurationTool.cs" />
|
<Compile Include="ConfigurationTool.cs" />
|
||||||
|
<Compile Include="DataWrapper.cs" />
|
||||||
<Compile Include="DriverData.cs" />
|
<Compile Include="DriverData.cs" />
|
||||||
<Compile Include="DriverDrsWindow.cs" />
|
<Compile Include="DriverDrsWindow.cs" />
|
||||||
<Compile Include="DriverGapToLeaderWindow.cs" />
|
<Compile Include="DriverGapToLeaderWindow.cs" />
|
||||||
@@ -102,16 +120,17 @@
|
|||||||
<Compile Include="Form1.Designer.cs">
|
<Compile Include="Form1.Designer.cs">
|
||||||
<DependentUpon>Form1.cs</DependentUpon>
|
<DependentUpon>Form1.cs</DependentUpon>
|
||||||
</Compile>
|
</Compile>
|
||||||
<Compile Include="OCRDecoder.cs" />
|
|
||||||
<Compile Include="OcrImage.cs" />
|
<Compile Include="OcrImage.cs" />
|
||||||
<Compile Include="Program.cs" />
|
<Compile Include="Program.cs" />
|
||||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||||
|
<Compile Include="Reader.cs" />
|
||||||
<Compile Include="Settings.cs">
|
<Compile Include="Settings.cs">
|
||||||
<SubType>Form</SubType>
|
<SubType>Form</SubType>
|
||||||
</Compile>
|
</Compile>
|
||||||
<Compile Include="Settings.Designer.cs">
|
<Compile Include="Settings.Designer.cs">
|
||||||
<DependentUpon>Settings.cs</DependentUpon>
|
<DependentUpon>Settings.cs</DependentUpon>
|
||||||
</Compile>
|
</Compile>
|
||||||
|
<Compile Include="SqliteStorage.cs" />
|
||||||
<Compile Include="Window.cs" />
|
<Compile Include="Window.cs" />
|
||||||
<Compile Include="Zone.cs" />
|
<Compile Include="Zone.cs" />
|
||||||
<EmbeddedResource Include="Form1.resx">
|
<EmbeddedResource Include="Form1.resx">
|
||||||
@@ -144,15 +163,20 @@
|
|||||||
<None Include="App.config" />
|
<None Include="App.config" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||||
<Import Project="..\packages\Selenium.Firefox.WebDriver.0.27.0\build\Selenium.Firefox.WebDriver.targets" Condition="Exists('..\packages\Selenium.Firefox.WebDriver.0.27.0\build\Selenium.Firefox.WebDriver.targets')" />
|
|
||||||
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
|
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<ErrorText>This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.</ErrorText>
|
<ErrorText>This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.</ErrorText>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
<Error Condition="!Exists('..\packages\Selenium.Firefox.WebDriver.0.27.0\build\Selenium.Firefox.WebDriver.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\Selenium.Firefox.WebDriver.0.27.0\build\Selenium.Firefox.WebDriver.targets'))" />
|
|
||||||
<Error Condition="!Exists('..\packages\Selenium.WebDriver.4.8.2\build\Selenium.WebDriver.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\Selenium.WebDriver.4.8.2\build\Selenium.WebDriver.targets'))" />
|
|
||||||
<Error Condition="!Exists('..\packages\Tesseract.5.2.0\build\Tesseract.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\Tesseract.5.2.0\build\Tesseract.targets'))" />
|
<Error Condition="!Exists('..\packages\Tesseract.5.2.0\build\Tesseract.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\Tesseract.5.2.0\build\Tesseract.targets'))" />
|
||||||
|
<Error Condition="!Exists('..\packages\Selenium.WebDriver.4.8.2\build\Selenium.WebDriver.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\Selenium.WebDriver.4.8.2\build\Selenium.WebDriver.targets'))" />
|
||||||
|
<Error Condition="!Exists('..\packages\Selenium.Firefox.WebDriver.0.27.0\build\Selenium.Firefox.WebDriver.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\Selenium.Firefox.WebDriver.0.27.0\build\Selenium.Firefox.WebDriver.targets'))" />
|
||||||
|
<Error Condition="!Exists('..\packages\EntityFramework.6.4.4\build\EntityFramework.props')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\EntityFramework.6.4.4\build\EntityFramework.props'))" />
|
||||||
|
<Error Condition="!Exists('..\packages\EntityFramework.6.4.4\build\EntityFramework.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\EntityFramework.6.4.4\build\EntityFramework.targets'))" />
|
||||||
|
<Error Condition="!Exists('..\packages\Stub.System.Data.SQLite.Core.NetFramework.1.0.117.0\build\net46\Stub.System.Data.SQLite.Core.NetFramework.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\Stub.System.Data.SQLite.Core.NetFramework.1.0.117.0\build\net46\Stub.System.Data.SQLite.Core.NetFramework.targets'))" />
|
||||||
</Target>
|
</Target>
|
||||||
<Import Project="..\packages\Selenium.WebDriver.4.8.2\build\Selenium.WebDriver.targets" Condition="Exists('..\packages\Selenium.WebDriver.4.8.2\build\Selenium.WebDriver.targets')" />
|
|
||||||
<Import Project="..\packages\Tesseract.5.2.0\build\Tesseract.targets" Condition="Exists('..\packages\Tesseract.5.2.0\build\Tesseract.targets')" />
|
<Import Project="..\packages\Tesseract.5.2.0\build\Tesseract.targets" Condition="Exists('..\packages\Tesseract.5.2.0\build\Tesseract.targets')" />
|
||||||
|
<Import Project="..\packages\Selenium.WebDriver.4.8.2\build\Selenium.WebDriver.targets" Condition="Exists('..\packages\Selenium.WebDriver.4.8.2\build\Selenium.WebDriver.targets')" />
|
||||||
|
<Import Project="..\packages\Selenium.Firefox.WebDriver.0.27.0\build\Selenium.Firefox.WebDriver.targets" Condition="Exists('..\packages\Selenium.Firefox.WebDriver.0.27.0\build\Selenium.Firefox.WebDriver.targets')" />
|
||||||
|
<Import Project="..\packages\EntityFramework.6.4.4\build\EntityFramework.targets" Condition="Exists('..\packages\EntityFramework.6.4.4\build\EntityFramework.targets')" />
|
||||||
|
<Import Project="..\packages\Stub.System.Data.SQLite.Core.NetFramework.1.0.117.0\build\net46\Stub.System.Data.SQLite.Core.NetFramework.targets" Condition="Exists('..\packages\Stub.System.Data.SQLite.Core.NetFramework.1.0.117.0\build\net46\Stub.System.Data.SQLite.Core.NetFramework.targets')" />
|
||||||
</Project>
|
</Project>
|
||||||
@@ -0,0 +1,672 @@
|
|||||||
|
/// Author : Maxime Rohmer
|
||||||
|
/// Date : 30/05/2023
|
||||||
|
/// File : Window.cs
|
||||||
|
/// Brief : Default Window object that is mainly expected to be inherited.
|
||||||
|
/// Version : Alpha 1.0
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using System.Drawing;
|
||||||
|
using System.IO;
|
||||||
|
using Tesseract;
|
||||||
|
using System.Text.RegularExpressions;
|
||||||
|
using System.Drawing.Drawing2D;
|
||||||
|
|
||||||
|
namespace TrackTrends
|
||||||
|
{
|
||||||
|
public class Window
|
||||||
|
{
|
||||||
|
public const string STRING_DEBUG_FOLDER = "./GetString";
|
||||||
|
public const string LAPTIME_DEBUG_FOLDER = "./LapTime";
|
||||||
|
public const string GAPTOLEADER_DEBUG_FOLDER = "./Gap";
|
||||||
|
public const string SECTOR1_DEBUG_FOLDER = "./Sector1";
|
||||||
|
public const string SECTOR2_DEBUG_FOLDER = "./Sector2";
|
||||||
|
public const string SECTOR3_DEBUG_FOLDER = "./Sector3";
|
||||||
|
public const string DRS_DEBUG_FOLDER = "./DRS";
|
||||||
|
public const string TYRE_DEBUG_FOLDER = "./Tyre";
|
||||||
|
|
||||||
|
private Rectangle _bounds;
|
||||||
|
private Bitmap _image;
|
||||||
|
private string _name;
|
||||||
|
protected TesseractEngine Engine;
|
||||||
|
public Rectangle Bounds { get => _bounds; private set => _bounds = value; }
|
||||||
|
public Bitmap Image { get => _image; set => _image = value; }
|
||||||
|
public string Name { get => _name; protected set => _name = value; }
|
||||||
|
//This will have to be changed if you want to make it run on your machine
|
||||||
|
public static DirectoryInfo TESS_DATA_FOLDER = new DirectoryInfo(@"C:\Users\Moi\Pictures\SeleniumScreens\TessData");
|
||||||
|
//Debug
|
||||||
|
public static Random rnd = new Random();
|
||||||
|
|
||||||
|
public Bitmap WindowImage
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
//This little trickery lets you have the image that the window sees
|
||||||
|
Bitmap sample = new Bitmap(Bounds.Width, Bounds.Height);
|
||||||
|
Graphics g = Graphics.FromImage(sample);
|
||||||
|
g.DrawImage(Image, new Rectangle(0, 0, sample.Width, sample.Height), Bounds, GraphicsUnit.Pixel);
|
||||||
|
return sample;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/// <summary>
|
||||||
|
/// Creates a new Window
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="image">The image of the parent zone</param>
|
||||||
|
/// <param name="bounds">The position and size of the window</param>
|
||||||
|
/// <param name="generateEngine">Does the window need to generate a tesseract engine (takes time and ressources)</param>
|
||||||
|
public Window(Bitmap image, Rectangle bounds, bool generateEngine = true)
|
||||||
|
{
|
||||||
|
Image = image;
|
||||||
|
Bounds = bounds;
|
||||||
|
if (generateEngine)
|
||||||
|
{
|
||||||
|
Engine = new TesseractEngine(TESS_DATA_FOLDER.FullName, "eng", EngineMode.Default);
|
||||||
|
Engine.DefaultPageSegMode = PageSegMode.SingleLine;
|
||||||
|
}
|
||||||
|
|
||||||
|
//DEBUG
|
||||||
|
/*
|
||||||
|
if (!Directory.Exists(STRING_DEBUG_FOLDER))
|
||||||
|
Directory.CreateDirectory(STRING_DEBUG_FOLDER);
|
||||||
|
if (!Directory.Exists(LAPTIME_DEBUG_FOLDER))
|
||||||
|
Directory.CreateDirectory(LAPTIME_DEBUG_FOLDER);
|
||||||
|
if (!Directory.Exists(GAPTOLEADER_DEBUG_FOLDER))
|
||||||
|
Directory.CreateDirectory(GAPTOLEADER_DEBUG_FOLDER);
|
||||||
|
if (!Directory.Exists(SECTOR1_DEBUG_FOLDER))
|
||||||
|
Directory.CreateDirectory(SECTOR1_DEBUG_FOLDER);
|
||||||
|
if (!Directory.Exists(SECTOR2_DEBUG_FOLDER))
|
||||||
|
Directory.CreateDirectory(SECTOR2_DEBUG_FOLDER);
|
||||||
|
if (!Directory.Exists(SECTOR3_DEBUG_FOLDER))
|
||||||
|
Directory.CreateDirectory(SECTOR3_DEBUG_FOLDER);
|
||||||
|
if (!Directory.Exists(DRS_DEBUG_FOLDER))
|
||||||
|
Directory.CreateDirectory(DRS_DEBUG_FOLDER);
|
||||||
|
if (!Directory.Exists(TYRE_DEBUG_FOLDER))
|
||||||
|
Directory.CreateDirectory(TYRE_DEBUG_FOLDER);
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
/// <summary>
|
||||||
|
/// Method that will have to be used by the childrens to let the model make them decode the images they have
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>Returns an object because we dont know what kind of return it will be</returns>
|
||||||
|
public virtual Object DecodePng()
|
||||||
|
{
|
||||||
|
return "NaN";
|
||||||
|
}
|
||||||
|
/// <summary>
|
||||||
|
/// Method that will have to be used by the childrens to let the model make them decode the images they have
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="driverList">This is a list of the different possible drivers in the race. It should not be too big but NEVER be too short</param>
|
||||||
|
/// <returns>Returns an object because we dont know what kind of return it will be</returns>
|
||||||
|
public virtual Object DecodePng(List<string> driverList)
|
||||||
|
{
|
||||||
|
return "NaN";
|
||||||
|
}
|
||||||
|
/// <summary>
|
||||||
|
/// This converts an image into a byte[]. It can be usefull when doing unsafe stuff. Use at your own risks
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="inputImage">The image you want to convert</param>
|
||||||
|
/// <returns>A byte array containing the image informations</returns>
|
||||||
|
public static byte[] ImageToByte(Image inputImage)
|
||||||
|
{
|
||||||
|
using (var stream = new MemoryStream())
|
||||||
|
{
|
||||||
|
inputImage.Save(stream, System.Drawing.Imaging.ImageFormat.Png);
|
||||||
|
return stream.ToArray();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/// <summary>
|
||||||
|
/// This method is used to recover a time from a PNG using Tesseract OCR
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="windowImage">The image where the text is</param>
|
||||||
|
/// <param name="windowType">The type of window it is</param>
|
||||||
|
/// <param name="Engine">The Tesseract Engine</param>
|
||||||
|
/// <returns>The time in milliseconds</returns>
|
||||||
|
public static int GetTimeFromPng(Bitmap image, OcrImage.WindowType windowType, TesseractEngine Engine)
|
||||||
|
{
|
||||||
|
//Kind of a big method but it has a lot of error handling and has to work with three special cases
|
||||||
|
string rawResult = "";
|
||||||
|
int result = 0;
|
||||||
|
|
||||||
|
//Debug
|
||||||
|
int salt = rnd.Next(0, 999999);
|
||||||
|
|
||||||
|
switch (windowType)
|
||||||
|
{
|
||||||
|
case OcrImage.WindowType.Sector:
|
||||||
|
//The usual sector is in this form : 33.456
|
||||||
|
Engine.SetVariable("tessedit_char_whitelist", "0123456789.");
|
||||||
|
break;
|
||||||
|
case OcrImage.WindowType.LapTime:
|
||||||
|
//The usual Lap time is in this form : 1:45:345
|
||||||
|
Engine.SetVariable("tessedit_char_whitelist", "0123456789.:");
|
||||||
|
break;
|
||||||
|
case OcrImage.WindowType.Gap:
|
||||||
|
//The usual Gap is in this form : + 34.567
|
||||||
|
Engine.SetVariable("tessedit_char_whitelist", "0123456789.+");
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
Engine.SetVariable("tessedit_char_whitelist", "");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Bitmap enhancedImage = new OcrImage(image).Enhance(salt, windowType);
|
||||||
|
|
||||||
|
var tessImage = Pix.LoadFromMemory(ImageToByte(enhancedImage));
|
||||||
|
|
||||||
|
Page page = Engine.Process(tessImage);
|
||||||
|
Graphics g = Graphics.FromImage(enhancedImage);
|
||||||
|
// Get the iterator for the page layout
|
||||||
|
using (var iter = page.GetIterator())
|
||||||
|
{
|
||||||
|
// Loop over the elements of the page layout
|
||||||
|
iter.Begin();
|
||||||
|
do
|
||||||
|
{
|
||||||
|
// Get the text for the current element
|
||||||
|
try
|
||||||
|
{
|
||||||
|
rawResult += iter.GetText(PageIteratorLevel.Word);
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
//nothing we just dont add it if its not a number
|
||||||
|
}
|
||||||
|
} while (iter.Next(PageIteratorLevel.Word));
|
||||||
|
}
|
||||||
|
|
||||||
|
List<string> rawNumbers;
|
||||||
|
|
||||||
|
//In the gaps we can find '+' but we dont care about it its redondant a driver will never be - something
|
||||||
|
if (windowType == OcrImage.WindowType.Gap)
|
||||||
|
rawResult = Regex.Replace(rawResult, "[^0-9.:]", "");
|
||||||
|
|
||||||
|
//Splits into minuts seconds miliseconds
|
||||||
|
rawNumbers = rawResult.Split('.', ':').ToList<string>();
|
||||||
|
//removes any empty cells (tho this usually sign of a really bad OCR implementation tbh will have to be fixed higher in the chian)
|
||||||
|
rawNumbers.RemoveAll(x => ((string)x) == "");
|
||||||
|
|
||||||
|
int minuts = 0;
|
||||||
|
int seconds = 0;
|
||||||
|
int miliseconds = 0;
|
||||||
|
switch (windowType)
|
||||||
|
{
|
||||||
|
case OcrImage.WindowType.Sector:
|
||||||
|
//Usually there is supposed to be only 2 parts.
|
||||||
|
if (rawNumbers.Count == 2)
|
||||||
|
{
|
||||||
|
//The perect case
|
||||||
|
try
|
||||||
|
{
|
||||||
|
seconds = Convert.ToInt32(rawNumbers[0].ToString());
|
||||||
|
miliseconds = Convert.ToInt32(rawNumbers[1].ToString());
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
Console.WriteLine("Sector time convertion failed");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (rawNumbers.Count == 1)
|
||||||
|
{
|
||||||
|
//Here it is a little harder... Usually its because a '.' has been overlooked or interpreted as a number
|
||||||
|
|
||||||
|
if (rawNumbers[0].Length == 6)
|
||||||
|
{
|
||||||
|
//The '.' has been understood as a number
|
||||||
|
try
|
||||||
|
{
|
||||||
|
seconds = Convert.ToInt32(rawNumbers[0][0].ToString() + rawNumbers[0][1].ToString());
|
||||||
|
miliseconds = Convert.ToInt32(rawNumbers[0][3].ToString() + rawNumbers[0][4].ToString() + rawNumbers[0][5].ToString());
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
Console.WriteLine("Sector time convertion failed");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (rawNumbers[0].Length == 5)
|
||||||
|
{
|
||||||
|
//The '.' has been overlooked
|
||||||
|
try
|
||||||
|
{
|
||||||
|
seconds = Convert.ToInt32(rawNumbers[0][0].ToString() + rawNumbers[0][1].ToString());
|
||||||
|
miliseconds = Convert.ToInt32(rawNumbers[0][2].ToString() + rawNumbers[0][3].ToString() + rawNumbers[0][4].ToString());
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
Console.WriteLine("Sector time convertion failed");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Console.WriteLine("Sector time convertion failed");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
//The OCR detected more than 1 '.' wich is concerning because that means that something went really wrong
|
||||||
|
Console.WriteLine("Sector time convertion failed");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
result = 0;
|
||||||
|
result += seconds * 1000;
|
||||||
|
result += miliseconds;
|
||||||
|
break;
|
||||||
|
case OcrImage.WindowType.LapTime:
|
||||||
|
|
||||||
|
if (rawNumbers.Count == 3)
|
||||||
|
{
|
||||||
|
//The normal way
|
||||||
|
try
|
||||||
|
{
|
||||||
|
minuts = Convert.ToInt32(rawNumbers[0].ToString());
|
||||||
|
seconds = Convert.ToInt32(rawNumbers[1].ToString());
|
||||||
|
miliseconds = Convert.ToInt32(rawNumbers[2].ToString());
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
Console.WriteLine("Lap time convertion failed");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (rawNumbers.Count == 2)
|
||||||
|
{
|
||||||
|
//Either the ':' or the '.' has been missinterpreted
|
||||||
|
if (rawNumbers[0].Length > rawNumbers[1].Length)
|
||||||
|
{
|
||||||
|
//The ':' has been missinterpreted
|
||||||
|
if (rawNumbers[0].Length == 3)
|
||||||
|
{
|
||||||
|
//It has been forgotten
|
||||||
|
try
|
||||||
|
{
|
||||||
|
minuts = Convert.ToInt32(rawNumbers[0][0].ToString());
|
||||||
|
seconds = Convert.ToInt32(rawNumbers[0][1].ToString() + rawNumbers[0][2].ToString());
|
||||||
|
miliseconds = Convert.ToInt32(rawNumbers[1]);
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
Console.WriteLine("Lap time convertion failed");
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (rawNumbers[0].Length == 4)
|
||||||
|
{
|
||||||
|
//I has been translated into an other number
|
||||||
|
try
|
||||||
|
{
|
||||||
|
minuts = Convert.ToInt32(rawNumbers[0][0].ToString());
|
||||||
|
seconds = Convert.ToInt32(rawNumbers[0][2].ToString() + rawNumbers[0][3].ToString());
|
||||||
|
miliseconds = Convert.ToInt32(rawNumbers[1]);
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
Console.WriteLine("Lap time convertion failed");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
//This could happen if the ':' has been missinterpreted with a lap time of over 9 minuts (HIGLY IMPROBABLE)
|
||||||
|
Console.WriteLine("Lap time convertion failed");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
//The '.' has been missinterpreted
|
||||||
|
if (rawNumbers[1].Length == 5)
|
||||||
|
{
|
||||||
|
//It has been forgotten
|
||||||
|
minuts = Convert.ToInt32(rawNumbers[0].ToString());
|
||||||
|
seconds = Convert.ToInt32(rawNumbers[1][0].ToString() + rawNumbers[1][1].ToString());
|
||||||
|
miliseconds = Convert.ToInt32(rawNumbers[1][2].ToString() + rawNumbers[1][3].ToString() + rawNumbers[1][4].ToString());
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (rawNumbers[1].Length == 6)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
//It has been interpreted as a number
|
||||||
|
minuts = Convert.ToInt32(rawNumbers[0].ToString());
|
||||||
|
seconds = Convert.ToInt32(rawNumbers[1][0].ToString() + rawNumbers[1][1].ToString());
|
||||||
|
miliseconds = Convert.ToInt32(rawNumbers[1][3].ToString() + rawNumbers[1][4].ToString() + rawNumbers[1][5].ToString());
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
//It can happen and to be honest I dont know how to fix it
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Console.WriteLine("Lap time convertion failed");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (rawNumbers.Count == 1)
|
||||||
|
{
|
||||||
|
//Both the '.' and the ':' have been missinterpreted
|
||||||
|
if (rawNumbers[0].Length == 6)
|
||||||
|
{
|
||||||
|
//The just all have been forgotten
|
||||||
|
try
|
||||||
|
{
|
||||||
|
minuts = Convert.ToInt32(rawNumbers[0][0].ToString());
|
||||||
|
seconds = Convert.ToInt32(rawNumbers[0][1].ToString() + rawNumbers[0][2].ToString());
|
||||||
|
miliseconds = Convert.ToInt32(rawNumbers[0][3].ToString() + rawNumbers[0][4].ToString() + rawNumbers[0][5].ToString());
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
Console.WriteLine("Lap time convertion failed");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (rawNumbers[0].Length == 7)
|
||||||
|
{
|
||||||
|
//The '.' or ':' have been interpreted as a number (usually the ':')
|
||||||
|
try
|
||||||
|
{
|
||||||
|
minuts = Convert.ToInt32(rawNumbers[0][0].ToString());
|
||||||
|
seconds = Convert.ToInt32(rawNumbers[0][2].ToString() + rawNumbers[0][3].ToString());
|
||||||
|
miliseconds = Convert.ToInt32(rawNumbers[0][4].ToString() + rawNumbers[0][5].ToString() + rawNumbers[0][6].ToString());
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
Console.WriteLine("Lap time convertion failed");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (rawNumbers[0].Length == 8)
|
||||||
|
{
|
||||||
|
//Both have been interpreted as a number
|
||||||
|
try
|
||||||
|
{
|
||||||
|
minuts = Convert.ToInt32(rawNumbers[0][0].ToString());
|
||||||
|
seconds = Convert.ToInt32(rawNumbers[0][2].ToString() + rawNumbers[0][3].ToString());
|
||||||
|
miliseconds = Convert.ToInt32(rawNumbers[0][5].ToString() + rawNumbers[0][6].ToString() + rawNumbers[0][7].ToString());
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
Console.WriteLine("Lap time convertion failed");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
//I dont know what could have happened
|
||||||
|
Console.WriteLine("Lap time convertion failed");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
//I dont know what could have happened
|
||||||
|
Console.WriteLine("Lap time convertion failed");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
result = 0;
|
||||||
|
result += minuts * 60 * 1000;
|
||||||
|
result += seconds * 1000;
|
||||||
|
result += miliseconds;
|
||||||
|
break;
|
||||||
|
case OcrImage.WindowType.Gap:
|
||||||
|
if (rawNumbers.Count == 2)
|
||||||
|
{
|
||||||
|
// This should be the x.xxx or a missed x:xx.xxx
|
||||||
|
if (rawNumbers[0].Length > 2)
|
||||||
|
{
|
||||||
|
//Its a missed x:xx.xxx
|
||||||
|
if (rawNumbers[0].Length == 3)
|
||||||
|
{
|
||||||
|
//It forgot the ":"
|
||||||
|
try
|
||||||
|
{
|
||||||
|
minuts = Convert.ToInt32(rawNumbers[0][0].ToString());
|
||||||
|
seconds = Convert.ToInt32(rawNumbers[0][1].ToString() + rawNumbers[0][2].ToString());
|
||||||
|
miliseconds = Convert.ToInt32(rawNumbers[1]);
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
Console.WriteLine("Gap to leader convertion failed");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
//The ":" has been mistaken as a number
|
||||||
|
if (rawNumbers[0].Length == 4)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
minuts = Convert.ToInt32(rawNumbers[0][0].ToString());
|
||||||
|
seconds = Convert.ToInt32(rawNumbers[0][2].ToString() + rawNumbers[0][3].ToString());
|
||||||
|
miliseconds = Convert.ToInt32(rawNumbers[1]);
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
Console.WriteLine("Gap to leader convertion failed");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Console.WriteLine("Gap to leader convertion failed");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
//It should be a normal x.xxx or xx.xxx
|
||||||
|
try
|
||||||
|
{
|
||||||
|
seconds = Convert.ToInt32(rawNumbers[0].ToString());
|
||||||
|
miliseconds = Convert.ToInt32(rawNumbers[1].ToString());
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
Console.WriteLine("Gap to leader convertion failed");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (rawNumbers.Count == 1)
|
||||||
|
{
|
||||||
|
//can be anything depending on the size of the string
|
||||||
|
if (rawNumbers[0].Length == 4)
|
||||||
|
{
|
||||||
|
//We just missed the '.'
|
||||||
|
try
|
||||||
|
{
|
||||||
|
seconds = Convert.ToInt32(rawNumbers[0][0].ToString());
|
||||||
|
miliseconds = Convert.ToInt32(rawNumbers[0][1].ToString() + rawNumbers[0][2].ToString() + rawNumbers[0][3].ToString());
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
Console.WriteLine("Gap to leader convertion failed");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (rawNumbers[0].Length == 5)
|
||||||
|
{
|
||||||
|
//We just missed the '.'
|
||||||
|
try
|
||||||
|
{
|
||||||
|
seconds = Convert.ToInt32(rawNumbers[0][0].ToString() + rawNumbers[0][1].ToString());
|
||||||
|
miliseconds = Convert.ToInt32(rawNumbers[0][2].ToString() + rawNumbers[0][3].ToString() + rawNumbers[0][4].ToString());
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
Console.WriteLine("Gap to leader convertion failed");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//There is just too much possibilities that it would be stupid to try and tell them appart so for now im leaving that as just an error
|
||||||
|
Console.WriteLine("Gap to leader convertion failed");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (rawNumbers.Count == 3)
|
||||||
|
{
|
||||||
|
// This should be the x:xx.xxx
|
||||||
|
try
|
||||||
|
{
|
||||||
|
minuts = Convert.ToInt32(rawNumbers[0].ToString());
|
||||||
|
seconds = Convert.ToInt32(rawNumbers[1].ToString());
|
||||||
|
miliseconds = Convert.ToInt32(rawNumbers[2].ToString());
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
Console.WriteLine("Gap to leader convertion failed");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
result = 0;
|
||||||
|
result += minuts * 60 * 1000;
|
||||||
|
result += seconds * 1000;
|
||||||
|
result += miliseconds;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
try
|
||||||
|
{
|
||||||
|
result = Convert.ToInt32(rawNumbers[0].ToString());
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
result = 0;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
page.Dispose();
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
/// <summary>
|
||||||
|
/// Method that recovers strings from an image using Tesseract OCR
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="WindowImage">The image of the window that contains text</param>
|
||||||
|
/// <param name="Engine">The Tesseract engine</param>
|
||||||
|
/// <param name="allowedChars">The list of allowed chars</param>
|
||||||
|
/// <param name="windowType">The type of window the text is on. Depending on the context the OCR will behave differently</param>
|
||||||
|
/// <returns>the string it found</returns>
|
||||||
|
public static string GetStringFromPng(Bitmap image, TesseractEngine Engine, string allowedChars = "", OcrImage.WindowType windowType = OcrImage.WindowType.Text)
|
||||||
|
{
|
||||||
|
string result = "";
|
||||||
|
|
||||||
|
//Debug
|
||||||
|
int salt = rnd.Next(0, 999999);
|
||||||
|
|
||||||
|
Engine.SetVariable("tessedit_char_whitelist", allowedChars);
|
||||||
|
|
||||||
|
Bitmap rawData = image;
|
||||||
|
Bitmap enhancedImage = new OcrImage(rawData).Enhance(salt, windowType);
|
||||||
|
|
||||||
|
Page page = Engine.Process(enhancedImage);
|
||||||
|
using (var iter = page.GetIterator())
|
||||||
|
{
|
||||||
|
iter.Begin();
|
||||||
|
do
|
||||||
|
{
|
||||||
|
result += iter.GetText(PageIteratorLevel.Word);
|
||||||
|
} while (iter.Next(PageIteratorLevel.Word));
|
||||||
|
}
|
||||||
|
page.Dispose();
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
/// <summary>
|
||||||
|
/// Get a smaller image from a bigger one
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="inputBitmap">The big bitmap you want to get a part of</param>
|
||||||
|
/// <param name="newBitmapDimensions">The dimensions of the new bitmap</param>
|
||||||
|
/// <returns>The little bitmap</returns>
|
||||||
|
protected Bitmap GetSmallBitmapFromBigOne(Bitmap inputBitmap, Rectangle newBitmapDimensions)
|
||||||
|
{
|
||||||
|
Bitmap sample = new Bitmap(newBitmapDimensions.Width, newBitmapDimensions.Height);
|
||||||
|
Graphics g = Graphics.FromImage(sample);
|
||||||
|
g.DrawImage(inputBitmap, new Rectangle(0, 0, sample.Width, sample.Height), newBitmapDimensions, GraphicsUnit.Pixel);
|
||||||
|
return sample;
|
||||||
|
}
|
||||||
|
/// <summary>
|
||||||
|
/// Returns the closest string from a list of options
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="options">an array of all the possibilities</param>
|
||||||
|
/// <param name="testString">the string you want to compare</param>
|
||||||
|
/// <returns>The closest option</returns>
|
||||||
|
protected static string FindClosestMatch(List<string> options, string testString)
|
||||||
|
{
|
||||||
|
var closestMatch = "";
|
||||||
|
var closestDistance = int.MaxValue;
|
||||||
|
|
||||||
|
foreach (var item in options)
|
||||||
|
{
|
||||||
|
var distance = LevenshteinDistance(item, testString);
|
||||||
|
if (distance < closestDistance)
|
||||||
|
{
|
||||||
|
closestMatch = item;
|
||||||
|
closestDistance = distance;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return closestMatch;
|
||||||
|
}
|
||||||
|
//This method has been generated with the help of ChatGPT
|
||||||
|
/// <summary>
|
||||||
|
/// Method that computes a score of distance between two strings
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="string1">The first string (order irrelevant)</param>
|
||||||
|
/// <param name="string2">The second string (order irrelevant)</param>
|
||||||
|
/// <returns>The levenshtein distance</returns>
|
||||||
|
protected static int LevenshteinDistance(string string1, string string2)
|
||||||
|
{
|
||||||
|
if (string.IsNullOrEmpty(string1))
|
||||||
|
{
|
||||||
|
return string.IsNullOrEmpty(string2) ? 0 : string2.Length;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (string.IsNullOrEmpty(string2))
|
||||||
|
{
|
||||||
|
return string.IsNullOrEmpty(string1) ? 0 : string1.Length;
|
||||||
|
}
|
||||||
|
|
||||||
|
var d = new int[string1.Length + 1, string2.Length + 1];
|
||||||
|
for (var i = 0; i <= string1.Length; i++)
|
||||||
|
{
|
||||||
|
d[i, 0] = i;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (var j = 0; j <= string2.Length; j++)
|
||||||
|
{
|
||||||
|
d[0, j] = j;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (var i = 1; i <= string1.Length; i++)
|
||||||
|
{
|
||||||
|
for (var j = 1; j <= string2.Length; j++)
|
||||||
|
{
|
||||||
|
var cost = (string1[i - 1] == string2[j - 1]) ? 0 : 1;
|
||||||
|
d[i, j] = Math.Min(Math.Min(d[i - 1, j] + 1, d[i, j - 1] + 1), d[i - 1, j - 1] + cost);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return d[string1.Length, string2.Length];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,11 +1,17 @@
|
|||||||
using System;
|
/// Author : Maxime Rohmer
|
||||||
|
/// Date : 30/05/2023
|
||||||
|
/// File : Zone.cs
|
||||||
|
/// Brief : Class that contains all the methods and infos for a zone. This is designed to be potentially be inherited.
|
||||||
|
/// Version : Alpha 1.0
|
||||||
|
|
||||||
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Drawing;
|
using System.Drawing;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
namespace Test_Merge
|
namespace TrackTrends
|
||||||
{
|
{
|
||||||
public class Zone
|
public class Zone
|
||||||
{
|
{
|
||||||
@@ -13,6 +19,7 @@ namespace Test_Merge
|
|||||||
private List<Zone> _zones;
|
private List<Zone> _zones;
|
||||||
private List<Window> _windows;
|
private List<Window> _windows;
|
||||||
private Bitmap _image;
|
private Bitmap _image;
|
||||||
|
private string _name;
|
||||||
|
|
||||||
public Bitmap ZoneImage
|
public Bitmap ZoneImage
|
||||||
{
|
{
|
||||||
@@ -31,7 +38,7 @@ namespace Test_Merge
|
|||||||
set
|
set
|
||||||
{
|
{
|
||||||
//It automatically sets the image for the contained windows and zones
|
//It automatically sets the image for the contained windows and zones
|
||||||
_image = Image;
|
_image = value;
|
||||||
foreach (Window w in Windows)
|
foreach (Window w in Windows)
|
||||||
{
|
{
|
||||||
w.Image = ZoneImage;
|
w.Image = ZoneImage;
|
||||||
@@ -42,15 +49,21 @@ namespace Test_Merge
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public Rectangle Bounds { get => _bounds; protected set => _bounds = value; }
|
public Rectangle Bounds { get => _bounds; protected set => _bounds = value; }
|
||||||
public List<Zone> Zones { get => _zones; protected set => _zones = value; }
|
public List<Zone> Zones { get => _zones; protected set => _zones = value; }
|
||||||
public List<Window> Windows { get => _windows; protected set => _windows = value; }
|
public List<Window> Windows { get => _windows; protected set => _windows = value; }
|
||||||
|
public string Name { get => _name; protected set => _name = value; }
|
||||||
public Zone(Bitmap image, Rectangle bounds)
|
/// <summary>
|
||||||
|
/// Creates a new Zone
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="image">Image of the parent zone</param>
|
||||||
|
/// <param name="bounds">The position and size of the zone</param>
|
||||||
|
/// <param name="name">THe name of the zone (usefull for the JSON formatting)</param>
|
||||||
|
public Zone(Bitmap image, Rectangle bounds, string name)
|
||||||
{
|
{
|
||||||
Windows = new List<Window>();
|
Windows = new List<Window>();
|
||||||
Zones = new List<Zone>();
|
Zones = new List<Zone>();
|
||||||
|
Name = name;
|
||||||
|
|
||||||
//You cant set the image in the CTOR because the processing is impossible at first initiation
|
//You cant set the image in the CTOR because the processing is impossible at first initiation
|
||||||
_image = image;
|
_image = image;
|
||||||
@@ -77,108 +90,80 @@ namespace Test_Merge
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="driverList">A list of all the driver in the race to help with text recognition</param>
|
/// <param name="driverList">A list of all the driver in the race to help with text recognition</param>
|
||||||
/// <returns>A driver data object that contains all the infos about a driver</returns>
|
/// <returns>A driver data object that contains all the infos about a driver</returns>
|
||||||
public virtual async Task<DriverData> Decode(List<string> driverList)
|
public virtual DriverData Decode(List<string> driverList)
|
||||||
{
|
{
|
||||||
int sectorCount = 0;
|
int sectorCount = 0;
|
||||||
DriverData result = new DriverData();
|
DriverData result = new DriverData();
|
||||||
Parallel.ForEach(Windows, async w =>
|
foreach(Window w in Windows)
|
||||||
{
|
{
|
||||||
// A switch would be prettier but I dont think its supported in this C# version
|
// A switch would be prettier but I dont think its supported in this C# version
|
||||||
if (w is DriverNameWindow)
|
if (w is DriverNameWindow)
|
||||||
result.Name = (string)await (w as DriverNameWindow).DecodePng(driverList);
|
result.Name = (string)(w as DriverNameWindow).DecodePng(driverList);
|
||||||
if (w is DriverDrsWindow)
|
if (w is DriverDrsWindow)
|
||||||
result.DRS = (bool)await (w as DriverDrsWindow).DecodePng();
|
result.DRS = (bool)(w as DriverDrsWindow).DecodePng();
|
||||||
if (w is DriverGapToLeaderWindow)
|
if (w is DriverGapToLeaderWindow)
|
||||||
result.GapToLeader = (int)await (w as DriverGapToLeaderWindow).DecodePng();
|
result.GapToLeader = (int)(w as DriverGapToLeaderWindow).DecodePng();
|
||||||
if (w is DriverLapTimeWindow)
|
if (w is DriverLapTimeWindow)
|
||||||
result.LapTime = (int)await (w as DriverLapTimeWindow).DecodePng();
|
result.LapTime = (int)(w as DriverLapTimeWindow).DecodePng();
|
||||||
if (w is DriverPositionWindow)
|
if (w is DriverPositionWindow)
|
||||||
result.Position = (int)await (w as DriverPositionWindow).DecodePng();
|
result.Position = (int)(w as DriverPositionWindow).DecodePng();
|
||||||
if (w is DriverSectorWindow)
|
if (w is DriverSectorWindow)
|
||||||
{
|
{
|
||||||
sectorCount++;
|
sectorCount++;
|
||||||
if (sectorCount == 1)
|
if (sectorCount == 1)
|
||||||
result.Sector1 = (int)await (w as DriverSectorWindow).DecodePng();
|
result.Sector1 = (int)(w as DriverSectorWindow).DecodePng();
|
||||||
if (sectorCount == 2)
|
if (sectorCount == 2)
|
||||||
result.Sector2 = (int)await (w as DriverSectorWindow).DecodePng();
|
result.Sector2 = (int)(w as DriverSectorWindow).DecodePng();
|
||||||
if (sectorCount == 3)
|
if (sectorCount == 3)
|
||||||
result.Sector3 = (int)await (w as DriverSectorWindow).DecodePng();
|
result.Sector3 = (int)(w as DriverSectorWindow).DecodePng();
|
||||||
}
|
}
|
||||||
if (w is DriverTyresWindow)
|
if (w is DriverTyresWindow)
|
||||||
result.CurrentTyre = (Tyre)await (w as DriverTyresWindow).DecodePng();
|
result.CurrentTyre = (Tyre)(w as DriverTyresWindow).DecodePng();
|
||||||
});
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
public virtual Bitmap Draw()
|
public virtual Bitmap Draw()
|
||||||
{
|
{
|
||||||
Image img = Image;
|
Bitmap img;
|
||||||
|
|
||||||
|
//If its the main zone we want to see everything
|
||||||
|
if (Zones.Count > 0)
|
||||||
|
{
|
||||||
|
img = Image;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
img = ZoneImage;
|
||||||
|
}
|
||||||
|
|
||||||
Graphics g = Graphics.FromImage(img);
|
Graphics g = Graphics.FromImage(img);
|
||||||
|
|
||||||
|
//If its the main zone we need to visualize the Zone bounds displayed
|
||||||
|
if (Zones.Count > 0)
|
||||||
|
g.DrawRectangle(new Pen(new SolidBrush(Color.FromArgb(249,194,46)), 5), Bounds);
|
||||||
|
|
||||||
foreach (Zone z in Zones)
|
foreach (Zone z in Zones)
|
||||||
{
|
{
|
||||||
Rectangle newBounds = new Rectangle(z.Bounds.X,z.Bounds.Y + Bounds.Y,z.Bounds.Width,z.Bounds.Height);
|
Rectangle newBounds = new Rectangle(z.Bounds.X, z.Bounds.Y + Bounds.Y, z.Bounds.Width, z.Bounds.Height);
|
||||||
g.DrawRectangle(Pens.Red, newBounds);
|
g.DrawRectangle(new Pen(new SolidBrush(Color.FromArgb(249, 194, 46)), 5), newBounds);
|
||||||
}
|
}
|
||||||
foreach (Window w in Windows)
|
foreach (Window w in Windows)
|
||||||
{
|
{
|
||||||
g.DrawRectangle(Pens.Blue, w.Bounds);
|
g.DrawRectangle(new Pen(new SolidBrush(Color.FromArgb(252, 252, 252)), 5), w.Bounds);
|
||||||
}
|
}
|
||||||
return (Bitmap)img;
|
return img;
|
||||||
}
|
}
|
||||||
public virtual string ToJSON()
|
public void ResetZones()
|
||||||
{
|
{
|
||||||
string result = "";
|
Zones.Clear();
|
||||||
result += "\"" + "Zone" + "\":{" + Environment.NewLine;
|
|
||||||
result += "\t" + "\"x\":" + Bounds.X + "," + Environment.NewLine;
|
|
||||||
result += "\t" + "\"y\":" + Bounds.Y + "," + Environment.NewLine;
|
|
||||||
result += "\t" + "\"width\":" + Bounds.Width + "," + Environment.NewLine;
|
|
||||||
result += "\t" + "\"height\":" + Bounds.Height;
|
|
||||||
|
|
||||||
if (Windows.Count != 0)
|
|
||||||
{
|
|
||||||
result += "," + Environment.NewLine;
|
|
||||||
|
|
||||||
result += "\t" + "\"Windows\":[" + Environment.NewLine;
|
|
||||||
result += "\t\t{" + Environment.NewLine;
|
|
||||||
int Wcount = 0;
|
|
||||||
foreach (Window w in Windows)
|
|
||||||
{
|
|
||||||
result += "\t\t" + w.ToJSON();
|
|
||||||
Wcount++;
|
|
||||||
if (Wcount != Windows.Count)
|
|
||||||
result += ",";
|
|
||||||
}
|
}
|
||||||
result += "\t\t}" + Environment.NewLine;
|
public void ResetWindows()
|
||||||
result += "\t" + "]" + Environment.NewLine;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
{
|
||||||
result += Environment.NewLine;
|
foreach (Zone z in Zones)
|
||||||
}
|
|
||||||
if (Zones.Count != 0)
|
|
||||||
{
|
{
|
||||||
result += "," + Environment.NewLine;
|
z.ResetWindows();
|
||||||
|
|
||||||
result += "\t" + "\"Zones\":[" + Environment.NewLine;
|
|
||||||
result += "\t\t{" + Environment.NewLine;
|
|
||||||
int Zcount = 0;
|
|
||||||
//foreach (Zone z in Zones)
|
|
||||||
//{
|
|
||||||
result += "\t\t" + Zones[0].ToJSON();
|
|
||||||
Zcount++;
|
|
||||||
if (Zcount != Zones.Count)
|
|
||||||
//result += ",";
|
|
||||||
//}
|
|
||||||
result += "\t\t}" + Environment.NewLine;
|
|
||||||
result += "\t" + "]" + Environment.NewLine;
|
|
||||||
}
|
}
|
||||||
else
|
Windows.Clear();
|
||||||
{
|
|
||||||
result += Environment.NewLine;
|
|
||||||
}
|
|
||||||
|
|
||||||
result += "}";
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Checks if the given Rectangle fits in the current zone
|
/// Checks if the given Rectangle fits in the current zone
|
||||||
@@ -1,10 +1,16 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<packages>
|
<packages>
|
||||||
|
<package id="EntityFramework" version="6.4.4" targetFramework="net472" />
|
||||||
<package id="Microsoft.Bcl.AsyncInterfaces" version="7.0.0" targetFramework="net472" />
|
<package id="Microsoft.Bcl.AsyncInterfaces" version="7.0.0" targetFramework="net472" />
|
||||||
<package id="Selenium.Firefox.WebDriver" version="0.27.0" targetFramework="net472" />
|
<package id="Selenium.Firefox.WebDriver" version="0.27.0" targetFramework="net472" />
|
||||||
<package id="Selenium.Support" version="4.8.2" targetFramework="net472" />
|
<package id="Selenium.Support" version="4.8.2" targetFramework="net472" />
|
||||||
<package id="Selenium.WebDriver" version="4.8.2" targetFramework="net472" />
|
<package id="Selenium.WebDriver" version="4.8.2" targetFramework="net472" />
|
||||||
|
<package id="Stub.System.Data.SQLite.Core.NetFramework" version="1.0.117.0" targetFramework="net472" />
|
||||||
<package id="System.Buffers" version="4.5.1" targetFramework="net472" />
|
<package id="System.Buffers" version="4.5.1" targetFramework="net472" />
|
||||||
|
<package id="System.Data.SQLite" version="1.0.117.0" targetFramework="net472" />
|
||||||
|
<package id="System.Data.SQLite.Core" version="1.0.117.0" targetFramework="net472" />
|
||||||
|
<package id="System.Data.SQLite.EF6" version="1.0.117.0" targetFramework="net472" />
|
||||||
|
<package id="System.Data.SQLite.Linq" version="1.0.117.0" targetFramework="net472" />
|
||||||
<package id="System.Memory" version="4.5.5" targetFramework="net472" />
|
<package id="System.Memory" version="4.5.5" targetFramework="net472" />
|
||||||
<package id="System.Numerics.Vectors" version="4.5.0" targetFramework="net472" />
|
<package id="System.Numerics.Vectors" version="4.5.0" targetFramework="net472" />
|
||||||
<package id="System.Runtime.CompilerServices.Unsafe" version="6.0.0" targetFramework="net472" />
|
<package id="System.Runtime.CompilerServices.Unsafe" version="6.0.0" targetFramework="net472" />
|
||||||
Reference in New Issue
Block a user