942 lines
35 KiB
C#
942 lines
35 KiB
C#
using AgroBase.Models.Modules;
|
|
using AgroBase.Services;
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using System.Drawing.Imaging;
|
|
using System.Drawing;
|
|
using System.Linq;
|
|
using System.Threading.Tasks;
|
|
using System.Windows.Forms;
|
|
using static AgroBase.Models.Enums;
|
|
using System.Drawing.Drawing2D;
|
|
using Microsoft.Win32;
|
|
using System.Reflection;
|
|
using CefSharp.WinForms;
|
|
using System.IO;
|
|
using System.Threading;
|
|
|
|
namespace AgroBase.Models
|
|
{
|
|
public class Variaveis
|
|
{
|
|
public static string CaminhoSistema { get; set; } = AppDomain.CurrentDomain.BaseDirectory;
|
|
public static string NomeAplicacao
|
|
{
|
|
get
|
|
{
|
|
Assembly assembly = Assembly.GetExecutingAssembly();
|
|
string name = assembly.GetName().Name;
|
|
return name.ToString();
|
|
}
|
|
}
|
|
public static string Versao
|
|
{
|
|
get
|
|
{
|
|
Assembly assembly = Assembly.GetExecutingAssembly();
|
|
Version version = assembly.GetName().Version;
|
|
return version.ToString();
|
|
}
|
|
}
|
|
public static string CaminhoLogsDispositivos { get; } = "Logs/";
|
|
public static string CaminhoOperacoes { get; } = "Operacoes/";
|
|
public static string CaminhoOperacoesSalvas { get; } = "OperacoesSalvas\\";
|
|
public static string CaminhoMapasConvertidos { get; } = "Mapas/";
|
|
public static string CaminhoParametros { get; } = "Parametros/";
|
|
public static string CaminhoModelos { get; } = "C:\\AgroBaseModels\\";
|
|
public static List<IDispositivosService> DispositivosConectados { get; set; } = new List<IDispositivosService>();
|
|
public static OperacaoModel OperacaoEmAndamento { get; set; } = new OperacaoModel(ModoOperacao.Manual);
|
|
public static MqttService MqttService { get; set; } = new MqttService("localhost", 1883);
|
|
public static LoRaService ConexaoLoRa = new LoRaService();
|
|
public static bool IsAgroMonitor
|
|
{
|
|
get
|
|
{
|
|
return CaminhoSistema.Contains("AgroMonitor");
|
|
}
|
|
}
|
|
}
|
|
|
|
public static class VariaveisPortas
|
|
{
|
|
public static int CameraSolo { get; } = 6522;
|
|
public static int CameraCaminho { get; } = 6544;
|
|
public static int Ethernet_AT { get; } = 8899;
|
|
public static int Ethernet_TCP { get; } = 8899;
|
|
}
|
|
|
|
public static class VariaveisEquipamento
|
|
{
|
|
public static double LarguraEsquerda { get; } = 40;
|
|
public static double LarguraDireita { get; } = 40;
|
|
public static double LarguraEquipamentoMm
|
|
{
|
|
get
|
|
{
|
|
return ((LarguraEsquerda + LarguraDireita + 20) * 10);
|
|
}
|
|
}
|
|
public static double PercentualTensaoBateriaMin { get; set; } = 25.0;
|
|
public static double PercentualReservatorioMin { get; set; } = 5.0;
|
|
public static double PercentualToleranciaPressaoLinha { get; set; } = 0.15;
|
|
public static double ReducaoDirecional { get; set; } = 20.0;
|
|
public static int RPM_Max_Roda
|
|
{
|
|
get
|
|
{
|
|
double RpmMax =
|
|
Variaveis.OperacaoEmAndamento.DispMvd != null ?
|
|
Variaveis.OperacaoEmAndamento.DispMvd.Dados.RPM_Max_MotorBLDC / RelacaoRPM :
|
|
100;
|
|
return (int)RpmMax;
|
|
}
|
|
}
|
|
public static double RelacaoRPM
|
|
{
|
|
get
|
|
{
|
|
double RelacaoRPM =
|
|
Variaveis.OperacaoEmAndamento.DispMvd != null ?
|
|
Variaveis.OperacaoEmAndamento.DispMvd.Dados.ReducaoMotorBLDC :
|
|
1;
|
|
return RelacaoRPM;
|
|
}
|
|
}
|
|
public static double DiametroRoda
|
|
{
|
|
get
|
|
{
|
|
double diametro =
|
|
Variaveis.OperacaoEmAndamento.DispMvd != null ?
|
|
Variaveis.OperacaoEmAndamento.DispMvd.Dados.DiametroRoda :
|
|
0.3556;
|
|
return diametro;
|
|
}
|
|
}
|
|
public static int TempoEntrePingsConexao { get; set; } = 10000;
|
|
public static Dictionary<AcaoFreio, int> AnguloFreio { get; } = new Dictionary<AcaoFreio, int>()
|
|
{
|
|
{ AcaoFreio.Ativar, 90 },
|
|
{ AcaoFreio.Desativar, 0 }
|
|
};
|
|
public static Dictionary<TipoMovimentoDirecional, int> AnguloMovimento { get; } = new Dictionary<TipoMovimentoDirecional, int>()
|
|
{
|
|
{ TipoMovimentoDirecional.RodasDianteiras, -1 },
|
|
{ TipoMovimentoDirecional.RodasTraseiras, -1 },
|
|
{ TipoMovimentoDirecional.MovimentoDiagonal, -1 },
|
|
{ TipoMovimentoDirecional.MovimentoArco, -1 },
|
|
{ TipoMovimentoDirecional.RotacionarNoEixo, 45 },
|
|
{ TipoMovimentoDirecional.MovimentoLateral, 90 },
|
|
{ TipoMovimentoDirecional.Diagnostico, 25 },
|
|
};
|
|
|
|
public static SensorSinaleiroComportamentoModel ComportamentoPorStatus(StatusOperacao? _status = null)
|
|
{
|
|
if (_status == null)
|
|
{
|
|
_status = Variaveis.OperacaoEmAndamento.StatusAtual;
|
|
}
|
|
|
|
SensorSinaleiroComportamentoModel comportamento = new SensorSinaleiroComportamentoModel()
|
|
{
|
|
statusLED = StatusLED.Apagado,
|
|
QtdPiscadas = 0,
|
|
TempoMs = 0,
|
|
PausaMs = 0,
|
|
};
|
|
|
|
switch (_status)
|
|
{
|
|
case StatusOperacao.Parametrizando:
|
|
{
|
|
comportamento = new SensorSinaleiroComportamentoModel()
|
|
{
|
|
statusLED = StatusLED.Aceso,
|
|
QtdPiscadas = 0,
|
|
TempoMs = 0,
|
|
PausaMs = 0,
|
|
};
|
|
break;
|
|
}
|
|
case StatusOperacao.NaoIniciado:
|
|
case StatusOperacao.Concluido:
|
|
{
|
|
comportamento = new SensorSinaleiroComportamentoModel()
|
|
{
|
|
statusLED = StatusLED.Apagado,
|
|
QtdPiscadas = 0,
|
|
TempoMs = 0,
|
|
PausaMs = 0,
|
|
};
|
|
break;
|
|
}
|
|
case StatusOperacao.Aguardando:
|
|
{
|
|
comportamento = new SensorSinaleiroComportamentoModel()
|
|
{
|
|
statusLED = StatusLED.Piscando,
|
|
QtdPiscadas = 1,
|
|
TempoMs = 1000,
|
|
PausaMs = 0,
|
|
};
|
|
break;
|
|
}
|
|
case StatusOperacao.Parado:
|
|
{
|
|
comportamento = new SensorSinaleiroComportamentoModel()
|
|
{
|
|
statusLED = StatusLED.Piscando,
|
|
QtdPiscadas = 1,
|
|
TempoMs = 2000,
|
|
PausaMs = 0,
|
|
};
|
|
break;
|
|
}
|
|
case StatusOperacao.EmAndamento:
|
|
{
|
|
comportamento = new SensorSinaleiroComportamentoModel()
|
|
{
|
|
statusLED = StatusLED.Piscando,
|
|
QtdPiscadas = 3,
|
|
TempoMs = 200,
|
|
PausaMs = 1000,
|
|
};
|
|
break;
|
|
}
|
|
}
|
|
|
|
return comportamento;
|
|
}
|
|
|
|
|
|
}
|
|
|
|
public static class VariaveisOperacao
|
|
{
|
|
public static double TempoManobra { get; set; } = 10;
|
|
public static double PercentualComErvas
|
|
{
|
|
get
|
|
{
|
|
if (!Variaveis.IsAgroMonitor && Variaveis.OperacaoEmAndamento.DispAtu != null)
|
|
{
|
|
return Variaveis.OperacaoEmAndamento.Sensoriamento.PercentualErvasTerreno / 100.0;
|
|
}
|
|
return 0.3;
|
|
}
|
|
}
|
|
public static double PercentualSemErvas
|
|
{
|
|
get
|
|
{
|
|
if (!Variaveis.IsAgroMonitor && Variaveis.OperacaoEmAndamento.DispAtu != null)
|
|
{
|
|
return (100.0 - Variaveis.OperacaoEmAndamento.Sensoriamento.PercentualErvasTerreno) / 100.0;
|
|
}
|
|
return 0.7;
|
|
}
|
|
}
|
|
public static GPSModel PosicaoBase { get; set; }
|
|
}
|
|
|
|
public static class FuncoesGlobais
|
|
{
|
|
public static void AddApplicationToStartup()
|
|
{
|
|
string appName = Assembly.GetExecutingAssembly().GetCustomAttribute<AssemblyTitleAttribute>()?.Title ?? "DefaultAppName";
|
|
string appPath = Application.ExecutablePath;
|
|
|
|
RegistryKey registryKey = Registry.CurrentUser.OpenSubKey(@"SOFTWARE\Microsoft\Windows\CurrentVersion\Run", true);
|
|
if (registryKey.GetValue(appName) == null)
|
|
{
|
|
registryKey.SetValue(appName, appPath);
|
|
}
|
|
}
|
|
|
|
public static string TimestampToDate(double timestamp, string Formatacao = "HH:mm:ss.fff")
|
|
{
|
|
// Converta o timestamp Unix para DateTime
|
|
// A época Unix começa em 1 de janeiro de 1970
|
|
DateTime epoch = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc);
|
|
DateTime date = epoch.AddSeconds(timestamp);
|
|
|
|
// Converter a data UTC para a data no fuso horário local do sistema
|
|
DateTime localDate = date.ToLocalTime();
|
|
|
|
// Formate a data para hh:mm:ss.fff (note a correção de MM para mm)
|
|
string formattedDate = localDate.ToString(Formatacao, System.Globalization.CultureInfo.InvariantCulture);
|
|
|
|
return formattedDate;
|
|
}
|
|
|
|
public static T FindControlRecursive<T>(Control parent, string controlName) where T : Control
|
|
{
|
|
foreach (Control child in parent.Controls)
|
|
{
|
|
if (child is T foundControl && child.Name == controlName)
|
|
{
|
|
return foundControl; // Retorna o controle se encontrado
|
|
}
|
|
else
|
|
{
|
|
T foundInChildren = FindControlRecursive<T>(child, controlName);
|
|
if (foundInChildren != null) return foundInChildren; // Retorna o controle se encontrado em controles filhos
|
|
}
|
|
}
|
|
return null; // Retorna null se o controle não for encontrado
|
|
}
|
|
|
|
public static void PreencheValorProgressBar(ProgressBar pgb, double Valor)
|
|
{
|
|
pgb.Value =
|
|
Valor >= pgb.Minimum && Valor <= pgb.Maximum ? pgb.Value = Convert.ToInt32(Valor) :
|
|
Valor < pgb.Minimum ? pgb.Value = pgb.Minimum :
|
|
Valor > pgb.Maximum ? pgb.Value = pgb.Maximum :
|
|
pgb.Minimum;
|
|
}
|
|
|
|
public static void PreencheValorTrackBar(TrackBar tkb, double Valor)
|
|
{
|
|
tkb.Value =
|
|
Valor >= tkb.Minimum && Valor <= tkb.Maximum ? tkb.Value = Convert.ToInt32(Valor) :
|
|
Valor < tkb.Minimum ? tkb.Value = tkb.Minimum :
|
|
Valor > tkb.Maximum ? tkb.Value = tkb.Maximum :
|
|
tkb.Minimum;
|
|
}
|
|
|
|
|
|
// Método para salvar o frame atual em JPEG
|
|
public static void SalvarFrameJPEG(Bitmap frame, string caminhoArquivo)
|
|
{
|
|
// Define as opções de codificação JPEG (qualidade de 90%)
|
|
EncoderParameters encoderParams = new EncoderParameters(1);
|
|
encoderParams.Param[0] = new EncoderParameter(System.Drawing.Imaging.Encoder.Quality, 90L);
|
|
|
|
// Salva o bitmap em formato JPEG
|
|
ImageCodecInfo jpegCodec = GetEncoderInfo(ImageFormat.Jpeg);
|
|
frame.Save(caminhoArquivo, jpegCodec, encoderParams);
|
|
}
|
|
|
|
// Método auxiliar para obter informações do codec JPEG
|
|
private static ImageCodecInfo GetEncoderInfo(ImageFormat format)
|
|
{
|
|
ImageCodecInfo[] codecs = ImageCodecInfo.GetImageDecoders();
|
|
foreach (ImageCodecInfo codec in codecs)
|
|
{
|
|
if (codec.FormatID == format.Guid)
|
|
{
|
|
return codec;
|
|
}
|
|
}
|
|
return null;
|
|
}
|
|
|
|
public static ImageCodecInfo GetEncoderInfo(string mimeType)
|
|
{
|
|
// Obtém todos os codecs de imagem disponíveis
|
|
ImageCodecInfo[] codecs = ImageCodecInfo.GetImageEncoders();
|
|
// Procura pelo codec que corresponde ao mimeType fornecido
|
|
foreach (ImageCodecInfo codec in codecs)
|
|
{
|
|
if (codec.MimeType == mimeType)
|
|
{
|
|
return codec;
|
|
}
|
|
}
|
|
return null;
|
|
}
|
|
|
|
|
|
public static Image EspelharImagemHorizontalmente(Image img)
|
|
{
|
|
// Cria uma cópia da imagem do PictureBox
|
|
Bitmap originalImage = new Bitmap(img);
|
|
|
|
// Cria uma nova imagem para conter a imagem espelhada
|
|
Bitmap mirroredImage = new Bitmap(originalImage.Width, originalImage.Height);
|
|
|
|
// Cria uma matriz de transformação para espelhar horizontalmente
|
|
Matrix matrix = new Matrix();
|
|
matrix.Scale(-1, 1);
|
|
|
|
// Cria um objeto Graphics para desenhar a imagem espelhada
|
|
using (Graphics g = Graphics.FromImage(mirroredImage))
|
|
{
|
|
// Espelha a imagem original na nova imagem
|
|
g.Transform = matrix;
|
|
g.DrawImage(originalImage, new Rectangle(-originalImage.Width, 0, originalImage.Width, originalImage.Height));
|
|
}
|
|
|
|
return mirroredImage;
|
|
}
|
|
|
|
// Método para rotacionar a imagem
|
|
public static Image RotacionarImagem(Image img, double rotationAngle, bool redimensionarParaCaber = true)
|
|
{
|
|
// Calcula as novas dimensões do bitmap com base na rotação
|
|
double angleRad = rotationAngle / 180.0 * Math.PI;
|
|
double sin = Math.Abs(Math.Sin(angleRad));
|
|
double cos = Math.Abs(Math.Cos(angleRad));
|
|
int newWidth = (int)(img.Width * cos + img.Height * sin);
|
|
int newHeight = (int)(img.Width * sin + img.Height * cos);
|
|
|
|
Bitmap bmp;
|
|
|
|
if (redimensionarParaCaber)
|
|
{
|
|
// Cria um novo bitmap com as dimensões calculadas
|
|
bmp = new Bitmap(newWidth, newHeight);
|
|
}
|
|
else
|
|
{
|
|
// Cria um novo bitmap com as dimensões originais
|
|
bmp = new Bitmap(img.Width, img.Height);
|
|
}
|
|
|
|
using (Graphics gfx = Graphics.FromImage(bmp))
|
|
{
|
|
gfx.Clear(Color.Transparent); // Define a cor de fundo como transparente
|
|
|
|
if (redimensionarParaCaber)
|
|
{
|
|
gfx.TranslateTransform(newWidth / 2f, newHeight / 2f); // Move o ponto de rotação para o centro do novo bitmap
|
|
}
|
|
else
|
|
{
|
|
gfx.TranslateTransform(img.Width / 2f, img.Height / 2f); // Move o ponto de rotação para o centro do bitmap original
|
|
}
|
|
|
|
gfx.RotateTransform((float)rotationAngle); // Aplica a rotação
|
|
|
|
if (redimensionarParaCaber)
|
|
{
|
|
gfx.TranslateTransform(-img.Width / 2f, -img.Height / 2f); // Move a imagem de volta para o centro
|
|
}
|
|
else
|
|
{
|
|
gfx.TranslateTransform(-img.Width / 2f, -img.Height / 2f); // Move a imagem de volta para o centro
|
|
}
|
|
|
|
gfx.InterpolationMode = InterpolationMode.HighQualityBicubic;
|
|
gfx.DrawImage(img, 0, 0, img.Width, img.Height); // Desenha a imagem original no bitmap
|
|
}
|
|
|
|
return bmp;
|
|
}
|
|
|
|
public static void DesenharInclinacao(Panel pnlBussola, PaintEventArgs e, float anguloInclinacao, float anguloSub)
|
|
{
|
|
if (!(anguloInclinacao >= 0 || anguloInclinacao <= 0))
|
|
{
|
|
anguloInclinacao = 0;
|
|
}
|
|
|
|
Graphics g = e.Graphics;
|
|
// Desenha o círculo da bússola
|
|
int diameter = Math.Min(pnlBussola.Width - 1, pnlBussola.Height - 1);
|
|
Point centro = new Point((pnlBussola.Width - 1) / 2, (pnlBussola.Height - 1) / 2);
|
|
//g.DrawEllipse(Pens.Black, centro.X - diameter / 2, centro.Y - diameter / 2, diameter, diameter);
|
|
|
|
// Escreve o ângulo no centro do círculo
|
|
string anguloTexto = $"{anguloInclinacao.ToString("0")}°";
|
|
Font fonteAngulo = new Font("Arial", 7); // Ajuste o tamanho da fonte conforme necessário
|
|
SizeF textSize = e.Graphics.MeasureString(anguloTexto, fonteAngulo);
|
|
|
|
// Calcula a posição para o texto ser centralizado no círculo
|
|
float textX = 0;
|
|
float textY = 0;
|
|
|
|
// Define a cor do texto
|
|
Brush textBrush = Brushes.Black;
|
|
|
|
// Desenha o texto no Graphics do painel
|
|
g.DrawString(anguloTexto, fonteAngulo, textBrush, textX, textY);
|
|
|
|
// A linha será desenhada do centro do círculo
|
|
PointF pontoCentral = new PointF(centro.X, centro.Y);
|
|
// O comprimento da linha será metade do diâmetro do círculo (raio)
|
|
float comprimentoLinha = diameter / 3;
|
|
|
|
// Ajustar o ângulo para que 0 graus esteja para cima e aumente no sentido horário
|
|
//float anguloRadianos = (anguloInclinacao - 90) * (float)(Math.PI / 180.0);
|
|
float anguloRadianos = (anguloInclinacao - anguloSub) * (float)(Math.PI / 180.0);
|
|
|
|
// Calcular o ponto final da linha baseado no ângulo de inclinação
|
|
PointF pontoFinal = new PointF(
|
|
pontoCentral.X + comprimentoLinha * (float)Math.Cos(anguloRadianos),
|
|
pontoCentral.Y + comprimentoLinha * (float)Math.Sin(anguloRadianos)
|
|
);
|
|
|
|
// Desenhar a linha de inclinação
|
|
g.DrawLine(Pens.Red, pontoCentral, pontoFinal);
|
|
|
|
// Opcional: Desenhar uma ponta de seta na linha para indicar direção
|
|
using (AdjustableArrowCap bigArrow = new AdjustableArrowCap(4, 4))
|
|
{
|
|
using (Pen pen = new Pen(Color.Red, 2))
|
|
{
|
|
pen.CustomEndCap = bigArrow;
|
|
g.DrawLine(pen, pontoCentral, pontoFinal);
|
|
}
|
|
}
|
|
}
|
|
|
|
public static string ConverterSegundosParaHHmmss(int totalSeconds)
|
|
{
|
|
TimeSpan timeSpan = TimeSpan.FromSeconds(totalSeconds);
|
|
return timeSpan.ToString(@"hh\:mm\:ss");
|
|
}
|
|
|
|
public static void DelaySincrono(int ms)
|
|
{
|
|
DateTime Agora = DateTime.Now;
|
|
while (Agora < DateTime.Now.AddMilliseconds(-ms)) { }
|
|
}
|
|
|
|
|
|
public static void DefinirEventosPicBtn(Control ctrl, string MensagemErro, Func<Task> func, bool hover = false)
|
|
{
|
|
ctrl.Cursor = Cursors.Hand;
|
|
if (hover)
|
|
{
|
|
ctrl.MouseEnter += picBtn_MouseEnter;
|
|
ctrl.MouseLeave += picBtn_MouseLeave;
|
|
}
|
|
ctrl.Click += (s, args) =>
|
|
{
|
|
picBtn_Click(s, args).ContinueWith(t =>
|
|
{
|
|
if (t.IsCompleted)
|
|
{
|
|
func().ContinueWith(ft =>
|
|
{
|
|
if (ft.IsFaulted)
|
|
{
|
|
MessageBox.Show(MensagemErro, "Erro", MessageBoxButtons.OK, MessageBoxIcon.Error);
|
|
}
|
|
}, TaskScheduler.FromCurrentSynchronizationContext());
|
|
}
|
|
}, TaskScheduler.FromCurrentSynchronizationContext());
|
|
};
|
|
}
|
|
|
|
public static async Task picBtn_Click(object sender, EventArgs e)
|
|
{
|
|
await PiscarBtn((Control)sender, 2);
|
|
}
|
|
|
|
public static void picBtn_MouseEnter(object sender, EventArgs e)
|
|
{
|
|
TransicaoTamanho((Control)sender, true, 5).ConfigureAwait(false);
|
|
}
|
|
|
|
public static void picBtn_MouseLeave(object sender, EventArgs e)
|
|
{
|
|
TransicaoTamanho((Control)sender, false, 5).ConfigureAwait(false);
|
|
}
|
|
|
|
private static void AlteraTamanhoObjeto(Control ctrl, bool Cresce)
|
|
{
|
|
int acX = Convert.ToInt32(ctrl.Width * 0.06);
|
|
if (acX % 2 == 1) acX++;
|
|
int acY = Convert.ToInt32(ctrl.Height * 0.06);
|
|
if (acY % 2 == 1) acY++;
|
|
if (!Cresce)
|
|
{
|
|
acX *= -1;
|
|
acY *= -1;
|
|
}
|
|
|
|
ctrl.Size = new Size((int)(ctrl.Width + acX), (int)(ctrl.Height + acY));
|
|
ctrl.Location = new Point(ctrl.Location.X - (acX / 2), ctrl.Location.Y - (acY / 2));
|
|
}
|
|
|
|
private static async Task TransicaoTamanho(Control ctrl, bool Cresce, int delay)
|
|
{
|
|
int steps = 10; // Número de passos na transição
|
|
int acX = Convert.ToInt32(ctrl.Width * 0.06);
|
|
if (acX % 2 == 1) acX++;
|
|
int acY = Convert.ToInt32(ctrl.Height * 0.06);
|
|
if (acY % 2 == 1) acY++;
|
|
|
|
// Ajuste para garantir que stepX e stepY sejam pelo menos 2
|
|
int stepX = Math.Max(acX / steps, 2);
|
|
int stepY = Math.Max(acY / steps, 2);
|
|
if (!Cresce)
|
|
{
|
|
stepX = -stepX;
|
|
stepY = -stepY;
|
|
}
|
|
|
|
for (int i = 0; i < steps; i++)
|
|
{
|
|
ctrl.Invoke((MethodInvoker)(() =>
|
|
{
|
|
ctrl.Size = new Size(ctrl.Width + stepX, ctrl.Height + stepY);
|
|
ctrl.Location = new Point(ctrl.Location.X - (stepX / 2), ctrl.Location.Y - (stepY / 2));
|
|
}));
|
|
await Task.Delay(delay);
|
|
}
|
|
}
|
|
|
|
private static async Task PiscarBtn(Control ctrl, int vezes)
|
|
{
|
|
for (int i = 0; i < vezes; i++)
|
|
{
|
|
await TransicaoTamanho(ctrl, true, 1);
|
|
await Task.Delay(3);
|
|
await TransicaoTamanho(ctrl, false, 1);
|
|
await Task.Delay(3);
|
|
}
|
|
}
|
|
|
|
public static Bitmap GetPanelImage(Panel panel)
|
|
{
|
|
// Cria um bitmap do tamanho do panel
|
|
Bitmap bitmap = new Bitmap(panel.Width, panel.Height);
|
|
|
|
// Desenha o conteúdo do panel no bitmap
|
|
panel.DrawToBitmap(bitmap, new Rectangle(0, 0, panel.Width, panel.Height));
|
|
|
|
// Retorna o bitmap
|
|
return bitmap;
|
|
}
|
|
|
|
public static async Task<Bitmap> GetBrowserImage(ChromiumWebBrowser browser)
|
|
{
|
|
if (browser != null)
|
|
{
|
|
var screenshot = await browser.CaptureScreenshotAsync();
|
|
|
|
using (var stream = new MemoryStream(screenshot))
|
|
{
|
|
var bitmap = new Bitmap(stream);
|
|
|
|
return bitmap;
|
|
}
|
|
}
|
|
return null;
|
|
}
|
|
|
|
|
|
public static void SalvarImagemComprimida(Bitmap frame, string Caminho, long qualidade)
|
|
{
|
|
// Se o frame for nulo, cria um novo bitmap representando uma tela preta
|
|
if (frame == null)
|
|
{
|
|
frame = new Bitmap(1, 1);
|
|
using (Graphics g = Graphics.FromImage(frame))
|
|
{
|
|
g.Clear(Color.Black);
|
|
}
|
|
}
|
|
|
|
// Obtém o codec para JPEG
|
|
ImageCodecInfo jpegCodec = GetEncoderInfo("image/jpeg");
|
|
|
|
// Configura os parâmetros de compressão
|
|
EncoderParameters encoderParams = new EncoderParameters(1);
|
|
encoderParams.Param[0] = new EncoderParameter(System.Drawing.Imaging.Encoder.Quality, qualidade);
|
|
|
|
using (Graphics g = Graphics.FromImage(frame))
|
|
{
|
|
g.DrawString(DateTime.Now.ToString("dd/MM/yyyy HH:mm:ss"), new Font("Arial", 10), Brushes.Transparent, new PointF(10, 10));
|
|
}
|
|
|
|
// Salva a imagem com a qualidade ajustada
|
|
frame.Save(Caminho, jpegCodec, encoderParams);
|
|
}
|
|
|
|
public static void SalvarImagemComprimida(Bitmap frame, string Caminho, long qualidade, int larguraDestino, int alturaDestino)
|
|
{
|
|
// Se o frame for nulo, cria um novo bitmap representando uma tela preta
|
|
if (frame == null)
|
|
{
|
|
larguraDestino = 1;
|
|
alturaDestino = 1;
|
|
frame = new Bitmap(larguraDestino, alturaDestino);
|
|
using (Graphics g = Graphics.FromImage(frame))
|
|
{
|
|
g.Clear(Color.Black);
|
|
}
|
|
}
|
|
|
|
Color corBorda = Color.FromArgb(14, 14, 14);
|
|
|
|
// Remover bordas pretas
|
|
Bitmap frameSemBordas = RemoverBordasPretas(frame, corBorda);
|
|
|
|
// Criar o novo bitmap redimensionado para o tamanho de destino
|
|
Bitmap bitmapRedimensionado = new Bitmap(larguraDestino, alturaDestino);
|
|
|
|
// Redimensionar a imagem original para ocupar toda a área de 512x512
|
|
using (Graphics g = Graphics.FromImage(bitmapRedimensionado))
|
|
{
|
|
// Configurações de alta qualidade para minimizar a perda de qualidade durante o redimensionamento
|
|
g.CompositingQuality = System.Drawing.Drawing2D.CompositingQuality.HighQuality;
|
|
g.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.HighQualityBicubic;
|
|
g.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.HighQuality;
|
|
|
|
// Preencher o bitmap de destino (512x512) com a imagem redimensionada
|
|
g.DrawImage(frameSemBordas, 0, 0, larguraDestino, alturaDestino);
|
|
|
|
// Adiciona a data e hora na imagem (opcional)
|
|
g.DrawString(DateTime.Now.ToString("dd/MM/yyyy HH:mm:ss"), new Font("Arial", 10), Brushes.Transparent, new PointF(10, 10));
|
|
}
|
|
|
|
// Obtém o codec para JPEG
|
|
ImageCodecInfo jpegCodec = GetEncoderInfo("image/jpeg");
|
|
|
|
// Configura os parâmetros de compressão
|
|
EncoderParameters encoderParams = new EncoderParameters(1);
|
|
encoderParams.Param[0] = new EncoderParameter(System.Drawing.Imaging.Encoder.Quality, qualidade);
|
|
|
|
// Salva a imagem redimensionada com a qualidade ajustada
|
|
bitmapRedimensionado.Save(Caminho, jpegCodec, encoderParams);
|
|
|
|
// Libera os recursos usados pelo bitmap redimensionado
|
|
bitmapRedimensionado.Dispose();
|
|
}
|
|
|
|
private static Bitmap RemoverBordasPretas(Bitmap _imagem, Color corBorda)
|
|
{
|
|
Bitmap imagem = (Bitmap)_imagem.Clone();
|
|
|
|
int xMin = imagem.Width, xMax = 0, yMin = imagem.Height, yMax = 0;
|
|
|
|
// Iterar sobre todos os pixels para encontrar os limites da imagem sem bordas com a cor especificada
|
|
for (int y = 0; y < imagem.Height; y++)
|
|
{
|
|
for (int x = 0; x < imagem.Width; x++)
|
|
{
|
|
Color pixel = imagem.GetPixel(x, y);
|
|
// Verificar se o pixel não corresponde à cor da borda
|
|
if (pixel.R != corBorda.R || pixel.G != corBorda.G || pixel.B != corBorda.B)
|
|
{
|
|
if (x < xMin) xMin = x;
|
|
if (x > xMax) xMax = x;
|
|
if (y < yMin) yMin = y;
|
|
if (y > yMax) yMax = y;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Se a imagem for completamente da cor da borda, retornar um bitmap vazio
|
|
if (xMax == 0 && yMax == 0)
|
|
{
|
|
return new Bitmap(1, 1); // Imagem completamente da cor da borda
|
|
}
|
|
|
|
// Cortar a imagem para remover as bordas
|
|
int novaLargura = xMax - xMin + 1;
|
|
int novaAltura = yMax - yMin + 1;
|
|
|
|
Bitmap imagemSemBordas = new Bitmap(novaLargura, novaAltura);
|
|
using (Graphics g = Graphics.FromImage(imagemSemBordas))
|
|
{
|
|
g.DrawImage(imagem, new Rectangle(0, 0, novaLargura, novaAltura), new Rectangle(xMin, yMin, novaLargura, novaAltura), GraphicsUnit.Pixel);
|
|
}
|
|
|
|
return imagemSemBordas;
|
|
}
|
|
|
|
|
|
public static async Task ExecutarMetodoComVerificacaoCrossThreadAsync(Control controle, Func<Task> acao)
|
|
{
|
|
if (controle.InvokeRequired)
|
|
{
|
|
await (Task)controle.Invoke(new Func<Task>(() => acao()));
|
|
}
|
|
else
|
|
{
|
|
await acao();
|
|
}
|
|
}
|
|
|
|
public static T ExecutarMetodoComVerificacaoCrossThread<T>(Control controle, Func<T> acao)
|
|
{
|
|
if (controle == null)
|
|
throw new ArgumentNullException(nameof(controle));
|
|
|
|
if (controle.InvokeRequired)
|
|
{
|
|
return (T)controle.Invoke(new Func<T>(() => acao()));
|
|
}
|
|
else
|
|
{
|
|
return acao();
|
|
}
|
|
}
|
|
|
|
|
|
|
|
public static string MontarStringPerformance(float? gpuLoad, float? cpuLoad, float? ramUsage, float? cpuTemp, float? gpuTemp)
|
|
{
|
|
return $"GPU: {gpuLoad?.ToString("0.0") ?? "N/A"}% " +
|
|
$"CPU: {cpuLoad?.ToString("0.0") ?? "N/A"}% " +
|
|
$"RAM: {ramUsage?.ToString("0.0") ?? "N/A"}% " +
|
|
$"Temp CPU: {cpuTemp?.ToString("0.0") ?? "N/A"}°C " +
|
|
$"Temp GPU: {gpuTemp?.ToString("0.0") ?? "N/A"}°C";
|
|
}
|
|
|
|
|
|
|
|
private static SemaphoreSlim semaphore = new SemaphoreSlim(1, 1);
|
|
|
|
public static async Task SafeExecuteAsync(Func<Task> action)
|
|
{
|
|
await semaphore.WaitAsync();
|
|
try
|
|
{
|
|
await action();
|
|
}
|
|
finally
|
|
{
|
|
semaphore.Release();
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
public static class FuncoesMatematicas
|
|
{
|
|
public static double Map(double valor, double deMin, double deMax, double paraMin, double paraMax)
|
|
{
|
|
return paraMin + (valor - deMin) * (paraMax - paraMin) / (deMax - deMin);
|
|
}
|
|
|
|
public static double ConvertDegreesToRadians(double degrees)
|
|
{
|
|
double radians = (Math.PI / 180) * degrees;
|
|
return (radians);
|
|
}
|
|
|
|
public static double CalcularAlturaTriangulo(double a, double b, double c)
|
|
{
|
|
// Verifica se os lados formam um triângulo válido
|
|
if (a + b <= c || a + c <= b || b + c <= a)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
// Calcule a área do triângulo usando a fórmula de Herão
|
|
double s = (a + b + c) / 2.0; // Semiperímetro
|
|
double area = Math.Sqrt(s * (s - a) * (s - b) * (s - c));
|
|
|
|
// Calcule a altura em relação à base c
|
|
double altura = (2 * area) / c;
|
|
|
|
return altura;
|
|
}
|
|
|
|
public static double CalcularMediana(List<double> numbers)
|
|
{
|
|
numbers.Sort();
|
|
int count = numbers.Count;
|
|
if (count % 2 == 0)
|
|
{
|
|
// Se count é par, a mediana é a média dos dois elementos do meio
|
|
double middle1 = numbers[count / 2 - 1];
|
|
double middle2 = numbers[count / 2];
|
|
return (middle1 + middle2) / 2.0;
|
|
}
|
|
else
|
|
{
|
|
// Se count é ímpar, a mediana é o elemento do meio
|
|
return numbers[count / 2];
|
|
}
|
|
}
|
|
|
|
public static double CalcularModa(List<double> numbers)
|
|
{
|
|
return numbers.GroupBy(n => n)
|
|
.OrderByDescending(g => g.Count())
|
|
.First()
|
|
.Key;
|
|
}
|
|
|
|
/*public static double CalcularTemperatura(double leitura, double offset)
|
|
{
|
|
double Vs = 3.3; // TENSÃO DE SAIDA DO ESP32
|
|
double R1 = 10000; //RESISTOR UTILIZADO NO DIVISOR DE TENSÃO
|
|
double Beta = 3950; // VALOR DE BETA
|
|
double To = 298.15; // VALOR EM KELVIN REFERENTE A 25° CELSIUS
|
|
double Ro = 10000;
|
|
double adcMax = 1024.0;
|
|
double Vout, Rt = 0;
|
|
double T, Tc, Tf, adc = 0;
|
|
//CALCULOS PARA CONVERSÃO DA LEITURA RECEBIDA PELO ESP32 EM TEMPERATURA EM °C
|
|
Vout = (leitura * Vs / adcMax) + offset;
|
|
Rt = R1 * Vout / (Vs - Vout);
|
|
T = 1 / (1 / To + Math.Log(Rt / Ro) / Beta);
|
|
Tc = T - 273.15;
|
|
Tf = Tc * 9 / 5 + 32;
|
|
|
|
Tc = Math.Round(Tc, 2);
|
|
|
|
return Tc;
|
|
}*/
|
|
|
|
public static double CalcularTemperatura(double leitura, double offset)
|
|
{
|
|
double Vs = 5.0; // TENSÃO DE SAÍDA DO ESP32
|
|
double Beta = 3950; // VALOR DE BETA
|
|
double To = 298.15; // VALOR EM KELVIN REFERENTE A 25° CELSIUS
|
|
double Ro = 10000; // RESISTÊNCIA DO NTC A 25°C
|
|
double adcMax = 4096.0;
|
|
double Vout, Rt = 0;
|
|
double T, Tc, Tf, adc = 0;
|
|
|
|
// CALCULOS PARA CONVERSÃO DA LEITURA RECEBIDA PELO ESP32 EM TEMPERATURA EM °C
|
|
Vout = (leitura * Vs / adcMax) + offset;
|
|
Rt = Ro * (Vs / Vout - 1);
|
|
T = 1 / (1 / To + Math.Log(Rt / Ro) / Beta);
|
|
Tc = T - 273.15;
|
|
Tf = Tc * 9 / 5 + 32;
|
|
|
|
Tc = Math.Round(Tc, 2);
|
|
|
|
return Tc;
|
|
}
|
|
|
|
public static bool ValorEstaEntre(double valorAtual, double valorComparar, double margem)
|
|
{
|
|
if (valorAtual <= (valorComparar + margem) && valorAtual >= (valorComparar - margem))
|
|
{
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
// Função personalizada Clamp
|
|
public static double Clamp(double valor, double minimo, double maximo)
|
|
{
|
|
if (valor < minimo) return minimo;
|
|
if (valor > maximo) return maximo;
|
|
return valor;
|
|
}
|
|
|
|
public static double CalculaVelocidadeRPM(double RPM)
|
|
{
|
|
double VelocidadeInstantanea = Math.Round((Math.PI * VariaveisEquipamento.DiametroRoda * 60 * RPM) / 1000, 2); // Km/h
|
|
return VelocidadeInstantanea;
|
|
}
|
|
|
|
public static double CalculaRPMVelocidade(double Velocidade)
|
|
{
|
|
double RPM = Math.Round((Velocidade * 1000) / (Math.PI * VariaveisEquipamento.DiametroRoda * 60), 2);
|
|
return RPM;
|
|
}
|
|
|
|
public static double ConverteKmhParaMs(double Velocidade)
|
|
{
|
|
return Velocidade / 3.6;
|
|
}
|
|
|
|
}
|
|
|
|
}
|