inclusao de motivos de controle e trajetoria
This commit is contained in:
parent
1ff65eeb67
commit
7398624ad7
|
|
@ -2167,6 +2167,7 @@ namespace AgroBase.Models
|
|||
public double Latencia { get; set; }
|
||||
public double ErroLateral { get; set; } = 0.0;
|
||||
public Dictionary<string, ManagerWorkerMessageResponseDebugCustoModel> DebugCustoMpc { get; set; } = new Dictionary<string, ManagerWorkerMessageResponseDebugCustoModel>();
|
||||
public List<string> Motivos { get; set; } = new List<string>();
|
||||
|
||||
public void Reiniciar()
|
||||
{
|
||||
|
|
@ -2197,6 +2198,7 @@ namespace AgroBase.Models
|
|||
EmFreio = EmFreio,
|
||||
ErroLateral = ErroLateral,
|
||||
DebugCustoMpc = new Dictionary<string, ManagerWorkerMessageResponseDebugCustoModel>(DebugCustoMpc ?? new Dictionary<string, ManagerWorkerMessageResponseDebugCustoModel>()),
|
||||
Motivos = new List<string>(Motivos ?? new List<string>())
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -534,6 +534,7 @@ namespace AgroBase.Models.Operacoes
|
|||
HerbicidaSuficiente = t.AutonomiaCooredor.HerbicidaSuficiente,
|
||||
Liberado = t.AutonomiaCooredor.Liberado,
|
||||
Motivo = t.AutonomiaCooredor.Motivo,
|
||||
Motivos = t.AutonomiaCooredor.Motivos.ToList(),
|
||||
Status = t.AutonomiaCooredor.Status
|
||||
},
|
||||
AnguloCaminho = t.AnguloCaminho,
|
||||
|
|
@ -566,6 +567,7 @@ namespace AgroBase.Models.Operacoes
|
|||
PercentualVelocidadeSPKmh = c.PercentualVelocidadeSPKmh,
|
||||
TipoMovimento = c.TipoMovimento,
|
||||
SimulacaoMPC = c.SimulacaoMPC,
|
||||
Motivos = c.Motivos
|
||||
} : new OperacaoParametrosDadosControleModel();
|
||||
ModulosSaude = new List<ManagerWorkerMessageResponseModulosPendentesModel>(sen?.ModulosSaude ?? new List<ManagerWorkerMessageResponseModulosPendentesModel>());
|
||||
DispositivosMapeados = new List<DispositivoDetalhesModel>(sen?.DispositivosMapeados ?? new List<DispositivoDetalhesModel>());
|
||||
|
|
@ -888,6 +890,7 @@ namespace AgroBase.Models.Operacoes
|
|||
public bool HerbicidaSuficiente { get; set; }
|
||||
public bool Liberado { get; set; }
|
||||
public string Motivo { get; set; }
|
||||
public List<string> Motivos { get; set; }
|
||||
|
||||
}
|
||||
|
||||
|
|
@ -898,6 +901,7 @@ namespace AgroBase.Models.Operacoes
|
|||
public TipoMovimentoDirecional TipoMovimento { get; set; }
|
||||
public double PercentualVelocidadeSPKmh { get; set; }
|
||||
public List<MPCSimulacaoModel> SimulacaoMPC { get; set; } = new List<MPCSimulacaoModel>();
|
||||
public List<string> Motivos { get; set; } = new List<string>();
|
||||
|
||||
public OperacaoParametrosDadosControleModel Clone()
|
||||
{
|
||||
|
|
@ -907,7 +911,8 @@ namespace AgroBase.Models.Operacoes
|
|||
Angulo = Angulo,
|
||||
PercentualVelocidadeSPKmh = PercentualVelocidadeSPKmh,
|
||||
TipoMovimento = TipoMovimento,
|
||||
SimulacaoMPC = SimulacaoMPC
|
||||
SimulacaoMPC = SimulacaoMPC,
|
||||
Motivos = new List<string>(Motivos ?? new List<string>())
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -57,6 +57,7 @@ namespace AgroBase.Models.Operadores
|
|||
public double latencia { get; set; }
|
||||
public double erro_lateral { get; set; }
|
||||
public Dictionary<string, ManagerWorkerMessageResponseDebugCustoModel> debug_custo { get; set; }
|
||||
public string[] motivos { get; set; }
|
||||
}
|
||||
|
||||
public class ManagerWorkerMessageResponseDebugCustoModel
|
||||
|
|
|
|||
|
|
@ -1014,6 +1014,7 @@ namespace AgroBase.Models
|
|||
dictParams.TryGetValue("latencia", out var _latencia);
|
||||
dictParams.TryGetValue("erro_lateral", out var _erro_lateral);
|
||||
dictParams.TryGetValue("debug_custo", out var _debug_custo);
|
||||
dictParams.TryGetValue("motivos", out var _motivos);
|
||||
novoComando = new ManagerWorkerMessageResponseComandoModel()
|
||||
{
|
||||
angulo = Convert.ToDouble(_angulo),
|
||||
|
|
@ -1025,6 +1026,7 @@ namespace AgroBase.Models
|
|||
latencia = Convert.ToDouble(_latencia.ToString().Replace(".", ",")),
|
||||
erro_lateral = Convert.ToDouble(_erro_lateral.ToString().Replace(".", ",")),
|
||||
debug_custo = JsonConvert.DeserializeObject<Dictionary<string, ManagerWorkerMessageResponseDebugCustoModel>>(_debug_custo.ToString()),
|
||||
motivos = JsonConvert.DeserializeObject<string[]>((_motivos ?? "").ToString())
|
||||
};
|
||||
}
|
||||
catch (Exception ex)
|
||||
|
|
@ -1073,11 +1075,15 @@ namespace AgroBase.Models
|
|||
_Controle.ticks_sem_resposta = DateTime.MinValue;
|
||||
}
|
||||
if (novoComando != null)
|
||||
{
|
||||
_Controle.heartbeat = novoComando.heartbeat;
|
||||
_Controle.Motivos = novoComando.motivos.ToList();
|
||||
}
|
||||
if (_Controle.ticks_sem_resposta != DateTime.MinValue)
|
||||
{
|
||||
if (_Controle.ticks_sem_resposta.AddMilliseconds(max_ticks_sem_resposta) < agora)
|
||||
{
|
||||
Variaveis.OperacaoEmAndamento.Sensoriamento?.InserirLog(T_Code.Npc, StatusModulo.Falha, 0, "Muito tempo sem receber novo comando do Manager Worker! Parando Movimento!");
|
||||
Console.WriteLine("Muito tempo sem receber novo comando do Manager Worker! Parando Movimento!");
|
||||
RedisService.AtualizarCampos(
|
||||
CtxKey.DadosControle,
|
||||
|
|
@ -1086,6 +1092,7 @@ namespace AgroBase.Models
|
|||
}
|
||||
else if (_Controle.ticks_sem_resposta.AddMilliseconds(min_ticks_sem_resposta) < agora)
|
||||
{
|
||||
Variaveis.OperacaoEmAndamento.Sensoriamento?.InserirLog(T_Code.Npc, StatusModulo.Alerta, 80, "Muito tempo sem receber novo comando do Manager Worker! Reduzindo Velocidade!");
|
||||
Console.WriteLine("Muito tempo sem receber novo comando do Manager Worker! Reduzindo Velocidade!");
|
||||
RedisService.AtualizarCampos(
|
||||
CtxKey.DadosControle,
|
||||
|
|
@ -2742,6 +2749,9 @@ namespace AgroBase.Models
|
|||
[JsonProperty]
|
||||
public string Motivo { get; private set; } = "";
|
||||
|
||||
[JsonProperty]
|
||||
public List<string> Motivos { get; private set; } = new List<string>();
|
||||
|
||||
// ==========================
|
||||
// Flags de conveniência
|
||||
// ==========================
|
||||
|
|
@ -2785,7 +2795,7 @@ namespace AgroBase.Models
|
|||
if (!Iniciado)
|
||||
{
|
||||
Liberado = true;
|
||||
Motivo = "Não iniciado";
|
||||
Motivos.Add("Não iniciado");
|
||||
Status = AutonomiaCorredorStatus.Desconhecido;
|
||||
return;
|
||||
}
|
||||
|
|
@ -2798,6 +2808,9 @@ namespace AgroBase.Models
|
|||
if (CorredoresLiberados.ContainsKey(idxCorredor) && CorredoresLiberados[idxCorredor].Liberado)
|
||||
return;
|
||||
|
||||
var motivosBloqueio = new List<string>();
|
||||
Motivos = new List<string>();
|
||||
|
||||
// Atalho: interpretar que o operador “clicou em liberar” (pelo menos um sinal veio)
|
||||
bool solicitouLiberacaoHumana = bateria_liberada || reservatorio_liberado;
|
||||
|
||||
|
|
@ -2839,23 +2852,26 @@ namespace AgroBase.Models
|
|||
statusBase = AutonomiaCorredorStatus.Critico;
|
||||
|
||||
if (criticoBateria)
|
||||
{
|
||||
motivosBloqueio.Add("Bateria insuficiente para concluir o corredor com segurança.");
|
||||
motivoBase += motivoBat;
|
||||
}
|
||||
|
||||
if (!herbOk)
|
||||
if (criticoHerbicida)
|
||||
{
|
||||
motivosBloqueio.Add("Herbicida insuficiente para pulverizar o corredor completo.");
|
||||
motivoBase += (string.IsNullOrEmpty(motivoBase) ? "" : "; ") + motivoHerb;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Não crítico
|
||||
if (!herbOk && !exigirPulverizacaoTotal)
|
||||
{
|
||||
// Pode atravessar, mas não pulveriza tudo
|
||||
statusBase = AutonomiaCorredorStatus.OkSomenteTransito;
|
||||
motivoBase = motivoHerb;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Tudo ok
|
||||
statusBase = AutonomiaCorredorStatus.OkCompleto;
|
||||
}
|
||||
}
|
||||
|
|
@ -2906,6 +2922,7 @@ namespace AgroBase.Models
|
|||
|
||||
motivoFinal = $"Corredor {idxCorredor + 1}: BLOQUEADO. {detalhes} " +
|
||||
$"Aguardando liberação do operador pela base.";
|
||||
motivosBloqueio.Add($"Corredor {idxCorredor + 1}: BLOQUEADO. Aguardando solução ou liberação manual do operador.");
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
@ -2931,6 +2948,7 @@ namespace AgroBase.Models
|
|||
|
||||
motivoFinal = $"Corredor {idxCorredor + 1}: LIBERAÇÃO MANUAL (override). " +
|
||||
(string.IsNullOrEmpty(motivoBase) ? "Autonomia insuficiente, mas liberado." : motivoBase);
|
||||
motivosBloqueio.Add($"Corredor {idxCorredor + 1}: LIBERAÇÃO MANUAL. Autonomia insuficiente, mas houver liberação supervisionada.");
|
||||
|
||||
// Destrava o corredor (o operador assumiu)
|
||||
_corredoresTravados.Remove(idxCorredor);
|
||||
|
|
@ -2958,26 +2976,30 @@ namespace AgroBase.Models
|
|||
// ==========================
|
||||
Status = statusFinal;
|
||||
|
||||
Motivos = motivosBloqueio
|
||||
.Where(x => !string.IsNullOrWhiteSpace(x))
|
||||
.Distinct()
|
||||
.ToList();
|
||||
|
||||
var res = new AutonomiaCorredorModel()
|
||||
{
|
||||
Iniciado = this.Iniciado,
|
||||
Liberado = liberadoFinal,
|
||||
Motivo = motivoFinal,
|
||||
Motivos = Motivos,
|
||||
Status = statusFinal,
|
||||
DistanciaCorredor_m = DistanciaCorredor_m,
|
||||
DistanciaSeguraBateria_m = DistanciaSeguraBateria_m,
|
||||
DistanciaSeguraHerbicida_m = DistanciaSeguraHerbicida_m,
|
||||
};
|
||||
|
||||
bool addLog = false;
|
||||
|
||||
if (CorredoresLiberados.ContainsKey(idxCorredor))
|
||||
{
|
||||
// Se estava bloqueado e agora liberou, registra mudança
|
||||
if (CorredoresLiberados[idxCorredor].Liberado == false && liberadoFinal)
|
||||
{
|
||||
CorredoresLiberados[idxCorredor] = res;
|
||||
addLog = true;
|
||||
Variaveis.OperacaoEmAndamento.Sensoriamento.InserirLog(T_Code.Trj, liberadoFinal ? StatusModulo.Operante : StatusModulo.Alerta, liberadoFinal ? 100 : 0, $"Corredor {idxCorredor + 1} liberado pelo operador");
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
@ -2988,23 +3010,13 @@ namespace AgroBase.Models
|
|||
else
|
||||
{
|
||||
CorredoresLiberados.Add(idxCorredor, res);
|
||||
addLog = true;
|
||||
}
|
||||
|
||||
if (addLog)
|
||||
{
|
||||
// Mantive tua ideia: loga operante quando liberado, alerta quando não
|
||||
Variaveis.OperacaoEmAndamento.Sensoriamento.InserirLog(
|
||||
T_Code.Trj,
|
||||
liberadoFinal ? StatusModulo.Operante : StatusModulo.Alerta,
|
||||
liberadoFinal ? 100 : 0,
|
||||
res.Motivo
|
||||
);
|
||||
Variaveis.OperacaoEmAndamento.Sensoriamento.InserirLog(T_Code.Trj, liberadoFinal ? StatusModulo.Operante : StatusModulo.Alerta, liberadoFinal ? 100 : 0, $"Corredor {idxCorredor + 1} bloqueado por autonomia insuficiente");
|
||||
}
|
||||
|
||||
// Atualiza estado exposto
|
||||
Liberado = res.Liberado;
|
||||
Motivo = res.Motivo;
|
||||
Motivos = res.Motivos;
|
||||
}
|
||||
|
||||
// ==========================
|
||||
|
|
@ -3016,7 +3028,7 @@ namespace AgroBase.Models
|
|||
{
|
||||
Iniciado = Iniciado,
|
||||
Liberado = Liberado,
|
||||
Motivo = Motivo,
|
||||
Motivos = new List<string>(Motivos ?? new List<string>()),
|
||||
Status = Status,
|
||||
DistanciaCorredor_m = DistanciaCorredor_m,
|
||||
DistanciaSeguraBateria_m = DistanciaSeguraBateria_m,
|
||||
|
|
|
|||
|
|
@ -94,6 +94,7 @@ namespace AgroBase.Services.Operadores
|
|||
("iniciado", Variaveis.OperacaoEmAndamento.Iniciado),
|
||||
("finalizando", Variaveis.OperacaoEmAndamento.Finalizando),
|
||||
("calibrando", Variaveis.OperacaoEmAndamento.Calibrando),
|
||||
("simulando", Variaveis.OperacaoEmAndamento.Simulando),
|
||||
("emergencia", Variaveis.OperacaoEmAndamento.Emergencia),
|
||||
("pausa", Variaveis.OperacaoEmAndamento.Pausa)
|
||||
);
|
||||
|
|
@ -818,7 +819,7 @@ namespace AgroBase.Services.Operadores
|
|||
("liberado", DadosTrj?.AutonomiaCooredor?.Liberado ?? false),
|
||||
("bateria_ok", DadosTrj?.AutonomiaCooredor?.BateriaSuficiente ?? false),
|
||||
("herbicida_ok", DadosTrj?.AutonomiaCooredor?.HerbicidaSuficiente ?? false),
|
||||
("motivo", DadosTrj?.AutonomiaCooredor?.Motivo)
|
||||
("motivos", DadosTrj?.AutonomiaCooredor?.Motivos ?? new List<string>())
|
||||
);
|
||||
|
||||
double distanciaBase = -1;
|
||||
|
|
|
|||
|
|
@ -60,6 +60,10 @@ namespace AgroBase.Services.Operadores
|
|||
dictParams.TryGetValue("tipo_movimento_direcional", out object _movimento);
|
||||
dictParams.TryGetValue("simulacao", out object _simulacao);
|
||||
dictParams.TryGetValue("heartbeat", out object _heartbeat);
|
||||
dictParams.TryGetValue("latencia", out var _latencia);
|
||||
dictParams.TryGetValue("erro_lateral", out var _erro_lateral);
|
||||
dictParams.TryGetValue("debug_custo", out var _debug_custo);
|
||||
dictParams.TryGetValue("motivos", out var _motivos);
|
||||
novoComando = new ManagerWorkerMessageResponseComandoModel()
|
||||
{
|
||||
angulo = Convert.ToDouble(_angulo),
|
||||
|
|
@ -67,7 +71,11 @@ namespace AgroBase.Services.Operadores
|
|||
em_freio = Convert.ToBoolean(_em_freio),
|
||||
tipo_movimento = (Enums.TipoMovimentoDirecional)Convert.ToInt32(_movimento),
|
||||
simulacao = JsonConvert.DeserializeObject<List<double[]>>((_simulacao ?? "").ToString()),
|
||||
heartbeat = Convert.ToInt32(_heartbeat)
|
||||
heartbeat = Convert.ToInt32(_heartbeat),
|
||||
latencia = Convert.ToDouble(_latencia.ToString().Replace(".", ",")),
|
||||
erro_lateral = Convert.ToDouble(_erro_lateral.ToString().Replace(".", ",")),
|
||||
debug_custo = JsonConvert.DeserializeObject<Dictionary<string, ManagerWorkerMessageResponseDebugCustoModel>>(_debug_custo.ToString()),
|
||||
motivos = JsonConvert.DeserializeObject<string[]>((_motivos ?? "").ToString())
|
||||
};
|
||||
}
|
||||
catch (Exception ex)
|
||||
|
|
@ -76,6 +84,7 @@ namespace AgroBase.Services.Operadores
|
|||
}
|
||||
|
||||
var _Controle = Variaveis.OperacaoEmAndamento.Controle;
|
||||
_Controle.Motivos = (novoComando?.motivos ?? (new List<string>()).ToArray()).ToList();
|
||||
bool comandoMudou = (_Controle.Angulo != novoComando.angulo || _Controle.PercentualVelocidadeSP != novoComando.percentual_velocidade || _Controle.TipoMovimento != novoComando.tipo_movimento || _Controle.EmFreio != novoComando.em_freio);
|
||||
if (novoComando != null && comandoMudou)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -57,6 +57,7 @@ def definir_comando(pid: PIDAdaptativo, envio_necessario: bool):
|
|||
Vmin = 0.1 # if _trajetoria.get("status", StatusCarroMapa.Parado.value) == StatusCarroMapa.CaminhandoRua.value else 0.8
|
||||
|
||||
contexto = {
|
||||
"Simulando": _operacao.get("simulando", False),
|
||||
"GPS": {
|
||||
"Latitude": _gps.get("lat", 0),
|
||||
"Longitude": _gps.get("lon", 0),
|
||||
|
|
|
|||
|
|
@ -656,10 +656,12 @@ class ControladorMPC:
|
|||
pos_timestamp = GPS.get("Timestamp", 0.0)
|
||||
pos_latencia = now() - pos_timestamp
|
||||
|
||||
simulando = contexto.get("Simulando", False)
|
||||
|
||||
LAT_MAX = 2.0
|
||||
if pos_latencia >= LAT_MAX:
|
||||
mostrar_log(f"[GPS] Grande latencia entre coordenadas detectado ({pos_latencia:.3f}/{LAT_MAX}): parando por fallback")
|
||||
return self._comando_fallback_hot_stop(comando_anterior, latencia=pos_latencia)
|
||||
return self._comando_fallback_hot_stop(comando_anterior, motivos=[] if simulando else [f"Grande latencia entre coordenadas detectado ({pos_latencia:.3f}/{LAT_MAX}): parando por fallback"], latencia=pos_latencia)
|
||||
if (pos_passos_atraso > 3):
|
||||
mostrar_log(f"[GPS] Atraso detectado de {(pos_passos_atraso / 3.0):.1f} passos, {pos_latencia:.3f} s")
|
||||
|
||||
|
|
@ -966,7 +968,8 @@ class ControladorMPC:
|
|||
"erro_lateral": erro_lateral,
|
||||
"erro_orientacao": erro_orientacao,
|
||||
"debug_custo": debug_custo,
|
||||
"candidatos_testados": K
|
||||
"candidatos_testados": K,
|
||||
"motivos": []
|
||||
}
|
||||
|
||||
# -------------------- Debug opcional da matriz de custo --------------------
|
||||
|
|
@ -996,7 +999,7 @@ class ControladorMPC:
|
|||
|
||||
except Exception as e:
|
||||
mostrar_log(f"❌ Erro ao processar MPC: {e}")
|
||||
return self._comando_fallback_hot_stop(comando_anterior, latencia=pos_latencia)
|
||||
return self._comando_fallback_hot_stop(comando_anterior, motivos=[f"Erro ao processar MPC: {e}"], latencia=pos_latencia)
|
||||
|
||||
|
||||
def _verifica_tempo_maximo_execucao(self, t_init, processo):
|
||||
|
|
@ -1007,7 +1010,7 @@ class ControladorMPC:
|
|||
mostrar_log(f"🚨 Tempo maximo de execucao excedido: {delta}/{limite}, processo: {processo}")
|
||||
return hot_stop
|
||||
|
||||
def _comando_fallback_hot_stop(self, comando_anterior, latencia=0):
|
||||
def _comando_fallback_hot_stop(self, comando_anterior, motivos, latencia=0):
|
||||
_cmd = {
|
||||
"enviar_comando": True,
|
||||
"parada_necessaria": True,
|
||||
|
|
@ -1019,7 +1022,8 @@ class ControladorMPC:
|
|||
"erro_latreral": 0,
|
||||
"erro_orientacao": 0,
|
||||
"debug_custo": {},
|
||||
"candidatos_testados": 0
|
||||
"candidatos_testados": 0,
|
||||
"motivos": motivos
|
||||
}
|
||||
return _cmd
|
||||
|
||||
|
|
|
|||
|
|
@ -73,7 +73,7 @@ class ProcessadorEmAndamento(ProcessadorBase):
|
|||
latencia=comando_dir.get("latencia", 0.0),
|
||||
erro_lateral=comando_dir.get("erro_lateral", 0.0),
|
||||
debug_custo=comando_dir.get("debug_custo", {}),
|
||||
motivos=[]
|
||||
motivos=comando_dir.get("motivos", []) if comando_dir.get("erro", False) else []
|
||||
)
|
||||
except Exception as e:
|
||||
from manager_worker.config import mostrar_log
|
||||
|
|
|
|||
|
|
@ -40,7 +40,8 @@ def comando_controle(percentual_velocidade: float, frear: bool, angulo: float, t
|
|||
"heartbeat": hb_novo,
|
||||
"latencia": latencia,
|
||||
"erro_lateral": erro_lateral,
|
||||
"debug_custo": debug_custo
|
||||
"debug_custo": debug_custo,
|
||||
"motivos": motivos
|
||||
}
|
||||
|
||||
def comando_parado(motivos=None):
|
||||
|
|
|
|||
|
|
@ -382,9 +382,9 @@ class ContextoGlobalRedis:
|
|||
trajetoria_ok = True
|
||||
if not trajetoria_liberada:
|
||||
trajetoria_ok = False
|
||||
_motivo_traj = _t.get("motivo")
|
||||
if _motivo_traj:
|
||||
motivos_dos_modulos_mandatorios.append(_motivo_traj)
|
||||
_motivos_traj = _t.get("motivos", [])
|
||||
if len(_motivos_traj) > 0:
|
||||
motivos_dos_modulos_mandatorios.extend(_motivos_traj)
|
||||
|
||||
controle_ok = True
|
||||
_motivos_controle = cls.get_controle().get("motivos", [])
|
||||
|
|
|
|||
|
|
@ -0,0 +1,139 @@
|
|||
using System;
|
||||
using System.ComponentModel;
|
||||
using System.Globalization;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Media;
|
||||
|
||||
namespace OperationControl.Controls
|
||||
{
|
||||
public class AutoFitTextBlock : TextBlock
|
||||
{
|
||||
public static readonly DependencyProperty MinFontSizeProperty =
|
||||
DependencyProperty.Register(
|
||||
nameof(MinFontSize),
|
||||
typeof(double),
|
||||
typeof(AutoFitTextBlock),
|
||||
new PropertyMetadata(10.0, OnAutoFitPropertyChanged));
|
||||
|
||||
public static readonly DependencyProperty MaxLinesProperty =
|
||||
DependencyProperty.Register(
|
||||
nameof(MaxLines),
|
||||
typeof(int),
|
||||
typeof(AutoFitTextBlock),
|
||||
new PropertyMetadata(2, OnAutoFitPropertyChanged));
|
||||
|
||||
private double _baseFontSize = 14;
|
||||
private bool _isAdjusting;
|
||||
|
||||
public double MinFontSize
|
||||
{
|
||||
get => (double)GetValue(MinFontSizeProperty);
|
||||
set => SetValue(MinFontSizeProperty, value);
|
||||
}
|
||||
|
||||
public int MaxLines
|
||||
{
|
||||
get => (int)GetValue(MaxLinesProperty);
|
||||
set => SetValue(MaxLinesProperty, value);
|
||||
}
|
||||
|
||||
public AutoFitTextBlock()
|
||||
{
|
||||
Loaded += AutoFitTextBlock_Loaded;
|
||||
SizeChanged += (_, _) => AdjustFontSize();
|
||||
}
|
||||
|
||||
private void AutoFitTextBlock_Loaded(object sender, RoutedEventArgs e)
|
||||
{
|
||||
_baseFontSize = FontSize;
|
||||
|
||||
WatchProperty(TextProperty);
|
||||
WatchProperty(FontSizeProperty);
|
||||
WatchProperty(FontFamilyProperty);
|
||||
WatchProperty(FontStyleProperty);
|
||||
WatchProperty(FontWeightProperty);
|
||||
WatchProperty(FontStretchProperty);
|
||||
WatchProperty(TextWrappingProperty);
|
||||
|
||||
AdjustFontSize();
|
||||
}
|
||||
|
||||
private void WatchProperty(DependencyProperty dp)
|
||||
{
|
||||
var descriptor = DependencyPropertyDescriptor.FromProperty(dp, typeof(AutoFitTextBlock));
|
||||
descriptor?.AddValueChanged(this, (_, _) =>
|
||||
{
|
||||
if (!_isAdjusting && dp == FontSizeProperty)
|
||||
_baseFontSize = FontSize;
|
||||
|
||||
AdjustFontSize();
|
||||
});
|
||||
}
|
||||
|
||||
private static void OnAutoFitPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
|
||||
{
|
||||
if (d is AutoFitTextBlock tb)
|
||||
tb.AdjustFontSize();
|
||||
}
|
||||
|
||||
private void AdjustFontSize()
|
||||
{
|
||||
if (_isAdjusting || !IsLoaded)
|
||||
return;
|
||||
|
||||
if (ActualWidth <= 0 || string.IsNullOrWhiteSpace(Text))
|
||||
return;
|
||||
|
||||
_isAdjusting = true;
|
||||
|
||||
try
|
||||
{
|
||||
double startFont = _baseFontSize;
|
||||
double minFont = MinFontSize;
|
||||
|
||||
FontSize = startFont;
|
||||
|
||||
while (FontSize > minFont)
|
||||
{
|
||||
if (Fits(FontSize))
|
||||
return;
|
||||
|
||||
FontSize -= 0.5;
|
||||
}
|
||||
|
||||
FontSize = minFont;
|
||||
}
|
||||
finally
|
||||
{
|
||||
_isAdjusting = false;
|
||||
}
|
||||
}
|
||||
|
||||
private bool Fits(double fontSize)
|
||||
{
|
||||
double pixelsPerDip = VisualTreeHelper.GetDpi(this).PixelsPerDip;
|
||||
|
||||
var formattedText = new FormattedText(
|
||||
Text ?? string.Empty,
|
||||
CultureInfo.CurrentUICulture,
|
||||
FlowDirection,
|
||||
new Typeface(FontFamily, FontStyle, FontWeight, FontStretch),
|
||||
fontSize,
|
||||
Foreground,
|
||||
pixelsPerDip)
|
||||
{
|
||||
MaxTextWidth = Math.Max(0, ActualWidth),
|
||||
Trimming = TextTrimming.None
|
||||
};
|
||||
|
||||
if (TextWrapping == TextWrapping.Wrap)
|
||||
formattedText.MaxLineCount = MaxLines;
|
||||
|
||||
double lineHeight = fontSize * 1.25;
|
||||
double maxAllowedHeight = lineHeight * MaxLines;
|
||||
|
||||
return formattedText.Height <= maxAllowedHeight + 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -366,7 +366,7 @@ namespace OperationControl.ViewModels
|
|||
{
|
||||
System.Windows.Application.Current.Dispatcher.BeginInvoke(new Action(() =>
|
||||
{
|
||||
_viewOperacaoTop?._vm.AtualizarStatus(status, titulo, linha1, linha2, status_str, resumo);
|
||||
_viewOperacaoTop?._vm.AtualizarStatus(status, titulo, linha1, linha2.Replace("\n\n", " • "), status_str, resumo);
|
||||
}));
|
||||
}
|
||||
|
||||
|
|
@ -546,8 +546,12 @@ namespace OperationControl.ViewModels
|
|||
|
||||
if (rover.RoverId != VariaveisControleOperacao.SelectedRoverId) return;
|
||||
|
||||
string motivos_trajetoria = string.Join("", obj.Trajetoria?.AutonomiaCorredor?.Motivos ?? new List<string>() { "Liberado" });
|
||||
string motivos_controle = string.Join("", obj.Controle?.Motivos ?? new List<string>() { "Liberado" });
|
||||
AtualizarBarraSuperior(obj.StatusRover, rover.RoverId, $"Trajetória: {motivos_trajetoria}", $"Controle: {motivos_controle}", obj.StatusRover.ToString(), (obj.Operacao?.Status ?? StatusOperacao.NaoIniciado).ToString());
|
||||
|
||||
// ESQUERDA
|
||||
var conexao = obj.ModulosSaude?.FirstOrDefault(x => x.modulo == AgroBase.Models.Enums.T_Code.Ipb);
|
||||
var conexao = obj.ModulosSaude?.FirstOrDefault(x => x.modulo == T_Code.Ipb);
|
||||
double c = conexao?.saude ?? 0;
|
||||
double conexao_latencia = conexao?.detalhes?["avg_rtt"]?.Value<double?>() ?? 0.0;
|
||||
double conexao_perda = conexao?.detalhes?["loss_pct"]?.Value<double?>() ?? 0.0;
|
||||
|
|
@ -559,12 +563,12 @@ namespace OperationControl.ViewModels
|
|||
rover?.Descricao ?? "",
|
||||
obj.Controle?.PercentualVelocidadeSPKmh ?? 0,
|
||||
obj.Controle?.Angulo ?? 0,
|
||||
obj.Controle?.TipoMovimento ?? AgroBase.Models.Enums.TipoMovimentoDirecional.Diagnostico,
|
||||
obj.Controle?.TipoMovimento ?? TipoMovimentoDirecional.Diagnostico,
|
||||
obj.Refrigeracao?.Temperatura ?? 0,
|
||||
obj.Bateria?.PercentualBateria ?? 0,
|
||||
obj.Atuador?.PercentualReservatorio ?? 0,
|
||||
$"{c}%",
|
||||
$"{obj.Gnss?.QualidadeFix ?? AgroBase.Models.Enums.TiposCorrecaoGPS.SemCorrecao} {obj.Gnss?.PrecisaoCm:F2} cm"
|
||||
$"{obj.Gnss?.QualidadeFix ?? TiposCorrecaoGPS.SemCorrecao} {obj.Gnss?.PrecisaoCm:F2} cm"
|
||||
);
|
||||
|
||||
// DIREITA (RESUMO)
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@
|
|||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:controls="clr-namespace:OperationControl.Controls"
|
||||
mc:Ignorable="d"
|
||||
d:DesignWidth="1400"
|
||||
d:DesignHeight="92">
|
||||
|
|
@ -41,8 +42,8 @@
|
|||
<Border Grid.Column="2" Margin="10,0,10,0" Background="#14000000" CornerRadius="10" Padding="14,8">
|
||||
<Grid>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="30"/>
|
||||
<RowDefinition Height="24"/>
|
||||
<RowDefinition Height="26"/>
|
||||
<RowDefinition Height="*"/>
|
||||
</Grid.RowDefinitions>
|
||||
|
||||
<!-- STATUS PRINCIPAL -->
|
||||
|
|
@ -51,9 +52,7 @@
|
|||
</Viewbox>
|
||||
|
||||
<!-- MOTIVO -->
|
||||
<Viewbox Grid.Row="1" Stretch="Uniform" StretchDirection="DownOnly" HorizontalAlignment="Left" VerticalAlignment="Center" Height="18">
|
||||
<TextBlock Text="{Binding MotivoPrincipal}" Foreground="#F2F2F2" FontSize="14" FontWeight="SemiBold" TextWrapping="NoWrap"/>
|
||||
</Viewbox>
|
||||
<controls:AutoFitTextBlock Grid.Row="1" Text="{Binding MotivoPrincipal}" Foreground="#F2F2F2" FontSize="14" FontWeight="SemiBold" MinFontSize="10" MaxLines="2" TextWrapping="Wrap" VerticalAlignment="Center"/>
|
||||
</Grid>
|
||||
</Border>
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue