adicionado ferramenta para gerar mapas
This commit is contained in:
parent
60c7468d55
commit
7a1b6bd51d
|
|
@ -3,6 +3,7 @@
|
||||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||||
xmlns:m="clr-namespace:Mapsui.UI.Wpf;assembly=Mapsui.UI.Wpf"
|
xmlns:m="clr-namespace:Mapsui.UI.Wpf;assembly=Mapsui.UI.Wpf"
|
||||||
xmlns:editing="clr-namespace:OperationControl.Mapas.Editing.Views"
|
xmlns:editing="clr-namespace:OperationControl.Mapas.Editing.Views"
|
||||||
|
xmlns:creation="clr-namespace:OperationControl.Mapas.Creation.Views"
|
||||||
x:Name="Root"
|
x:Name="Root"
|
||||||
MinHeight="100"
|
MinHeight="100"
|
||||||
MinWidth="300"
|
MinWidth="300"
|
||||||
|
|
@ -91,5 +92,8 @@
|
||||||
<!-- COCKPIT DO EDITOR DE MAPAS -->
|
<!-- COCKPIT DO EDITOR DE MAPAS -->
|
||||||
<editing:MapaEditorOverlay x:Name="EditorOverlay" Panel.ZIndex="100"/>
|
<editing:MapaEditorOverlay x:Name="EditorOverlay" Panel.ZIndex="100"/>
|
||||||
|
|
||||||
|
<!-- COCKPIT DA CRIAÇÃO DE MAPAS -->
|
||||||
|
<creation:MapaCriacaoOverlay x:Name="CriacaoOverlay" Panel.ZIndex="110"/>
|
||||||
|
|
||||||
</Grid>
|
</Grid>
|
||||||
</UserControl>
|
</UserControl>
|
||||||
File diff suppressed because it is too large
Load Diff
|
|
@ -0,0 +1,844 @@
|
||||||
|
using NetTopologySuite.Geometries;
|
||||||
|
using OperationControl.Mapas.Models;
|
||||||
|
using OperationControl.Mapas.Services;
|
||||||
|
using System.Globalization;
|
||||||
|
using static AgroBase.Models.Enums;
|
||||||
|
|
||||||
|
namespace OperationControl.Mapas.Creation
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Backend puro da criação de mapas por levantamento GNSS.
|
||||||
|
///
|
||||||
|
/// Não conhece WPF, Mapsui, Dock, Rover ou GpsService.
|
||||||
|
/// A futura camada Controller entrega snapshots GNSS válidos
|
||||||
|
/// e pede operações a este serviço.
|
||||||
|
/// </summary>
|
||||||
|
public sealed class MapaCriacaoService
|
||||||
|
{
|
||||||
|
private const double DistanciaMinimaPontoManualMetros = 0.02;
|
||||||
|
|
||||||
|
private readonly MapaValidationService _validationService;
|
||||||
|
|
||||||
|
private readonly GeometryFactory _geometryFactory =
|
||||||
|
new(
|
||||||
|
new PrecisionModel(),
|
||||||
|
4326
|
||||||
|
);
|
||||||
|
|
||||||
|
public MapaCriacaoService(
|
||||||
|
MapaValidationService? validationService = null)
|
||||||
|
{
|
||||||
|
_validationService =
|
||||||
|
validationService
|
||||||
|
?? new MapaValidationService();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public void Iniciar(
|
||||||
|
MapaEstadoCriacao estado,
|
||||||
|
string? nome,
|
||||||
|
TipoMapaOperacao tipo,
|
||||||
|
double distanciaMinimaAutomaticaMetros = 0.50)
|
||||||
|
{
|
||||||
|
ValidarEstado(estado);
|
||||||
|
|
||||||
|
if (estado.EmCriacao)
|
||||||
|
{
|
||||||
|
throw new InvalidOperationException(
|
||||||
|
"Já existe uma sessão de criação de mapa ativa."
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (
|
||||||
|
!double.IsFinite(distanciaMinimaAutomaticaMetros) ||
|
||||||
|
distanciaMinimaAutomaticaMetros <= 0
|
||||||
|
)
|
||||||
|
{
|
||||||
|
throw new ArgumentOutOfRangeException(
|
||||||
|
nameof(distanciaMinimaAutomaticaMetros),
|
||||||
|
"A distância mínima automática deve ser maior que zero."
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
estado.Limpar();
|
||||||
|
|
||||||
|
estado.EmCriacao = true;
|
||||||
|
estado.Nome = NormalizarNome(nome);
|
||||||
|
estado.Tipo = tipo;
|
||||||
|
estado.DistanciaMinimaCapturaAutomaticaMetros =
|
||||||
|
distanciaMinimaAutomaticaMetros;
|
||||||
|
estado.ModoCaptura = MapaModoCapturaCriacao.Manual;
|
||||||
|
estado.GravacaoAutomaticaAtiva = false;
|
||||||
|
|
||||||
|
estado.RuasMutaveis.Add(
|
||||||
|
new MapaRuaCriacao
|
||||||
|
{
|
||||||
|
Numero = 1
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
estado.IndiceRuaAtual = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public void Cancelar(
|
||||||
|
MapaEstadoCriacao estado)
|
||||||
|
{
|
||||||
|
ValidarEstado(estado);
|
||||||
|
estado.Limpar();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public void DefinirNome(
|
||||||
|
MapaEstadoCriacao estado,
|
||||||
|
string? nome)
|
||||||
|
{
|
||||||
|
ValidarEstadoAtivo(estado);
|
||||||
|
estado.Nome = NormalizarNome(nome);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public bool DefinirModoCaptura(
|
||||||
|
MapaEstadoCriacao estado,
|
||||||
|
MapaModoCapturaCriacao modo,
|
||||||
|
out string motivo)
|
||||||
|
{
|
||||||
|
ValidarEstadoAtivo(estado);
|
||||||
|
motivo = string.Empty;
|
||||||
|
|
||||||
|
if (estado.GravacaoAutomaticaAtiva)
|
||||||
|
{
|
||||||
|
motivo =
|
||||||
|
"Finalize a gravação automática antes de trocar o modo.";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
estado.ModoCaptura = modo;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public bool IniciarGravacaoAutomatica(
|
||||||
|
MapaEstadoCriacao estado,
|
||||||
|
out string motivo)
|
||||||
|
{
|
||||||
|
ValidarEstadoAtivo(estado);
|
||||||
|
motivo = string.Empty;
|
||||||
|
|
||||||
|
if (
|
||||||
|
estado.ModoCaptura !=
|
||||||
|
MapaModoCapturaCriacao.Automatico
|
||||||
|
)
|
||||||
|
{
|
||||||
|
motivo =
|
||||||
|
"A captura atual não está no modo automático.";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (estado.GravacaoAutomaticaAtiva)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
if (estado.RuaAtual == null)
|
||||||
|
{
|
||||||
|
motivo =
|
||||||
|
"Não existe rua atual para receber pontos.";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
estado.GravacaoAutomaticaAtiva = true;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public bool PararGravacaoAutomatica(
|
||||||
|
MapaEstadoCriacao estado,
|
||||||
|
out string motivo)
|
||||||
|
{
|
||||||
|
ValidarEstadoAtivo(estado);
|
||||||
|
motivo = string.Empty;
|
||||||
|
estado.GravacaoAutomaticaAtiva = false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public bool TentarAdicionarPontoManual(
|
||||||
|
MapaEstadoCriacao estado,
|
||||||
|
MapaPontoCriacao ponto,
|
||||||
|
out string motivo)
|
||||||
|
{
|
||||||
|
ValidarEstadoAtivo(estado);
|
||||||
|
motivo = string.Empty;
|
||||||
|
|
||||||
|
if (
|
||||||
|
estado.ModoCaptura !=
|
||||||
|
MapaModoCapturaCriacao.Manual
|
||||||
|
)
|
||||||
|
{
|
||||||
|
motivo =
|
||||||
|
"A captura atual está no modo automático.";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (estado.GravacaoAutomaticaAtiva)
|
||||||
|
{
|
||||||
|
motivo =
|
||||||
|
"Finalize a gravação automática antes de registrar um ponto manual.";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return TentarAdicionarPonto(
|
||||||
|
estado,
|
||||||
|
ponto,
|
||||||
|
DistanciaMinimaPontoManualMetros,
|
||||||
|
out motivo
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public bool TentarAdicionarPontoAutomatico(
|
||||||
|
MapaEstadoCriacao estado,
|
||||||
|
MapaPontoCriacao ponto,
|
||||||
|
bool forcarPrimeiroPonto,
|
||||||
|
out string motivo)
|
||||||
|
{
|
||||||
|
ValidarEstadoAtivo(estado);
|
||||||
|
motivo = string.Empty;
|
||||||
|
|
||||||
|
if (
|
||||||
|
estado.ModoCaptura !=
|
||||||
|
MapaModoCapturaCriacao.Automatico ||
|
||||||
|
!estado.GravacaoAutomaticaAtiva
|
||||||
|
)
|
||||||
|
{
|
||||||
|
motivo =
|
||||||
|
"A gravação automática não está ativa.";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
MapaRuaCriacao? rua = estado.RuaAtual;
|
||||||
|
|
||||||
|
if (rua == null)
|
||||||
|
{
|
||||||
|
motivo =
|
||||||
|
"Não existe rua atual para receber pontos.";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (
|
||||||
|
forcarPrimeiroPonto &&
|
||||||
|
rua.QuantidadePontos == 0
|
||||||
|
)
|
||||||
|
{
|
||||||
|
return TentarAdicionarPonto(
|
||||||
|
estado,
|
||||||
|
ponto,
|
||||||
|
distanciaMinimaMetros: 0,
|
||||||
|
out motivo
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return TentarAdicionarPonto(
|
||||||
|
estado,
|
||||||
|
ponto,
|
||||||
|
estado.DistanciaMinimaCapturaAutomaticaMetros,
|
||||||
|
out motivo
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public bool TentarRemoverUltimoPonto(
|
||||||
|
MapaEstadoCriacao estado,
|
||||||
|
out string motivo)
|
||||||
|
{
|
||||||
|
ValidarEstadoAtivo(estado);
|
||||||
|
motivo = string.Empty;
|
||||||
|
|
||||||
|
if (estado.GravacaoAutomaticaAtiva)
|
||||||
|
{
|
||||||
|
motivo =
|
||||||
|
"Finalize a gravação automática antes de remover pontos.";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
MapaRuaCriacao? rua = estado.RuaAtual;
|
||||||
|
|
||||||
|
if (
|
||||||
|
rua == null ||
|
||||||
|
rua.QuantidadePontos <= 0
|
||||||
|
)
|
||||||
|
{
|
||||||
|
motivo =
|
||||||
|
"A rua atual não possui pontos.";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
rua.PontosMutaveis.RemoveAt(
|
||||||
|
rua.QuantidadePontos - 1
|
||||||
|
);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public bool TentarCriarNovaRua(
|
||||||
|
MapaEstadoCriacao estado,
|
||||||
|
out string motivo)
|
||||||
|
{
|
||||||
|
ValidarEstadoAtivo(estado);
|
||||||
|
motivo = string.Empty;
|
||||||
|
|
||||||
|
if (estado.GravacaoAutomaticaAtiva)
|
||||||
|
{
|
||||||
|
motivo =
|
||||||
|
"Finalize a gravação automática antes de criar outra rua.";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
MapaRuaCriacao? atual = estado.RuaAtual;
|
||||||
|
|
||||||
|
if (
|
||||||
|
atual == null ||
|
||||||
|
atual.QuantidadePontos < 2
|
||||||
|
)
|
||||||
|
{
|
||||||
|
int numero =
|
||||||
|
atual?.Numero
|
||||||
|
?? (estado.IndiceRuaAtual + 1);
|
||||||
|
|
||||||
|
motivo =
|
||||||
|
$"Registre pelo menos 2 pontos na rua {numero} antes de criar uma nova rua.";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
estado.RuasMutaveis.Add(
|
||||||
|
new MapaRuaCriacao
|
||||||
|
{
|
||||||
|
Numero =
|
||||||
|
estado.RuasMutaveis.Count + 1
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
estado.IndiceRuaAtual =
|
||||||
|
estado.RuasMutaveis.Count - 1;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public bool TentarSelecionarRua(
|
||||||
|
MapaEstadoCriacao estado,
|
||||||
|
int indiceRua,
|
||||||
|
out string motivo)
|
||||||
|
{
|
||||||
|
ValidarEstadoAtivo(estado);
|
||||||
|
motivo = string.Empty;
|
||||||
|
|
||||||
|
if (estado.GravacaoAutomaticaAtiva)
|
||||||
|
{
|
||||||
|
motivo =
|
||||||
|
"Finalize a gravação automática antes de trocar de rua.";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (
|
||||||
|
indiceRua < 0 ||
|
||||||
|
indiceRua >= estado.RuasMutaveis.Count
|
||||||
|
)
|
||||||
|
{
|
||||||
|
motivo =
|
||||||
|
"A rua informada não existe.";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
estado.IndiceRuaAtual = indiceRua;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public bool TentarExcluirRua(
|
||||||
|
MapaEstadoCriacao estado,
|
||||||
|
int indiceRua,
|
||||||
|
out string motivo)
|
||||||
|
{
|
||||||
|
ValidarEstadoAtivo(estado);
|
||||||
|
motivo = string.Empty;
|
||||||
|
|
||||||
|
if (estado.GravacaoAutomaticaAtiva)
|
||||||
|
{
|
||||||
|
motivo =
|
||||||
|
"Finalize a gravação automática antes de excluir uma rua.";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (
|
||||||
|
indiceRua < 0 ||
|
||||||
|
indiceRua >= estado.RuasMutaveis.Count
|
||||||
|
)
|
||||||
|
{
|
||||||
|
motivo =
|
||||||
|
"A rua informada não existe.";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* A sessão mantém pelo menos uma rua.
|
||||||
|
* Se existe apenas uma, excluir significa limpar a Rua 1.
|
||||||
|
*/
|
||||||
|
if (estado.RuasMutaveis.Count == 1)
|
||||||
|
{
|
||||||
|
estado.RuasMutaveis[0]
|
||||||
|
.PontosMutaveis
|
||||||
|
.Clear();
|
||||||
|
|
||||||
|
estado.IndiceRuaAtual = 0;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
estado.RuasMutaveis.RemoveAt(indiceRua);
|
||||||
|
RenumerarRuas(estado);
|
||||||
|
|
||||||
|
if (
|
||||||
|
estado.IndiceRuaAtual >=
|
||||||
|
estado.RuasMutaveis.Count
|
||||||
|
)
|
||||||
|
{
|
||||||
|
estado.IndiceRuaAtual =
|
||||||
|
estado.RuasMutaveis.Count - 1;
|
||||||
|
}
|
||||||
|
else if (indiceRua < estado.IndiceRuaAtual)
|
||||||
|
{
|
||||||
|
estado.IndiceRuaAtual--;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public void LimparPontos(
|
||||||
|
MapaEstadoCriacao estado)
|
||||||
|
{
|
||||||
|
ValidarEstadoAtivo(estado);
|
||||||
|
|
||||||
|
if (estado.GravacaoAutomaticaAtiva)
|
||||||
|
{
|
||||||
|
throw new InvalidOperationException(
|
||||||
|
"Finalize a gravação automática antes de limpar o levantamento."
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
estado.RuasMutaveis.Clear();
|
||||||
|
estado.RuasMutaveis.Add(
|
||||||
|
new MapaRuaCriacao
|
||||||
|
{
|
||||||
|
Numero = 1
|
||||||
|
}
|
||||||
|
);
|
||||||
|
estado.IndiceRuaAtual = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public MapaResumoCriacao CriarResumo(
|
||||||
|
MapaEstadoCriacao estado)
|
||||||
|
{
|
||||||
|
ValidarEstado(estado);
|
||||||
|
|
||||||
|
MapaRuaCriacao? atual = estado.RuaAtual;
|
||||||
|
|
||||||
|
double comprimentoAtual =
|
||||||
|
atual == null
|
||||||
|
? 0
|
||||||
|
: CalcularComprimentoMetros(
|
||||||
|
atual.Pontos
|
||||||
|
);
|
||||||
|
|
||||||
|
double comprimentoTotal =
|
||||||
|
estado.Ruas.Sum(
|
||||||
|
rua =>
|
||||||
|
CalcularComprimentoMetros(
|
||||||
|
rua.Pontos
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
var ruasResumo =
|
||||||
|
estado.Ruas
|
||||||
|
.Select(
|
||||||
|
(rua, indice) =>
|
||||||
|
new MapaRuaResumoCriacao
|
||||||
|
{
|
||||||
|
Numero = rua.Numero,
|
||||||
|
QuantidadePontos = rua.QuantidadePontos,
|
||||||
|
ComprimentoMetros =
|
||||||
|
CalcularComprimentoMetros(rua.Pontos),
|
||||||
|
Valida = rua.Valida,
|
||||||
|
Atual = indice == estado.IndiceRuaAtual
|
||||||
|
}
|
||||||
|
)
|
||||||
|
.ToList();
|
||||||
|
|
||||||
|
return new MapaResumoCriacao
|
||||||
|
{
|
||||||
|
EmCriacao = estado.EmCriacao,
|
||||||
|
Nome = estado.Nome,
|
||||||
|
RuaAtual = atual?.Numero ?? 0,
|
||||||
|
QuantidadeRuas = estado.QuantidadeRuas,
|
||||||
|
QuantidadeRuasValidas = estado.QuantidadeRuasValidas,
|
||||||
|
PontosRuaAtual = atual?.QuantidadePontos ?? 0,
|
||||||
|
PontosTotal = estado.QuantidadePontosTotal,
|
||||||
|
ComprimentoRuaAtualMetros = comprimentoAtual,
|
||||||
|
ComprimentoTotalMetros = comprimentoTotal,
|
||||||
|
ModoCaptura = estado.ModoCaptura,
|
||||||
|
GravacaoAutomaticaAtiva = estado.GravacaoAutomaticaAtiva,
|
||||||
|
DistanciaMinimaAutomaticaMetros =
|
||||||
|
estado.DistanciaMinimaCapturaAutomaticaMetros,
|
||||||
|
PodeNovaRua = estado.PodeCriarNovaRua,
|
||||||
|
PodeSalvar =
|
||||||
|
estado.PodeSalvar &&
|
||||||
|
!string.IsNullOrWhiteSpace(estado.Nome),
|
||||||
|
Ruas = ruasResumo
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Converte o levantamento transitório para o domínio canônico.
|
||||||
|
/// IDs finais são sempre strings numéricas sequenciais.
|
||||||
|
/// </summary>
|
||||||
|
public MapaDocumento CriarDocumento(
|
||||||
|
MapaEstadoCriacao estado)
|
||||||
|
{
|
||||||
|
ValidarEstadoAtivo(estado);
|
||||||
|
|
||||||
|
if (estado.GravacaoAutomaticaAtiva)
|
||||||
|
{
|
||||||
|
throw new InvalidOperationException(
|
||||||
|
"Finalize a gravação automática antes de gerar o mapa."
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
string nome = NormalizarNome(estado.Nome);
|
||||||
|
|
||||||
|
if (string.IsNullOrWhiteSpace(nome))
|
||||||
|
{
|
||||||
|
throw new InvalidOperationException(
|
||||||
|
"Informe um nome para o novo mapa."
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (estado.Ruas.Count == 0)
|
||||||
|
{
|
||||||
|
throw new InvalidOperationException(
|
||||||
|
"O levantamento não possui ruas."
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < estado.Ruas.Count; i++)
|
||||||
|
{
|
||||||
|
MapaRuaCriacao rua = estado.Ruas[i];
|
||||||
|
|
||||||
|
if (
|
||||||
|
rua == null ||
|
||||||
|
rua.QuantidadePontos < 2
|
||||||
|
)
|
||||||
|
{
|
||||||
|
throw new InvalidOperationException(
|
||||||
|
$"A rua {i + 1} precisa possuir pelo menos 2 pontos."
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var documento =
|
||||||
|
new MapaDocumento
|
||||||
|
{
|
||||||
|
Nome = nome,
|
||||||
|
CaminhoOrigem = null,
|
||||||
|
FormatoOrigem = MapaFormatoOrigem.Desconhecido,
|
||||||
|
Tipo = estado.Tipo,
|
||||||
|
Modificado = true
|
||||||
|
};
|
||||||
|
|
||||||
|
for (int i = 0; i < estado.Ruas.Count; i++)
|
||||||
|
{
|
||||||
|
MapaRuaCriacao ruaCriacao = estado.Ruas[i];
|
||||||
|
|
||||||
|
string id =
|
||||||
|
(i + 1).ToString(
|
||||||
|
CultureInfo.InvariantCulture
|
||||||
|
);
|
||||||
|
|
||||||
|
Coordinate[] coordenadas =
|
||||||
|
ruaCriacao.Pontos
|
||||||
|
.Select(
|
||||||
|
ponto =>
|
||||||
|
new Coordinate(
|
||||||
|
ponto.Longitude,
|
||||||
|
ponto.Latitude
|
||||||
|
)
|
||||||
|
)
|
||||||
|
.ToArray();
|
||||||
|
|
||||||
|
LineString geometria =
|
||||||
|
_geometryFactory.CreateLineString(
|
||||||
|
coordenadas
|
||||||
|
);
|
||||||
|
|
||||||
|
documento.Ruas.Add(
|
||||||
|
new MapaRua
|
||||||
|
{
|
||||||
|
Id = id,
|
||||||
|
IdOriginal = null,
|
||||||
|
IdGeradoAutomaticamente = true,
|
||||||
|
Nome = nome,
|
||||||
|
Geometria = geometria,
|
||||||
|
ComprimentoMetros =
|
||||||
|
CalcularComprimentoMetros(
|
||||||
|
ruaCriacao.Pontos
|
||||||
|
),
|
||||||
|
Dist1 = 0,
|
||||||
|
Dist2 = 0,
|
||||||
|
IndiceFeatureOrigem = i
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
MapaResultadoValidacao validacao =
|
||||||
|
_validationService.Validar(
|
||||||
|
documento
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!validacao.Valido)
|
||||||
|
{
|
||||||
|
string erros =
|
||||||
|
string.Join(
|
||||||
|
Environment.NewLine,
|
||||||
|
validacao.Erros
|
||||||
|
);
|
||||||
|
|
||||||
|
throw new InvalidOperationException(
|
||||||
|
"O mapa criado não passou pela validação canônica:" +
|
||||||
|
Environment.NewLine +
|
||||||
|
erros
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return documento;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public static double CalcularComprimentoMetros(
|
||||||
|
IReadOnlyList<MapaPontoCriacao> pontos)
|
||||||
|
{
|
||||||
|
if (
|
||||||
|
pontos == null ||
|
||||||
|
pontos.Count < 2
|
||||||
|
)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
double total = 0;
|
||||||
|
|
||||||
|
for (int i = 1; i < pontos.Count; i++)
|
||||||
|
{
|
||||||
|
total += CalcularDistanciaMetros(
|
||||||
|
pontos[i - 1],
|
||||||
|
pontos[i]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return total;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public static double CalcularDistanciaMetros(
|
||||||
|
MapaPontoCriacao a,
|
||||||
|
MapaPontoCriacao b)
|
||||||
|
{
|
||||||
|
if (
|
||||||
|
a == null ||
|
||||||
|
b == null
|
||||||
|
)
|
||||||
|
{
|
||||||
|
return double.PositiveInfinity;
|
||||||
|
}
|
||||||
|
|
||||||
|
const double raioTerraMetros = 6378137.0;
|
||||||
|
|
||||||
|
double lat1 = GrausParaRadianos(a.Latitude);
|
||||||
|
double lat2 = GrausParaRadianos(b.Latitude);
|
||||||
|
double dLat = GrausParaRadianos(b.Latitude - a.Latitude);
|
||||||
|
double dLon = GrausParaRadianos(b.Longitude - a.Longitude);
|
||||||
|
|
||||||
|
double h =
|
||||||
|
Math.Sin(dLat / 2.0) * Math.Sin(dLat / 2.0) +
|
||||||
|
Math.Cos(lat1) *
|
||||||
|
Math.Cos(lat2) *
|
||||||
|
Math.Sin(dLon / 2.0) * Math.Sin(dLon / 2.0);
|
||||||
|
|
||||||
|
h = Math.Clamp(h, 0.0, 1.0);
|
||||||
|
|
||||||
|
return
|
||||||
|
2.0 *
|
||||||
|
raioTerraMetros *
|
||||||
|
Math.Atan2(
|
||||||
|
Math.Sqrt(h),
|
||||||
|
Math.Sqrt(1.0 - h)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private static bool TentarAdicionarPonto(
|
||||||
|
MapaEstadoCriacao estado,
|
||||||
|
MapaPontoCriacao ponto,
|
||||||
|
double distanciaMinimaMetros,
|
||||||
|
out string motivo)
|
||||||
|
{
|
||||||
|
motivo = string.Empty;
|
||||||
|
|
||||||
|
if (ponto == null)
|
||||||
|
{
|
||||||
|
motivo =
|
||||||
|
"O ponto informado é nulo.";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (
|
||||||
|
!CoordenadaValida(
|
||||||
|
ponto.Latitude,
|
||||||
|
ponto.Longitude
|
||||||
|
)
|
||||||
|
)
|
||||||
|
{
|
||||||
|
motivo =
|
||||||
|
"O ponto informado possui coordenada inválida.";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
MapaRuaCriacao? rua = estado.RuaAtual;
|
||||||
|
|
||||||
|
if (rua == null)
|
||||||
|
{
|
||||||
|
motivo =
|
||||||
|
"Não existe rua atual para receber pontos.";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (
|
||||||
|
rua.QuantidadePontos > 0 &&
|
||||||
|
distanciaMinimaMetros > 0
|
||||||
|
)
|
||||||
|
{
|
||||||
|
MapaPontoCriacao ultimo =
|
||||||
|
rua.Pontos[
|
||||||
|
rua.QuantidadePontos - 1
|
||||||
|
];
|
||||||
|
|
||||||
|
double distancia =
|
||||||
|
CalcularDistanciaMetros(
|
||||||
|
ultimo,
|
||||||
|
ponto
|
||||||
|
);
|
||||||
|
|
||||||
|
if (
|
||||||
|
!double.IsFinite(distancia) ||
|
||||||
|
distancia < distanciaMinimaMetros
|
||||||
|
)
|
||||||
|
{
|
||||||
|
motivo =
|
||||||
|
"Ponto ignorado: distância do último ponto = " +
|
||||||
|
$"{distancia:F3} m; mínimo = " +
|
||||||
|
$"{distanciaMinimaMetros:F3} m.";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* O estado guarda um snapshot próprio.
|
||||||
|
* Nenhuma referência externa fica viva aqui dentro.
|
||||||
|
*/
|
||||||
|
rua.PontosMutaveis.Add(
|
||||||
|
ponto.Clonar()
|
||||||
|
);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private static bool CoordenadaValida(
|
||||||
|
double latitude,
|
||||||
|
double longitude)
|
||||||
|
{
|
||||||
|
return
|
||||||
|
double.IsFinite(latitude) &&
|
||||||
|
double.IsFinite(longitude) &&
|
||||||
|
latitude >= -90.0 &&
|
||||||
|
latitude <= 90.0 &&
|
||||||
|
longitude >= -180.0 &&
|
||||||
|
longitude <= 180.0 &&
|
||||||
|
(
|
||||||
|
Math.Abs(latitude) > 1e-12 ||
|
||||||
|
Math.Abs(longitude) > 1e-12
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private static void RenumerarRuas(
|
||||||
|
MapaEstadoCriacao estado)
|
||||||
|
{
|
||||||
|
for (
|
||||||
|
int i = 0;
|
||||||
|
i < estado.RuasMutaveis.Count;
|
||||||
|
i++
|
||||||
|
)
|
||||||
|
{
|
||||||
|
estado.RuasMutaveis[i].Numero = i + 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private static string NormalizarNome(
|
||||||
|
string? nome)
|
||||||
|
{
|
||||||
|
return
|
||||||
|
string.IsNullOrWhiteSpace(nome)
|
||||||
|
? string.Empty
|
||||||
|
: nome.Trim();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private static double GrausParaRadianos(
|
||||||
|
double graus)
|
||||||
|
{
|
||||||
|
return
|
||||||
|
graus *
|
||||||
|
Math.PI /
|
||||||
|
180.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private static void ValidarEstado(
|
||||||
|
MapaEstadoCriacao estado)
|
||||||
|
{
|
||||||
|
if (estado == null)
|
||||||
|
{
|
||||||
|
throw new ArgumentNullException(
|
||||||
|
nameof(estado)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private static void ValidarEstadoAtivo(
|
||||||
|
MapaEstadoCriacao estado)
|
||||||
|
{
|
||||||
|
ValidarEstado(estado);
|
||||||
|
|
||||||
|
if (!estado.EmCriacao)
|
||||||
|
{
|
||||||
|
throw new InvalidOperationException(
|
||||||
|
"Não existe uma sessão de criação de mapa ativa."
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,62 @@
|
||||||
|
using static AgroBase.Models.Enums;
|
||||||
|
|
||||||
|
namespace OperationControl.Mapas.Creation
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Estado transitório da criação de mapa.
|
||||||
|
/// Não altera o Workspace até o operador explicitamente concluir.
|
||||||
|
/// </summary>
|
||||||
|
public sealed class MapaEstadoCriacao
|
||||||
|
{
|
||||||
|
private readonly List<MapaRuaCriacao> _ruas = new();
|
||||||
|
|
||||||
|
public bool EmCriacao { get; internal set; }
|
||||||
|
public string Nome { get; internal set; } = string.Empty;
|
||||||
|
public TipoMapaOperacao Tipo { get; internal set; } = TipoMapaOperacao.Indefinido;
|
||||||
|
public MapaModoCapturaCriacao ModoCaptura { get; internal set; } = MapaModoCapturaCriacao.Manual;
|
||||||
|
public bool GravacaoAutomaticaAtiva { get; internal set; }
|
||||||
|
public double DistanciaMinimaCapturaAutomaticaMetros { get; internal set; } = 0.50;
|
||||||
|
public int IndiceRuaAtual { get; internal set; }
|
||||||
|
|
||||||
|
public IReadOnlyList<MapaRuaCriacao> Ruas => _ruas;
|
||||||
|
internal List<MapaRuaCriacao> RuasMutaveis => _ruas;
|
||||||
|
|
||||||
|
public int QuantidadeRuas => _ruas.Count;
|
||||||
|
public int QuantidadeRuasValidas => _ruas.Count(x => x != null && x.Valida);
|
||||||
|
public int QuantidadePontosTotal => _ruas.Sum(x => x?.QuantidadePontos ?? 0);
|
||||||
|
|
||||||
|
public MapaRuaCriacao? RuaAtual
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
if (IndiceRuaAtual < 0 || IndiceRuaAtual >= _ruas.Count)
|
||||||
|
return null;
|
||||||
|
|
||||||
|
return _ruas[IndiceRuaAtual];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool PodeCriarNovaRua =>
|
||||||
|
EmCriacao &&
|
||||||
|
!GravacaoAutomaticaAtiva &&
|
||||||
|
RuaAtual?.Valida == true;
|
||||||
|
|
||||||
|
public bool PodeSalvar =>
|
||||||
|
EmCriacao &&
|
||||||
|
!GravacaoAutomaticaAtiva &&
|
||||||
|
_ruas.Count > 0 &&
|
||||||
|
_ruas.All(x => x != null && x.Valida);
|
||||||
|
|
||||||
|
internal void Limpar()
|
||||||
|
{
|
||||||
|
_ruas.Clear();
|
||||||
|
EmCriacao = false;
|
||||||
|
Nome = string.Empty;
|
||||||
|
Tipo = TipoMapaOperacao.Indefinido;
|
||||||
|
ModoCaptura = MapaModoCapturaCriacao.Manual;
|
||||||
|
GravacaoAutomaticaAtiva = false;
|
||||||
|
DistanciaMinimaCapturaAutomaticaMetros = 0.50;
|
||||||
|
IndiceRuaAtual = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,11 @@
|
||||||
|
namespace OperationControl.Mapas.Creation
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Forma como os pontos da rua atual são registrados.
|
||||||
|
/// </summary>
|
||||||
|
public enum MapaModoCapturaCriacao
|
||||||
|
{
|
||||||
|
Manual = 0,
|
||||||
|
Automatico = 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,33 @@
|
||||||
|
using static AgroBase.Models.Enums;
|
||||||
|
|
||||||
|
namespace OperationControl.Mapas.Creation
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Snapshot de um ponto coletado durante a criação de um mapa.
|
||||||
|
/// Latitude/Longitude são sempre WGS84.
|
||||||
|
/// </summary>
|
||||||
|
public sealed class MapaPontoCriacao
|
||||||
|
{
|
||||||
|
public double Latitude { get; set; }
|
||||||
|
public double Longitude { get; set; }
|
||||||
|
public double Altitude { get; set; }
|
||||||
|
public double PrecisaoCm { get; set; }
|
||||||
|
public int NumeroSatelites { get; set; }
|
||||||
|
public TiposCorrecaoGPS QualidadeFix { get; set; }
|
||||||
|
public DateTime Momento { get; set; }
|
||||||
|
|
||||||
|
public MapaPontoCriacao Clonar()
|
||||||
|
{
|
||||||
|
return new MapaPontoCriacao
|
||||||
|
{
|
||||||
|
Latitude = Latitude,
|
||||||
|
Longitude = Longitude,
|
||||||
|
Altitude = Altitude,
|
||||||
|
PrecisaoCm = PrecisaoCm,
|
||||||
|
NumeroSatelites = NumeroSatelites,
|
||||||
|
QualidadeFix = QualidadeFix,
|
||||||
|
Momento = Momento
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,53 @@
|
||||||
|
namespace OperationControl.Mapas.Creation
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// DTO pronto para alimentar o cockpit de criação.
|
||||||
|
///
|
||||||
|
/// O bloco GNSS é preenchido pelo Controller, pois o service
|
||||||
|
/// de domínio não conhece GpsService/GPSModel.
|
||||||
|
/// </summary>
|
||||||
|
public sealed class MapaResumoCriacao
|
||||||
|
{
|
||||||
|
public bool EmCriacao { get; init; }
|
||||||
|
|
||||||
|
public string Nome { get; init; } =
|
||||||
|
string.Empty;
|
||||||
|
|
||||||
|
public int RuaAtual { get; init; }
|
||||||
|
|
||||||
|
public int QuantidadeRuas { get; init; }
|
||||||
|
|
||||||
|
public int QuantidadeRuasValidas { get; init; }
|
||||||
|
|
||||||
|
public int PontosRuaAtual { get; init; }
|
||||||
|
|
||||||
|
public int PontosTotal { get; init; }
|
||||||
|
|
||||||
|
public double ComprimentoRuaAtualMetros { get; init; }
|
||||||
|
|
||||||
|
public double ComprimentoTotalMetros { get; init; }
|
||||||
|
|
||||||
|
public MapaModoCapturaCriacao ModoCaptura { get; init; }
|
||||||
|
|
||||||
|
public bool GravacaoAutomaticaAtiva { get; init; }
|
||||||
|
|
||||||
|
public double DistanciaMinimaAutomaticaMetros { get; init; }
|
||||||
|
|
||||||
|
public bool PodeNovaRua { get; init; }
|
||||||
|
|
||||||
|
public bool PodeSalvar { get; init; }
|
||||||
|
|
||||||
|
public IReadOnlyList<MapaRuaResumoCriacao> Ruas { get; init; } =
|
||||||
|
Array.Empty<MapaRuaResumoCriacao>();
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Estado do GNSS local para o cockpit.
|
||||||
|
*/
|
||||||
|
public bool LeituraGnssValida { get; init; }
|
||||||
|
|
||||||
|
public bool QualidadeAlta { get; init; }
|
||||||
|
|
||||||
|
public string StatusGnss { get; init; } =
|
||||||
|
"GNSS sem leitura.";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,18 @@
|
||||||
|
namespace OperationControl.Mapas.Creation
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Uma rua ainda em levantamento.
|
||||||
|
/// O ID canônico definitivo é gerado na conversão para MapaDocumento.
|
||||||
|
/// </summary>
|
||||||
|
public sealed class MapaRuaCriacao
|
||||||
|
{
|
||||||
|
private readonly List<MapaPontoCriacao> _pontos = new();
|
||||||
|
|
||||||
|
public int Numero { get; internal set; }
|
||||||
|
public IReadOnlyList<MapaPontoCriacao> Pontos => _pontos;
|
||||||
|
public int QuantidadePontos => _pontos.Count;
|
||||||
|
public bool Valida => _pontos.Count >= 2;
|
||||||
|
|
||||||
|
internal List<MapaPontoCriacao> PontosMutaveis => _pontos;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,25 @@
|
||||||
|
namespace OperationControl.Mapas.Creation
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Linha resumida exibida no seletor de ruas do cockpit.
|
||||||
|
/// </summary>
|
||||||
|
public sealed class MapaRuaResumoCriacao
|
||||||
|
{
|
||||||
|
public int Numero { get; init; }
|
||||||
|
|
||||||
|
public int QuantidadePontos { get; init; }
|
||||||
|
|
||||||
|
public double ComprimentoMetros { get; init; }
|
||||||
|
|
||||||
|
public bool Valida { get; init; }
|
||||||
|
|
||||||
|
public bool Atual { get; init; }
|
||||||
|
|
||||||
|
|
||||||
|
public string Descricao =>
|
||||||
|
$"Rua {Numero} • " +
|
||||||
|
$"{QuantidadePontos} pts • " +
|
||||||
|
$"{ComprimentoMetros:F1} m" +
|
||||||
|
(Atual ? " • atual" : string.Empty);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,273 @@
|
||||||
|
<UserControl x:Class="OperationControl.Mapas.Creation.Views.MapaCriacaoOverlay"
|
||||||
|
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||||
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||||
|
Visibility="Collapsed"
|
||||||
|
IsHitTestVisible="False">
|
||||||
|
|
||||||
|
<UserControl.Resources>
|
||||||
|
<Style x:Key="CreationButtonStyle" TargetType="Button">
|
||||||
|
<Setter Property="Height" Value="36"/>
|
||||||
|
<Setter Property="Foreground" Value="White"/>
|
||||||
|
<Setter Property="Background" Value="#303030"/>
|
||||||
|
<Setter Property="BorderBrush" Value="#505050"/>
|
||||||
|
<Setter Property="BorderThickness" Value="1"/>
|
||||||
|
<Setter Property="FontSize" Value="11"/>
|
||||||
|
<Setter Property="FontWeight" Value="SemiBold"/>
|
||||||
|
<Setter Property="Cursor" Value="Hand"/>
|
||||||
|
<Setter Property="Padding" Value="8,4"/>
|
||||||
|
<Setter Property="HorizontalContentAlignment" Value="Center"/>
|
||||||
|
<Setter Property="VerticalContentAlignment" Value="Center"/>
|
||||||
|
</Style>
|
||||||
|
|
||||||
|
<Style x:Key="CreationPrimaryButtonStyle"
|
||||||
|
TargetType="Button"
|
||||||
|
BasedOn="{StaticResource CreationButtonStyle}">
|
||||||
|
<Setter Property="Background" Value="#18794E"/>
|
||||||
|
<Setter Property="BorderBrush" Value="#2AA36B"/>
|
||||||
|
</Style>
|
||||||
|
|
||||||
|
<Style x:Key="CreationDangerButtonStyle"
|
||||||
|
TargetType="Button"
|
||||||
|
BasedOn="{StaticResource CreationButtonStyle}">
|
||||||
|
<Setter Property="Background" Value="#4A2626"/>
|
||||||
|
<Setter Property="BorderBrush" Value="#704040"/>
|
||||||
|
</Style>
|
||||||
|
|
||||||
|
<Style x:Key="CreationLabelStyle" TargetType="TextBlock">
|
||||||
|
<Setter Property="Foreground" Value="#9E9E9E"/>
|
||||||
|
<Setter Property="FontSize" Value="10"/>
|
||||||
|
</Style>
|
||||||
|
</UserControl.Resources>
|
||||||
|
|
||||||
|
<Grid>
|
||||||
|
<Border Width="344"
|
||||||
|
MaxHeight="720"
|
||||||
|
Margin="14"
|
||||||
|
HorizontalAlignment="Left"
|
||||||
|
VerticalAlignment="Top"
|
||||||
|
Background="#F21C1C1C"
|
||||||
|
BorderBrush="#474747"
|
||||||
|
BorderThickness="1"
|
||||||
|
CornerRadius="12"
|
||||||
|
Padding="0">
|
||||||
|
|
||||||
|
<Border.Effect>
|
||||||
|
<DropShadowEffect BlurRadius="18"
|
||||||
|
ShadowDepth="3"
|
||||||
|
Opacity="0.35"/>
|
||||||
|
</Border.Effect>
|
||||||
|
|
||||||
|
<Grid>
|
||||||
|
<Grid.RowDefinitions>
|
||||||
|
<RowDefinition Height="Auto"/>
|
||||||
|
<RowDefinition Height="*"/>
|
||||||
|
</Grid.RowDefinitions>
|
||||||
|
|
||||||
|
<Border Grid.Row="0"
|
||||||
|
Background="#252525"
|
||||||
|
BorderBrush="#3B3B3B"
|
||||||
|
BorderThickness="0,0,0,1"
|
||||||
|
CornerRadius="12,12,0,0"
|
||||||
|
Padding="14,12">
|
||||||
|
<StackPanel>
|
||||||
|
<TextBlock Text="+ Criar novo mapa"
|
||||||
|
Foreground="White"
|
||||||
|
FontSize="16"
|
||||||
|
FontWeight="SemiBold"/>
|
||||||
|
<TextBlock Text="Levantamento GNSS por ruas"
|
||||||
|
Foreground="#909090"
|
||||||
|
FontSize="10"
|
||||||
|
Margin="0,3,0,0"/>
|
||||||
|
</StackPanel>
|
||||||
|
</Border>
|
||||||
|
|
||||||
|
<ScrollViewer Grid.Row="1"
|
||||||
|
VerticalScrollBarVisibility="Auto"
|
||||||
|
HorizontalScrollBarVisibility="Disabled">
|
||||||
|
<StackPanel Margin="14">
|
||||||
|
<TextBlock Text="Nome do mapa"
|
||||||
|
Style="{StaticResource CreationLabelStyle}"/>
|
||||||
|
|
||||||
|
<TextBox x:Name="txtNomeMapa"
|
||||||
|
Height="34"
|
||||||
|
Margin="0,5,0,12"
|
||||||
|
Padding="8,4"
|
||||||
|
Background="#161616"
|
||||||
|
Foreground="White"
|
||||||
|
BorderBrush="#464646"
|
||||||
|
BorderThickness="1"
|
||||||
|
VerticalContentAlignment="Center"
|
||||||
|
TextChanged="txtNomeMapa_TextChanged"/>
|
||||||
|
|
||||||
|
<Border Background="#242424"
|
||||||
|
BorderBrush="#3B3B3B"
|
||||||
|
BorderThickness="1"
|
||||||
|
CornerRadius="8"
|
||||||
|
Padding="10"
|
||||||
|
Margin="0,0,0,10">
|
||||||
|
<Grid>
|
||||||
|
<Grid.ColumnDefinitions>
|
||||||
|
<ColumnDefinition Width="*"/>
|
||||||
|
<ColumnDefinition Width="*"/>
|
||||||
|
</Grid.ColumnDefinitions>
|
||||||
|
|
||||||
|
<StackPanel Grid.Column="0">
|
||||||
|
<TextBlock Text="Rua atual"
|
||||||
|
Style="{StaticResource CreationLabelStyle}"/>
|
||||||
|
<TextBlock x:Name="txtRuaAtual"
|
||||||
|
Text="Rua 1"
|
||||||
|
Foreground="#48D8FF"
|
||||||
|
FontSize="18"
|
||||||
|
FontWeight="Bold"
|
||||||
|
Margin="0,2,0,0"/>
|
||||||
|
</StackPanel>
|
||||||
|
|
||||||
|
<StackPanel Grid.Column="1">
|
||||||
|
<TextBlock Text="Pontos / comprimento"
|
||||||
|
Style="{StaticResource CreationLabelStyle}"/>
|
||||||
|
<TextBlock x:Name="txtResumoRua"
|
||||||
|
Text="0 pts • 0,0 m"
|
||||||
|
Foreground="White"
|
||||||
|
FontSize="13"
|
||||||
|
FontWeight="SemiBold"
|
||||||
|
Margin="0,5,0,0"/>
|
||||||
|
</StackPanel>
|
||||||
|
</Grid>
|
||||||
|
</Border>
|
||||||
|
|
||||||
|
<Border Background="#20272A"
|
||||||
|
BorderBrush="#35505A"
|
||||||
|
BorderThickness="1"
|
||||||
|
CornerRadius="8"
|
||||||
|
Padding="10"
|
||||||
|
Margin="0,0,0,12">
|
||||||
|
<StackPanel>
|
||||||
|
<TextBlock Text="GNSS"
|
||||||
|
Foreground="#65D8FF"
|
||||||
|
FontSize="10"
|
||||||
|
FontWeight="Bold"/>
|
||||||
|
<TextBlock x:Name="txtStatusGnss"
|
||||||
|
Text="Aguardando leitura..."
|
||||||
|
Foreground="#D8D8D8"
|
||||||
|
FontSize="10"
|
||||||
|
TextWrapping="Wrap"
|
||||||
|
Margin="0,4,0,0"/>
|
||||||
|
</StackPanel>
|
||||||
|
</Border>
|
||||||
|
|
||||||
|
<TextBlock Text="Captura dos pontos"
|
||||||
|
Style="{StaticResource CreationLabelStyle}"/>
|
||||||
|
|
||||||
|
<StackPanel Orientation="Horizontal"
|
||||||
|
Margin="0,6,0,8">
|
||||||
|
<RadioButton x:Name="rbManual"
|
||||||
|
Content="Manual"
|
||||||
|
Foreground="White"
|
||||||
|
Margin="0,0,18,0"
|
||||||
|
Checked="rbModo_Checked"/>
|
||||||
|
<RadioButton x:Name="rbAutomatico"
|
||||||
|
Content="Automático"
|
||||||
|
Foreground="White"
|
||||||
|
Checked="rbModo_Checked"/>
|
||||||
|
</StackPanel>
|
||||||
|
|
||||||
|
<Button x:Name="btnRegistrarPonto"
|
||||||
|
Content="+ Registrar ponto"
|
||||||
|
Style="{StaticResource CreationPrimaryButtonStyle}"
|
||||||
|
Click="btnRegistrarPonto_Click"/>
|
||||||
|
|
||||||
|
<Button x:Name="btnCapturaAutomatica"
|
||||||
|
Content="▶ Iniciar captura automática"
|
||||||
|
Style="{StaticResource CreationPrimaryButtonStyle}"
|
||||||
|
Margin="0,7,0,0"
|
||||||
|
Click="btnCapturaAutomatica_Click"/>
|
||||||
|
|
||||||
|
<Button x:Name="btnRemoverUltimoPonto"
|
||||||
|
Content="↶ Remover último ponto"
|
||||||
|
Style="{StaticResource CreationButtonStyle}"
|
||||||
|
Margin="0,7,0,0"
|
||||||
|
Click="btnRemoverUltimoPonto_Click"/>
|
||||||
|
|
||||||
|
<Separator Margin="0,14,0,12"
|
||||||
|
Background="#404040"/>
|
||||||
|
|
||||||
|
<TextBlock Text="Ruas levantadas"
|
||||||
|
Style="{StaticResource CreationLabelStyle}"/>
|
||||||
|
|
||||||
|
<ComboBox x:Name="cmbRuas"
|
||||||
|
Height="34"
|
||||||
|
Margin="0,5,0,8"
|
||||||
|
DisplayMemberPath="Descricao"
|
||||||
|
SelectedValuePath="Numero"
|
||||||
|
SelectionChanged="cmbRuas_SelectionChanged"/>
|
||||||
|
|
||||||
|
<Grid>
|
||||||
|
<Grid.ColumnDefinitions>
|
||||||
|
<ColumnDefinition Width="*"/>
|
||||||
|
<ColumnDefinition Width="8"/>
|
||||||
|
<ColumnDefinition Width="*"/>
|
||||||
|
</Grid.ColumnDefinitions>
|
||||||
|
|
||||||
|
<Button x:Name="btnNovaRua"
|
||||||
|
Grid.Column="0"
|
||||||
|
Content="+ Nova rua"
|
||||||
|
Style="{StaticResource CreationButtonStyle}"
|
||||||
|
Click="btnNovaRua_Click"/>
|
||||||
|
|
||||||
|
<Button x:Name="btnExcluirRua"
|
||||||
|
Grid.Column="2"
|
||||||
|
Content="🗑 Excluir rua"
|
||||||
|
Style="{StaticResource CreationDangerButtonStyle}"
|
||||||
|
Click="btnExcluirRua_Click"/>
|
||||||
|
</Grid>
|
||||||
|
|
||||||
|
<Button x:Name="btnLimpar"
|
||||||
|
Content="Limpar levantamento"
|
||||||
|
Style="{StaticResource CreationDangerButtonStyle}"
|
||||||
|
Margin="0,8,0,0"
|
||||||
|
Click="btnLimpar_Click"/>
|
||||||
|
|
||||||
|
<Border Background="#222222"
|
||||||
|
BorderBrush="#373737"
|
||||||
|
BorderThickness="1"
|
||||||
|
CornerRadius="8"
|
||||||
|
Padding="10"
|
||||||
|
Margin="0,12,0,0">
|
||||||
|
<TextBlock x:Name="txtResumoTotal"
|
||||||
|
Text="1 rua • 0 pontos • 0,0 m"
|
||||||
|
Foreground="#BDBDBD"
|
||||||
|
FontSize="10"
|
||||||
|
TextWrapping="Wrap"/>
|
||||||
|
</Border>
|
||||||
|
|
||||||
|
<Grid Margin="0,14,0,0">
|
||||||
|
<Grid.ColumnDefinitions>
|
||||||
|
<ColumnDefinition Width="*"/>
|
||||||
|
<ColumnDefinition Width="8"/>
|
||||||
|
<ColumnDefinition Width="*"/>
|
||||||
|
</Grid.ColumnDefinitions>
|
||||||
|
|
||||||
|
<Button x:Name="btnCancelar"
|
||||||
|
Grid.Column="0"
|
||||||
|
Content="✕ Cancelar"
|
||||||
|
Style="{StaticResource CreationButtonStyle}"
|
||||||
|
Click="btnCancelar_Click"/>
|
||||||
|
|
||||||
|
<Button x:Name="btnSalvar"
|
||||||
|
Grid.Column="2"
|
||||||
|
Content="💾 Salvar mapa"
|
||||||
|
Style="{StaticResource CreationPrimaryButtonStyle}"
|
||||||
|
Click="btnSalvar_Click"/>
|
||||||
|
</Grid>
|
||||||
|
|
||||||
|
<TextBlock Text="Salvar gera o GeoJSON e já o carrega como mapa oficial."
|
||||||
|
Foreground="#777777"
|
||||||
|
FontSize="9"
|
||||||
|
TextWrapping="Wrap"
|
||||||
|
Margin="0,8,0,0"/>
|
||||||
|
</StackPanel>
|
||||||
|
</ScrollViewer>
|
||||||
|
</Grid>
|
||||||
|
</Border>
|
||||||
|
</Grid>
|
||||||
|
</UserControl>
|
||||||
|
|
@ -0,0 +1,178 @@
|
||||||
|
using OperationControl.Mapas.Creation;
|
||||||
|
using System.Windows;
|
||||||
|
using System.Windows.Controls;
|
||||||
|
|
||||||
|
namespace OperationControl.Mapas.Creation.Views
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Cockpit passivo da criação de mapas.
|
||||||
|
/// Exibe estado e emite intenções. Não altera mapa ou GNSS.
|
||||||
|
/// </summary>
|
||||||
|
public partial class MapaCriacaoOverlay : System.Windows.Controls.UserControl
|
||||||
|
{
|
||||||
|
public event Action<string>? NomeMapaAlterado;
|
||||||
|
public event Action<MapaModoCapturaCriacao>? ModoCapturaAlterado;
|
||||||
|
public event Action? RegistrarPontoSolicitado;
|
||||||
|
public event Action? RemoverUltimoPontoSolicitado;
|
||||||
|
public event Action? IniciarCapturaAutomaticaSolicitado;
|
||||||
|
public event Action? FinalizarCapturaAutomaticaSolicitado;
|
||||||
|
public event Action? NovaRuaSolicitada;
|
||||||
|
public event Action<int>? RuaSelecionada;
|
||||||
|
public event Action<int>? ExcluirRuaSolicitada;
|
||||||
|
public event Action? LimparSolicitado;
|
||||||
|
public event Action? SalvarSolicitado;
|
||||||
|
public event Action? CancelarSolicitado;
|
||||||
|
|
||||||
|
private bool _atualizandoEstado;
|
||||||
|
private MapaResumoCriacao? _ultimoResumo;
|
||||||
|
|
||||||
|
public MapaCriacaoOverlay()
|
||||||
|
{
|
||||||
|
InitializeComponent();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void AtualizarEstado(MapaResumoCriacao? resumo)
|
||||||
|
{
|
||||||
|
_atualizandoEstado = true;
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
_ultimoResumo = resumo;
|
||||||
|
|
||||||
|
bool ativo = resumo?.EmCriacao == true;
|
||||||
|
Visibility = ativo ? Visibility.Visible : Visibility.Collapsed;
|
||||||
|
IsHitTestVisible = ativo;
|
||||||
|
|
||||||
|
if (!ativo)
|
||||||
|
return;
|
||||||
|
|
||||||
|
string nome = resumo!.Nome ?? string.Empty;
|
||||||
|
|
||||||
|
if (!string.Equals(txtNomeMapa.Text, nome, StringComparison.Ordinal))
|
||||||
|
{
|
||||||
|
int caret = txtNomeMapa.CaretIndex;
|
||||||
|
txtNomeMapa.Text = nome;
|
||||||
|
txtNomeMapa.CaretIndex = Math.Min(caret, txtNomeMapa.Text.Length);
|
||||||
|
}
|
||||||
|
|
||||||
|
txtRuaAtual.Text = resumo.RuaAtual > 0
|
||||||
|
? $"Rua {resumo.RuaAtual}"
|
||||||
|
: "Sem rua";
|
||||||
|
|
||||||
|
txtResumoRua.Text =
|
||||||
|
$"{resumo.PontosRuaAtual} pts • {resumo.ComprimentoRuaAtualMetros:F1} m";
|
||||||
|
|
||||||
|
txtStatusGnss.Text = string.IsNullOrWhiteSpace(resumo.StatusGnss)
|
||||||
|
? "GNSS sem leitura."
|
||||||
|
: resumo.StatusGnss;
|
||||||
|
|
||||||
|
rbManual.IsChecked = resumo.ModoCaptura == MapaModoCapturaCriacao.Manual;
|
||||||
|
rbAutomatico.IsChecked = resumo.ModoCaptura == MapaModoCapturaCriacao.Automatico;
|
||||||
|
|
||||||
|
cmbRuas.ItemsSource = resumo.Ruas;
|
||||||
|
cmbRuas.SelectedValue = resumo.RuaAtual;
|
||||||
|
|
||||||
|
bool gravando = resumo.GravacaoAutomaticaAtiva;
|
||||||
|
|
||||||
|
btnRegistrarPonto.Visibility =
|
||||||
|
resumo.ModoCaptura == MapaModoCapturaCriacao.Manual
|
||||||
|
? Visibility.Visible
|
||||||
|
: Visibility.Collapsed;
|
||||||
|
|
||||||
|
btnCapturaAutomatica.Visibility =
|
||||||
|
resumo.ModoCaptura == MapaModoCapturaCriacao.Automatico
|
||||||
|
? Visibility.Visible
|
||||||
|
: Visibility.Collapsed;
|
||||||
|
|
||||||
|
btnRegistrarPonto.IsEnabled = !gravando && resumo.LeituraGnssValida;
|
||||||
|
|
||||||
|
btnCapturaAutomatica.Content = gravando
|
||||||
|
? "■ Finalizar captura automática"
|
||||||
|
: "▶ Iniciar captura automática";
|
||||||
|
|
||||||
|
btnCapturaAutomatica.IsEnabled = gravando || resumo.LeituraGnssValida;
|
||||||
|
btnRemoverUltimoPonto.IsEnabled = !gravando && resumo.PontosRuaAtual > 0;
|
||||||
|
btnNovaRua.IsEnabled = resumo.PodeNovaRua;
|
||||||
|
btnExcluirRua.IsEnabled = !gravando && resumo.QuantidadeRuas > 0;
|
||||||
|
btnLimpar.IsEnabled = !gravando && resumo.PontosTotal > 0;
|
||||||
|
cmbRuas.IsEnabled = !gravando && resumo.QuantidadeRuas > 0;
|
||||||
|
rbManual.IsEnabled = !gravando;
|
||||||
|
rbAutomatico.IsEnabled = !gravando;
|
||||||
|
txtNomeMapa.IsEnabled = !gravando;
|
||||||
|
btnSalvar.IsEnabled = resumo.PodeSalvar;
|
||||||
|
|
||||||
|
txtResumoTotal.Text =
|
||||||
|
$"{resumo.QuantidadeRuas} {(resumo.QuantidadeRuas == 1 ? "rua" : "ruas")} • " +
|
||||||
|
$"{resumo.PontosTotal} {(resumo.PontosTotal == 1 ? "ponto" : "pontos")} • " +
|
||||||
|
$"{resumo.ComprimentoTotalMetros:F1} m" +
|
||||||
|
Environment.NewLine +
|
||||||
|
$"{resumo.QuantidadeRuasValidas}/{resumo.QuantidadeRuas} ruas válidas";
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
_atualizandoEstado = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void txtNomeMapa_TextChanged(object sender, TextChangedEventArgs e)
|
||||||
|
{
|
||||||
|
if (_atualizandoEstado)
|
||||||
|
return;
|
||||||
|
|
||||||
|
NomeMapaAlterado?.Invoke(txtNomeMapa.Text);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void rbModo_Checked(object sender, RoutedEventArgs e)
|
||||||
|
{
|
||||||
|
if (_atualizandoEstado)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (rbAutomatico.IsChecked == true)
|
||||||
|
ModoCapturaAlterado?.Invoke(MapaModoCapturaCriacao.Automatico);
|
||||||
|
else if (rbManual.IsChecked == true)
|
||||||
|
ModoCapturaAlterado?.Invoke(MapaModoCapturaCriacao.Manual);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void btnRegistrarPonto_Click(object sender, RoutedEventArgs e) =>
|
||||||
|
RegistrarPontoSolicitado?.Invoke();
|
||||||
|
|
||||||
|
private void btnRemoverUltimoPonto_Click(object sender, RoutedEventArgs e) =>
|
||||||
|
RemoverUltimoPontoSolicitado?.Invoke();
|
||||||
|
|
||||||
|
private void btnCapturaAutomatica_Click(object sender, RoutedEventArgs e)
|
||||||
|
{
|
||||||
|
if (_ultimoResumo?.GravacaoAutomaticaAtiva == true)
|
||||||
|
FinalizarCapturaAutomaticaSolicitado?.Invoke();
|
||||||
|
else
|
||||||
|
IniciarCapturaAutomaticaSolicitado?.Invoke();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void btnNovaRua_Click(object sender, RoutedEventArgs e) =>
|
||||||
|
NovaRuaSolicitada?.Invoke();
|
||||||
|
|
||||||
|
private void cmbRuas_SelectionChanged(object sender, SelectionChangedEventArgs e)
|
||||||
|
{
|
||||||
|
if (_atualizandoEstado)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (cmbRuas.SelectedValue is int numeroRua)
|
||||||
|
RuaSelecionada?.Invoke(numeroRua);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void btnExcluirRua_Click(object sender, RoutedEventArgs e)
|
||||||
|
{
|
||||||
|
int numeroRua = _ultimoResumo?.RuaAtual ?? 0;
|
||||||
|
if (numeroRua > 0)
|
||||||
|
ExcluirRuaSolicitada?.Invoke(numeroRua);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void btnLimpar_Click(object sender, RoutedEventArgs e) =>
|
||||||
|
LimparSolicitado?.Invoke();
|
||||||
|
|
||||||
|
private void btnSalvar_Click(object sender, RoutedEventArgs e) =>
|
||||||
|
SalvarSolicitado?.Invoke();
|
||||||
|
|
||||||
|
private void btnCancelar_Click(object sender, RoutedEventArgs e) =>
|
||||||
|
CancelarSolicitado?.Invoke();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,412 @@
|
||||||
|
using Mapsui;
|
||||||
|
using Mapsui.Layers;
|
||||||
|
using Mapsui.Nts;
|
||||||
|
using Mapsui.Projections;
|
||||||
|
using Mapsui.Styles;
|
||||||
|
using NetTopologySuite.Geometries;
|
||||||
|
using OperationControl.Mapas.Creation;
|
||||||
|
using Brush = Mapsui.Styles.Brush;
|
||||||
|
using Color = Mapsui.Styles.Color;
|
||||||
|
using Font = Mapsui.Styles.Font;
|
||||||
|
using Pen = Mapsui.Styles.Pen;
|
||||||
|
|
||||||
|
namespace OperationControl.Mapas.Rendering
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Preview georreferenciado do mapa ainda em levantamento.
|
||||||
|
///
|
||||||
|
/// Regras visuais:
|
||||||
|
/// - ruas concluídas: verde;
|
||||||
|
/// - rua atual: ciano e mais espessa;
|
||||||
|
/// - pontos da rua atual: marcadores numerados;
|
||||||
|
/// - primeira posição de cada rua: etiqueta R1, R2...
|
||||||
|
///
|
||||||
|
/// Nada aqui altera o MapaWorkspace.
|
||||||
|
/// </summary>
|
||||||
|
public sealed class MapaCriacaoRenderService
|
||||||
|
{
|
||||||
|
public const string NomeCamada =
|
||||||
|
"MapaCriacaoPreview";
|
||||||
|
|
||||||
|
|
||||||
|
public MemoryLayer CriarCamada(
|
||||||
|
MapaEstadoCriacao estado)
|
||||||
|
{
|
||||||
|
if (estado == null)
|
||||||
|
{
|
||||||
|
throw new ArgumentNullException(
|
||||||
|
nameof(estado)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
return new MemoryLayer
|
||||||
|
{
|
||||||
|
Name =
|
||||||
|
NomeCamada,
|
||||||
|
|
||||||
|
Features =
|
||||||
|
CriarFeatures(
|
||||||
|
estado
|
||||||
|
)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public void AtualizarCamada(
|
||||||
|
MemoryLayer camada,
|
||||||
|
MapaEstadoCriacao estado)
|
||||||
|
{
|
||||||
|
if (camada == null)
|
||||||
|
{
|
||||||
|
throw new ArgumentNullException(
|
||||||
|
nameof(camada)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if (estado == null)
|
||||||
|
{
|
||||||
|
throw new ArgumentNullException(
|
||||||
|
nameof(estado)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
camada.Features =
|
||||||
|
CriarFeatures(
|
||||||
|
estado
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private static IEnumerable<IFeature>
|
||||||
|
CriarFeatures(
|
||||||
|
MapaEstadoCriacao estado)
|
||||||
|
{
|
||||||
|
var features =
|
||||||
|
new List<IFeature>();
|
||||||
|
|
||||||
|
|
||||||
|
if (!estado.EmCriacao)
|
||||||
|
{
|
||||||
|
return features;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
for (
|
||||||
|
int indiceRua = 0;
|
||||||
|
indiceRua < estado.Ruas.Count;
|
||||||
|
indiceRua++
|
||||||
|
)
|
||||||
|
{
|
||||||
|
MapaRuaCriacao rua =
|
||||||
|
estado.Ruas[indiceRua];
|
||||||
|
|
||||||
|
|
||||||
|
if (
|
||||||
|
rua == null ||
|
||||||
|
rua.Pontos.Count == 0
|
||||||
|
)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool atual =
|
||||||
|
indiceRua ==
|
||||||
|
estado.IndiceRuaAtual;
|
||||||
|
|
||||||
|
|
||||||
|
Color corLinha =
|
||||||
|
atual
|
||||||
|
? new Color(
|
||||||
|
0,
|
||||||
|
210,
|
||||||
|
255,
|
||||||
|
255
|
||||||
|
)
|
||||||
|
: new Color(
|
||||||
|
95,
|
||||||
|
207,
|
||||||
|
128,
|
||||||
|
255
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* LINHA DA RUA
|
||||||
|
*/
|
||||||
|
if (
|
||||||
|
rua.Pontos.Count >= 2
|
||||||
|
)
|
||||||
|
{
|
||||||
|
Coordinate[] coordenadas =
|
||||||
|
rua
|
||||||
|
.Pontos
|
||||||
|
.Select(
|
||||||
|
ponto =>
|
||||||
|
{
|
||||||
|
var mercator =
|
||||||
|
SphericalMercator
|
||||||
|
.FromLonLat(
|
||||||
|
ponto.Longitude,
|
||||||
|
ponto.Latitude
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
return new Coordinate(
|
||||||
|
mercator.x,
|
||||||
|
mercator.y
|
||||||
|
);
|
||||||
|
}
|
||||||
|
)
|
||||||
|
.ToArray();
|
||||||
|
|
||||||
|
|
||||||
|
var featureLinha =
|
||||||
|
new GeometryFeature
|
||||||
|
{
|
||||||
|
Geometry =
|
||||||
|
new LineString(
|
||||||
|
coordenadas
|
||||||
|
)
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
featureLinha["Tipo"] =
|
||||||
|
"MapaCriacaoRua";
|
||||||
|
|
||||||
|
featureLinha["Rua"] =
|
||||||
|
rua.Numero;
|
||||||
|
|
||||||
|
|
||||||
|
featureLinha.Styles.Add(
|
||||||
|
new VectorStyle
|
||||||
|
{
|
||||||
|
Line =
|
||||||
|
new Pen(
|
||||||
|
corLinha,
|
||||||
|
atual ? 5 : 3
|
||||||
|
)
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
features.Add(
|
||||||
|
featureLinha
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* MARCADOR DO INÍCIO DA RUA
|
||||||
|
*/
|
||||||
|
MapaPontoCriacao primeiro =
|
||||||
|
rua.Pontos[0];
|
||||||
|
|
||||||
|
|
||||||
|
var inicioMercator =
|
||||||
|
SphericalMercator
|
||||||
|
.FromLonLat(
|
||||||
|
primeiro.Longitude,
|
||||||
|
primeiro.Latitude
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
var marcadorRua =
|
||||||
|
new PointFeature(
|
||||||
|
inicioMercator.x,
|
||||||
|
inicioMercator.y
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
marcadorRua["Tipo"] =
|
||||||
|
"MapaCriacaoInicioRua";
|
||||||
|
|
||||||
|
marcadorRua["label"] =
|
||||||
|
$"R{rua.Numero}";
|
||||||
|
|
||||||
|
|
||||||
|
marcadorRua.Styles.Add(
|
||||||
|
new SymbolStyle
|
||||||
|
{
|
||||||
|
SymbolType =
|
||||||
|
SymbolType.Ellipse,
|
||||||
|
|
||||||
|
SymbolScale =
|
||||||
|
atual
|
||||||
|
? 1.25
|
||||||
|
: 1.0,
|
||||||
|
|
||||||
|
Fill =
|
||||||
|
new Brush(
|
||||||
|
corLinha
|
||||||
|
),
|
||||||
|
|
||||||
|
Outline =
|
||||||
|
new Pen(
|
||||||
|
Color.White,
|
||||||
|
2
|
||||||
|
)
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
marcadorRua.Styles.Add(
|
||||||
|
new LabelStyle
|
||||||
|
{
|
||||||
|
LabelColumn =
|
||||||
|
"label",
|
||||||
|
|
||||||
|
ForeColor =
|
||||||
|
Color.White,
|
||||||
|
|
||||||
|
BackColor =
|
||||||
|
null,
|
||||||
|
|
||||||
|
HorizontalAlignment =
|
||||||
|
LabelStyle
|
||||||
|
.HorizontalAlignmentEnum
|
||||||
|
.Center,
|
||||||
|
|
||||||
|
VerticalAlignment =
|
||||||
|
LabelStyle
|
||||||
|
.VerticalAlignmentEnum
|
||||||
|
.Center,
|
||||||
|
|
||||||
|
Font =
|
||||||
|
new Font
|
||||||
|
{
|
||||||
|
Size = 10
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
features.Add(
|
||||||
|
marcadorRua
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* PONTOS DA RUA ATUAL
|
||||||
|
*
|
||||||
|
* Nas ruas concluídas evitamos centenas de marcadores
|
||||||
|
* para manter o mapa limpo e leve.
|
||||||
|
*/
|
||||||
|
if (!atual)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
for (
|
||||||
|
int indicePonto = 0;
|
||||||
|
indicePonto < rua.Pontos.Count;
|
||||||
|
indicePonto++
|
||||||
|
)
|
||||||
|
{
|
||||||
|
MapaPontoCriacao ponto =
|
||||||
|
rua.Pontos[indicePonto];
|
||||||
|
|
||||||
|
|
||||||
|
var mercator =
|
||||||
|
SphericalMercator
|
||||||
|
.FromLonLat(
|
||||||
|
ponto.Longitude,
|
||||||
|
ponto.Latitude
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
var featurePonto =
|
||||||
|
new PointFeature(
|
||||||
|
mercator.x,
|
||||||
|
mercator.y
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
featurePonto["Tipo"] =
|
||||||
|
"MapaCriacaoPonto";
|
||||||
|
|
||||||
|
featurePonto["Rua"] =
|
||||||
|
rua.Numero;
|
||||||
|
|
||||||
|
featurePonto["Ordem"] =
|
||||||
|
indicePonto + 1;
|
||||||
|
|
||||||
|
featurePonto["label"] =
|
||||||
|
(indicePonto + 1)
|
||||||
|
.ToString();
|
||||||
|
|
||||||
|
|
||||||
|
featurePonto.Styles.Add(
|
||||||
|
new SymbolStyle
|
||||||
|
{
|
||||||
|
SymbolType =
|
||||||
|
SymbolType.Ellipse,
|
||||||
|
|
||||||
|
SymbolScale =
|
||||||
|
0.95,
|
||||||
|
|
||||||
|
Fill =
|
||||||
|
new Brush(
|
||||||
|
new Color(
|
||||||
|
0,
|
||||||
|
210,
|
||||||
|
255,
|
||||||
|
255
|
||||||
|
)
|
||||||
|
),
|
||||||
|
|
||||||
|
Outline =
|
||||||
|
new Pen(
|
||||||
|
Color.White,
|
||||||
|
2
|
||||||
|
)
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
featurePonto.Styles.Add(
|
||||||
|
new LabelStyle
|
||||||
|
{
|
||||||
|
LabelColumn =
|
||||||
|
"label",
|
||||||
|
|
||||||
|
ForeColor =
|
||||||
|
Color.White,
|
||||||
|
|
||||||
|
BackColor =
|
||||||
|
null,
|
||||||
|
|
||||||
|
HorizontalAlignment =
|
||||||
|
LabelStyle
|
||||||
|
.HorizontalAlignmentEnum
|
||||||
|
.Center,
|
||||||
|
|
||||||
|
VerticalAlignment =
|
||||||
|
LabelStyle
|
||||||
|
.VerticalAlignmentEnum
|
||||||
|
.Center,
|
||||||
|
|
||||||
|
Font =
|
||||||
|
new Font
|
||||||
|
{
|
||||||
|
Size = 9
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
features.Add(
|
||||||
|
featurePonto
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
return features;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -22,6 +22,7 @@ namespace OperationControl.ViewModels
|
||||||
public event PropertyChangedEventHandler? PropertyChanged;
|
public event PropertyChangedEventHandler? PropertyChanged;
|
||||||
|
|
||||||
public event Action<string, AgroBase.Models.Enums.TipoMapaOperacao>? CarregarMapaSolicitado;
|
public event Action<string, AgroBase.Models.Enums.TipoMapaOperacao>? CarregarMapaSolicitado;
|
||||||
|
public event Action? CriarMapaSolicitado;
|
||||||
public event Action? EditarMapaSolicitado;
|
public event Action? EditarMapaSolicitado;
|
||||||
|
|
||||||
// Método, latitude, longitude, altitude, offset frontal cm, offset lateral cm
|
// Método, latitude, longitude, altitude, offset frontal cm, offset lateral cm
|
||||||
|
|
@ -63,6 +64,7 @@ namespace OperationControl.ViewModels
|
||||||
};
|
};
|
||||||
|
|
||||||
public ICommand CarregarMapaCommand { get; }
|
public ICommand CarregarMapaCommand { get; }
|
||||||
|
public ICommand CriarMapaCommand { get; }
|
||||||
public ICommand EditarMapaCommand { get; }
|
public ICommand EditarMapaCommand { get; }
|
||||||
public ICommand FixarBaseCommand { get; }
|
public ICommand FixarBaseCommand { get; }
|
||||||
public ICommand AplicarOffsetCommand { get; }
|
public ICommand AplicarOffsetCommand { get; }
|
||||||
|
|
@ -73,6 +75,7 @@ namespace OperationControl.ViewModels
|
||||||
public PreparacaoMapaBottomViewModel()
|
public PreparacaoMapaBottomViewModel()
|
||||||
{
|
{
|
||||||
CarregarMapaCommand = new RelayCommand(_ => ExecutarCarregarMapa(), _ => PodeCarregarMapa);
|
CarregarMapaCommand = new RelayCommand(_ => ExecutarCarregarMapa(), _ => PodeCarregarMapa);
|
||||||
|
CriarMapaCommand = new RelayCommand(_ => CriarMapaSolicitado?.Invoke(), _ => PodeCriarMapa);
|
||||||
EditarMapaCommand = new RelayCommand(_ => EditarMapaSolicitado?.Invoke(), _ => PodeEditarMapa);
|
EditarMapaCommand = new RelayCommand(_ => EditarMapaSolicitado?.Invoke(), _ => PodeEditarMapa);
|
||||||
FixarBaseCommand = new RelayCommand(_ => ExecutarFixarBase(), _ => PodeFixarBase);
|
FixarBaseCommand = new RelayCommand(_ => ExecutarFixarBase(), _ => PodeFixarBase);
|
||||||
AplicarOffsetCommand = new RelayCommand(_ => ExecutarAplicarOffset(), _ => PodeEditarOffsetBase);
|
AplicarOffsetCommand = new RelayCommand(_ => ExecutarAplicarOffset(), _ => PodeEditarOffsetBase);
|
||||||
|
|
@ -124,6 +127,7 @@ namespace OperationControl.ViewModels
|
||||||
|
|
||||||
private bool _mapaCarregado;
|
private bool _mapaCarregado;
|
||||||
private bool _edicaoMapaAtiva;
|
private bool _edicaoMapaAtiva;
|
||||||
|
private bool _criacaoMapaAtiva;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Enquanto o editor estiver aberto nesta etapa:
|
/// Enquanto o editor estiver aberto nesta etapa:
|
||||||
|
|
@ -137,20 +141,32 @@ namespace OperationControl.ViewModels
|
||||||
public bool EdicaoMapaAtiva =>
|
public bool EdicaoMapaAtiva =>
|
||||||
_edicaoMapaAtiva;
|
_edicaoMapaAtiva;
|
||||||
|
|
||||||
|
public bool CriacaoMapaAtiva =>
|
||||||
|
_criacaoMapaAtiva;
|
||||||
|
|
||||||
|
public bool PodeCriarMapa =>
|
||||||
|
!_edicaoMapaAtiva &&
|
||||||
|
!_criacaoMapaAtiva &&
|
||||||
|
!FixacaoEmAndamento &&
|
||||||
|
!AlteracaoPapelGnssEmAndamento;
|
||||||
|
|
||||||
public bool PodeEditarMapa =>
|
public bool PodeEditarMapa =>
|
||||||
_mapaCarregado &&
|
_mapaCarregado &&
|
||||||
!_edicaoMapaAtiva &&
|
!_edicaoMapaAtiva &&
|
||||||
|
!_criacaoMapaAtiva &&
|
||||||
!FixacaoEmAndamento &&
|
!FixacaoEmAndamento &&
|
||||||
!AlteracaoPapelGnssEmAndamento;
|
!AlteracaoPapelGnssEmAndamento;
|
||||||
|
|
||||||
public bool PodeContinuar =>
|
public bool PodeContinuar =>
|
||||||
_mapaCarregado &&
|
_mapaCarregado &&
|
||||||
!_edicaoMapaAtiva &&
|
!_edicaoMapaAtiva &&
|
||||||
|
!_criacaoMapaAtiva &&
|
||||||
!FixacaoEmAndamento &&
|
!FixacaoEmAndamento &&
|
||||||
!AlteracaoPapelGnssEmAndamento;
|
!AlteracaoPapelGnssEmAndamento;
|
||||||
|
|
||||||
public bool PodeVoltar =>
|
public bool PodeVoltar =>
|
||||||
!_edicaoMapaAtiva &&
|
!_edicaoMapaAtiva &&
|
||||||
|
!_criacaoMapaAtiva &&
|
||||||
!FixacaoEmAndamento &&
|
!FixacaoEmAndamento &&
|
||||||
!AlteracaoPapelGnssEmAndamento;
|
!AlteracaoPapelGnssEmAndamento;
|
||||||
|
|
||||||
|
|
@ -201,6 +217,10 @@ namespace OperationControl.ViewModels
|
||||||
nameof(PodeEditarMapa)
|
nameof(PodeEditarMapa)
|
||||||
);
|
);
|
||||||
|
|
||||||
|
OnPropertyChanged(
|
||||||
|
nameof(PodeCriarMapa)
|
||||||
|
);
|
||||||
|
|
||||||
OnPropertyChanged(
|
OnPropertyChanged(
|
||||||
nameof(PodeCarregarMapa)
|
nameof(PodeCarregarMapa)
|
||||||
);
|
);
|
||||||
|
|
@ -214,6 +234,22 @@ namespace OperationControl.ViewModels
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void DefinirCriacaoMapaAtiva(bool ativa)
|
||||||
|
{
|
||||||
|
if (_criacaoMapaAtiva == ativa)
|
||||||
|
return;
|
||||||
|
|
||||||
|
_criacaoMapaAtiva = ativa;
|
||||||
|
|
||||||
|
OnPropertyChanged(nameof(CriacaoMapaAtiva));
|
||||||
|
OnPropertyChanged(nameof(PodeCriarMapa));
|
||||||
|
OnPropertyChanged(nameof(PodeEditarMapa));
|
||||||
|
OnPropertyChanged(nameof(PodeCarregarMapa));
|
||||||
|
OnPropertyChanged(nameof(PodeContinuar));
|
||||||
|
OnPropertyChanged(nameof(PodeVoltar));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
private GnssPapelEstacao _papelGnssAtual = GnssPapelEstacao.Indefinido;
|
private GnssPapelEstacao _papelGnssAtual = GnssPapelEstacao.Indefinido;
|
||||||
public GnssPapelEstacao PapelGnssAtual
|
public GnssPapelEstacao PapelGnssAtual
|
||||||
{
|
{
|
||||||
|
|
@ -316,6 +352,10 @@ namespace OperationControl.ViewModels
|
||||||
nameof(PodeEditarMapa)
|
nameof(PodeEditarMapa)
|
||||||
);
|
);
|
||||||
|
|
||||||
|
OnPropertyChanged(
|
||||||
|
nameof(PodeCriarMapa)
|
||||||
|
);
|
||||||
|
|
||||||
OnPropertyChanged(
|
OnPropertyChanged(
|
||||||
nameof(PodeEditarMetodoFixacao)
|
nameof(PodeEditarMetodoFixacao)
|
||||||
);
|
);
|
||||||
|
|
@ -451,6 +491,7 @@ namespace OperationControl.ViewModels
|
||||||
OnPropertyChanged(nameof(FixacaoEmAndamento));
|
OnPropertyChanged(nameof(FixacaoEmAndamento));
|
||||||
OnPropertyChanged(nameof(PodeCarregarMapa));
|
OnPropertyChanged(nameof(PodeCarregarMapa));
|
||||||
OnPropertyChanged(nameof(PodeEditarMapa));
|
OnPropertyChanged(nameof(PodeEditarMapa));
|
||||||
|
OnPropertyChanged(nameof(PodeCriarMapa));
|
||||||
OnPropertyChanged(nameof(PodeEditarMetodoFixacao));
|
OnPropertyChanged(nameof(PodeEditarMetodoFixacao));
|
||||||
OnPropertyChanged(nameof(PodeEditarCoordenadasManuais));
|
OnPropertyChanged(nameof(PodeEditarCoordenadasManuais));
|
||||||
OnPropertyChanged(nameof(PodeEditarOffsetBase));
|
OnPropertyChanged(nameof(PodeEditarOffsetBase));
|
||||||
|
|
@ -480,6 +521,7 @@ namespace OperationControl.ViewModels
|
||||||
|
|
||||||
public bool PodeCarregarMapa =>
|
public bool PodeCarregarMapa =>
|
||||||
!_edicaoMapaAtiva &&
|
!_edicaoMapaAtiva &&
|
||||||
|
!_criacaoMapaAtiva &&
|
||||||
!FixacaoEmAndamento &&
|
!FixacaoEmAndamento &&
|
||||||
!AlteracaoPapelGnssEmAndamento;
|
!AlteracaoPapelGnssEmAndamento;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -8,6 +8,7 @@ using Newtonsoft.Json.Linq;
|
||||||
using OperationControl.Controls;
|
using OperationControl.Controls;
|
||||||
using OperationControl.Helpers;
|
using OperationControl.Helpers;
|
||||||
using OperationControl.Mapas;
|
using OperationControl.Mapas;
|
||||||
|
using OperationControl.Mapas.Creation;
|
||||||
using OperationControl.Mapas.Editing;
|
using OperationControl.Mapas.Editing;
|
||||||
using OperationControl.Mapas.Interaction;
|
using OperationControl.Mapas.Interaction;
|
||||||
using OperationControl.Mapas.Models;
|
using OperationControl.Mapas.Models;
|
||||||
|
|
@ -58,6 +59,7 @@ namespace OperationControl.ViewModels
|
||||||
|
|
||||||
_viewPreparacaoMapaBottom = new PreparacaoMapaBottomView();
|
_viewPreparacaoMapaBottom = new PreparacaoMapaBottomView();
|
||||||
_viewPreparacaoMapaBottom._vm.CarregarMapaSolicitado += OnCarregarMapaSolicitado;
|
_viewPreparacaoMapaBottom._vm.CarregarMapaSolicitado += OnCarregarMapaSolicitado;
|
||||||
|
_viewPreparacaoMapaBottom._vm.CriarMapaSolicitado += OnCriarMapaSolicitado;
|
||||||
_viewPreparacaoMapaBottom._vm.EditarMapaSolicitado += OnEditarMapaPreparacaoSolicitado;
|
_viewPreparacaoMapaBottom._vm.EditarMapaSolicitado += OnEditarMapaPreparacaoSolicitado;
|
||||||
_viewPreparacaoMapaBottom._vm.FixarBaseSolicitado += OnFixarBaseSolicitado;
|
_viewPreparacaoMapaBottom._vm.FixarBaseSolicitado += OnFixarBaseSolicitado;
|
||||||
_viewPreparacaoMapaBottom._vm.AplicarOffsetSolicitado += OnAplicarOffsetSolicitado;
|
_viewPreparacaoMapaBottom._vm.AplicarOffsetSolicitado += OnAplicarOffsetSolicitado;
|
||||||
|
|
@ -97,6 +99,47 @@ namespace OperationControl.ViewModels
|
||||||
.SalvarMapaEditadoSolicitado +=
|
.SalvarMapaEditadoSolicitado +=
|
||||||
OnSalvarMapaEditadoSolicitado;
|
OnSalvarMapaEditadoSolicitado;
|
||||||
|
|
||||||
|
var criacaoOverlay =
|
||||||
|
_viewPreparacaoMapa
|
||||||
|
.MapaPreparacao
|
||||||
|
.CriacaoOverlay;
|
||||||
|
|
||||||
|
criacaoOverlay.NomeMapaAlterado +=
|
||||||
|
nome => _mapas.DefinirNomeCriacaoMapa(nome);
|
||||||
|
|
||||||
|
criacaoOverlay.ModoCapturaAlterado +=
|
||||||
|
modo => _mapas.DefinirModoCapturaCriacao(modo);
|
||||||
|
|
||||||
|
criacaoOverlay.RegistrarPontoSolicitado +=
|
||||||
|
() => _mapas.RegistrarPontoCriacaoManual();
|
||||||
|
|
||||||
|
criacaoOverlay.RemoverUltimoPontoSolicitado +=
|
||||||
|
() => _mapas.RemoverUltimoPontoCriacao();
|
||||||
|
|
||||||
|
criacaoOverlay.IniciarCapturaAutomaticaSolicitado +=
|
||||||
|
() => _mapas.IniciarGravacaoAutomaticaCriacao();
|
||||||
|
|
||||||
|
criacaoOverlay.FinalizarCapturaAutomaticaSolicitado +=
|
||||||
|
() => _mapas.FinalizarGravacaoAutomaticaCriacao();
|
||||||
|
|
||||||
|
criacaoOverlay.NovaRuaSolicitada +=
|
||||||
|
() => _mapas.CriarNovaRuaMapa();
|
||||||
|
|
||||||
|
criacaoOverlay.RuaSelecionada +=
|
||||||
|
numeroRua => _mapas.SelecionarRuaCriacao(numeroRua);
|
||||||
|
|
||||||
|
criacaoOverlay.ExcluirRuaSolicitada +=
|
||||||
|
OnExcluirRuaCriacaoSolicitado;
|
||||||
|
|
||||||
|
criacaoOverlay.LimparSolicitado +=
|
||||||
|
OnLimparCriacaoSolicitado;
|
||||||
|
|
||||||
|
criacaoOverlay.SalvarSolicitado +=
|
||||||
|
OnSalvarMapaCriadoSolicitado;
|
||||||
|
|
||||||
|
criacaoOverlay.CancelarSolicitado +=
|
||||||
|
OnCancelarCriacaoMapaSolicitado;
|
||||||
|
|
||||||
_viewOperacaoLeft = new OperacaoLeftView();
|
_viewOperacaoLeft = new OperacaoLeftView();
|
||||||
|
|
||||||
_viewOperacaoRight = new OperacaoRightView();
|
_viewOperacaoRight = new OperacaoRightView();
|
||||||
|
|
@ -118,6 +161,7 @@ namespace OperationControl.ViewModels
|
||||||
_mapas.ValidacaoEdicaoFalhou += OnMapaValidacaoEdicaoFalhou;
|
_mapas.ValidacaoEdicaoFalhou += OnMapaValidacaoEdicaoFalhou;
|
||||||
_mapas.EstadoMapaAlterado += OnEstadoMapaAlterado;
|
_mapas.EstadoMapaAlterado += OnEstadoMapaAlterado;
|
||||||
_mapas.EstadoEdicaoAlterado += OnEstadoMapaAlterado;
|
_mapas.EstadoEdicaoAlterado += OnEstadoMapaAlterado;
|
||||||
|
_mapas.EstadoCriacaoAlterado += OnEstadoCriacaoAlterado;
|
||||||
|
|
||||||
// Commands
|
// Commands
|
||||||
BackCommand = new RelayCommand(_ => GoBack(), _ => CanGoBack);
|
BackCommand = new RelayCommand(_ => GoBack(), _ => CanGoBack);
|
||||||
|
|
@ -240,7 +284,10 @@ namespace OperationControl.ViewModels
|
||||||
CurrentStep != DockStep.ConfigConexao &&
|
CurrentStep != DockStep.ConfigConexao &&
|
||||||
!(
|
!(
|
||||||
CurrentStep == DockStep.PreparacaoMapa &&
|
CurrentStep == DockStep.PreparacaoMapa &&
|
||||||
_mapas.EdicaoAtiva
|
(
|
||||||
|
_mapas.EdicaoAtiva ||
|
||||||
|
_mapas.CriacaoMapaAtiva
|
||||||
|
)
|
||||||
);
|
);
|
||||||
|
|
||||||
public bool CanGoNext
|
public bool CanGoNext
|
||||||
|
|
@ -254,7 +301,8 @@ namespace OperationControl.ViewModels
|
||||||
|
|
||||||
DockStep.PreparacaoMapa =>
|
DockStep.PreparacaoMapa =>
|
||||||
MapaCarregado &&
|
MapaCarregado &&
|
||||||
!_mapas.EdicaoAtiva,
|
!_mapas.EdicaoAtiva &&
|
||||||
|
!_mapas.CriacaoMapaAtiva,
|
||||||
|
|
||||||
_ =>
|
_ =>
|
||||||
false
|
false
|
||||||
|
|
@ -1266,6 +1314,21 @@ namespace OperationControl.ViewModels
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Snapshot GNSS compartilhado pelas ferramentas de mapa
|
||||||
|
* que fazem levantamento em campo:
|
||||||
|
*
|
||||||
|
* - borda GNSS do editor;
|
||||||
|
* - criação de mapa por ruas.
|
||||||
|
*
|
||||||
|
* O Controller faz Clone() internamente e aplica a mesma
|
||||||
|
* validação de freshness já usada pela borda.
|
||||||
|
*/
|
||||||
|
_mapas.AtualizarGnssLocal(
|
||||||
|
dados
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
_mapas.AtualizarBase(
|
_mapas.AtualizarBase(
|
||||||
dados,
|
dados,
|
||||||
mapaAtual
|
mapaAtual
|
||||||
|
|
@ -1675,6 +1738,8 @@ namespace OperationControl.ViewModels
|
||||||
|
|
||||||
private void OnEstadoMapaAlterado()
|
private void OnEstadoMapaAlterado()
|
||||||
{
|
{
|
||||||
|
MapaCarregado = _mapas.PossuiMapa;
|
||||||
|
|
||||||
_viewPreparacaoMapaBottom?
|
_viewPreparacaoMapaBottom?
|
||||||
._vm?
|
._vm?
|
||||||
.DefinirEdicaoMapaAtiva(
|
.DefinirEdicaoMapaAtiva(
|
||||||
|
|
@ -1695,6 +1760,27 @@ namespace OperationControl.ViewModels
|
||||||
AtualizarEstadoMapaParametrizacao();
|
AtualizarEstadoMapaParametrizacao();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void OnEstadoCriacaoAlterado()
|
||||||
|
{
|
||||||
|
bool ativa = _mapas.CriacaoMapaAtiva;
|
||||||
|
|
||||||
|
_viewPreparacaoMapaBottom?
|
||||||
|
._vm?
|
||||||
|
.DefinirCriacaoMapaAtiva(ativa);
|
||||||
|
|
||||||
|
_viewPreparacaoMapa?
|
||||||
|
.MapaPreparacao?
|
||||||
|
.CriacaoOverlay?
|
||||||
|
.AtualizarEstado(
|
||||||
|
_mapas.ObterResumoCriacaoMapa()
|
||||||
|
);
|
||||||
|
|
||||||
|
OnPropertyChanged(nameof(CanGoBack));
|
||||||
|
OnPropertyChanged(nameof(CanGoNext));
|
||||||
|
CommandManager.InvalidateRequerySuggested();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
private void AtualizarEstadoMapaParametrizacao()
|
private void AtualizarEstadoMapaParametrizacao()
|
||||||
{
|
{
|
||||||
void Atualizar()
|
void Atualizar()
|
||||||
|
|
@ -1858,6 +1944,206 @@ namespace OperationControl.ViewModels
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void OnCriarMapaSolicitado()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (CurrentStep != DockStep.PreparacaoMapa)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (_mapas.EdicaoAtiva || _mapas.CriacaoMapaAtiva)
|
||||||
|
return;
|
||||||
|
|
||||||
|
var dlgTipo = new OperationControl.Windows.SelecaoTipoMapa
|
||||||
|
{
|
||||||
|
Owner = Models.Variaveis.Dock
|
||||||
|
};
|
||||||
|
|
||||||
|
if (dlgTipo.ShowDialog() != true || dlgTipo.Resultado == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
MapViewControl? mapa = _viewPreparacaoMapa?.MapaPreparacao;
|
||||||
|
if (mapa == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
_mapas.IniciarCriacaoMapa(
|
||||||
|
mapa,
|
||||||
|
nome: "NovoMapa",
|
||||||
|
tipo: dlgTipo.Resultado.Value,
|
||||||
|
distanciaMinimaAutomaticaMetros: 0.50
|
||||||
|
);
|
||||||
|
|
||||||
|
_viewPreparacaoMapaBottom?._vm?.DefinirCriacaoMapaAtiva(true);
|
||||||
|
|
||||||
|
if (_viewPreparacaoMapaBottom?._vm != null)
|
||||||
|
{
|
||||||
|
_viewPreparacaoMapaBottom._vm.StatusTexto =
|
||||||
|
"Criação de mapa ativa. Registre os pontos das ruas pelo GNSS.";
|
||||||
|
}
|
||||||
|
|
||||||
|
Models.Variaveis.MostrarLog(
|
||||||
|
"[MAPA][CRIACAO][UI] Cockpit aberto na preparação."
|
||||||
|
);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Models.Variaveis.MostrarLog(
|
||||||
|
"[MAPA][CRIACAO][UI][ERRO] " + ex
|
||||||
|
);
|
||||||
|
|
||||||
|
MessageBox.Show(
|
||||||
|
"Não foi possível iniciar a criação do mapa." +
|
||||||
|
Environment.NewLine + Environment.NewLine + ex.Message,
|
||||||
|
"Criar mapa",
|
||||||
|
MessageBoxButton.OK,
|
||||||
|
MessageBoxImage.Error
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private void OnExcluirRuaCriacaoSolicitado(int numeroRua)
|
||||||
|
{
|
||||||
|
var resposta = MessageBox.Show(
|
||||||
|
$"Excluir a Rua {numeroRua} do levantamento?",
|
||||||
|
"Excluir rua",
|
||||||
|
MessageBoxButton.YesNo,
|
||||||
|
MessageBoxImage.Question
|
||||||
|
);
|
||||||
|
|
||||||
|
if (resposta == MessageBoxResult.Yes)
|
||||||
|
_mapas.ExcluirRuaCriacao(numeroRua);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private void OnLimparCriacaoSolicitado()
|
||||||
|
{
|
||||||
|
var resposta = MessageBox.Show(
|
||||||
|
"Limpar todos os pontos e ruas levantados?",
|
||||||
|
"Limpar levantamento",
|
||||||
|
MessageBoxButton.YesNo,
|
||||||
|
MessageBoxImage.Question
|
||||||
|
);
|
||||||
|
|
||||||
|
if (resposta == MessageBoxResult.Yes)
|
||||||
|
_mapas.LimparLevantamentoCriacao();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private void OnCancelarCriacaoMapaSolicitado()
|
||||||
|
{
|
||||||
|
if (!_mapas.CriacaoMapaAtiva)
|
||||||
|
return;
|
||||||
|
|
||||||
|
MapaResumoCriacao resumo = _mapas.ObterResumoCriacaoMapa();
|
||||||
|
|
||||||
|
if (resumo.PontosTotal > 0)
|
||||||
|
{
|
||||||
|
var resposta = MessageBox.Show(
|
||||||
|
"Cancelar a criação do mapa?" +
|
||||||
|
Environment.NewLine + Environment.NewLine +
|
||||||
|
"Os pontos ainda não salvos serão descartados.",
|
||||||
|
"Cancelar criação",
|
||||||
|
MessageBoxButton.YesNo,
|
||||||
|
MessageBoxImage.Question
|
||||||
|
);
|
||||||
|
|
||||||
|
if (resposta != MessageBoxResult.Yes)
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
_mapas.CancelarCriacaoMapa();
|
||||||
|
|
||||||
|
if (_viewPreparacaoMapaBottom?._vm != null)
|
||||||
|
{
|
||||||
|
_viewPreparacaoMapaBottom._vm.StatusTexto =
|
||||||
|
_mapas.PossuiMapa
|
||||||
|
? "Criação cancelada. O mapa anterior foi restaurado."
|
||||||
|
: "Criação cancelada.";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private void OnSalvarMapaCriadoSolicitado()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (!_mapas.CriacaoMapaAtiva)
|
||||||
|
return;
|
||||||
|
|
||||||
|
MapaResumoCriacao resumo = _mapas.ObterResumoCriacaoMapa();
|
||||||
|
|
||||||
|
if (!resumo.PodeSalvar)
|
||||||
|
{
|
||||||
|
MessageBox.Show(
|
||||||
|
"Para salvar o mapa, informe um nome e garanta que " +
|
||||||
|
"todas as ruas possuam pelo menos 2 pontos.",
|
||||||
|
"Mapa incompleto",
|
||||||
|
MessageBoxButton.OK,
|
||||||
|
MessageBoxImage.Warning
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var dialog = new Microsoft.Win32.SaveFileDialog
|
||||||
|
{
|
||||||
|
Title = "Salvar novo mapa operacional",
|
||||||
|
Filter = "GeoJSON (*.geojson)|*.geojson",
|
||||||
|
DefaultExt = ".geojson",
|
||||||
|
AddExtension = true,
|
||||||
|
OverwritePrompt = true,
|
||||||
|
FileName = _mapas.ObterNomeArquivoSugeridoMapaCriado()
|
||||||
|
};
|
||||||
|
|
||||||
|
if (dialog.ShowDialog() != true)
|
||||||
|
return;
|
||||||
|
|
||||||
|
MapaDocumento documento =
|
||||||
|
_mapas.SalvarECarregarMapaCriado(dialog.FileName);
|
||||||
|
|
||||||
|
MapaCarregado = true;
|
||||||
|
|
||||||
|
_mapas.PrepararMapa(
|
||||||
|
_viewPreparacaoMapa?.MapaPreparacao,
|
||||||
|
modoInteracao: MapaModoInteracao.Visualizacao,
|
||||||
|
enquadrarDocumento: true
|
||||||
|
);
|
||||||
|
|
||||||
|
if (_viewPreparacaoMapaBottom?._vm != null)
|
||||||
|
{
|
||||||
|
_viewPreparacaoMapaBottom._vm.StatusTexto =
|
||||||
|
$"Mapa criado e carregado: {System.IO.Path.GetFileName(dialog.FileName)}";
|
||||||
|
}
|
||||||
|
|
||||||
|
MessageBox.Show(
|
||||||
|
"Mapa criado com sucesso." + Environment.NewLine + Environment.NewLine +
|
||||||
|
$"Ruas: {documento.QuantidadeRuas}" + Environment.NewLine +
|
||||||
|
$"Comprimento total: {documento.ComprimentoTotalMetros:F1} m" +
|
||||||
|
Environment.NewLine + Environment.NewLine +
|
||||||
|
dialog.FileName + Environment.NewLine + Environment.NewLine +
|
||||||
|
"O arquivo já está carregado como mapa oficial.",
|
||||||
|
"Mapa criado",
|
||||||
|
MessageBoxButton.OK,
|
||||||
|
MessageBoxImage.Information
|
||||||
|
);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Models.Variaveis.MostrarLog(
|
||||||
|
"[MAPA][CRIACAO][SALVAR][ERRO] " + ex
|
||||||
|
);
|
||||||
|
|
||||||
|
MessageBox.Show(
|
||||||
|
"Não foi possível salvar/carregar o novo mapa." +
|
||||||
|
Environment.NewLine + Environment.NewLine + ex.Message,
|
||||||
|
"Erro ao criar mapa",
|
||||||
|
MessageBoxButton.OK,
|
||||||
|
MessageBoxImage.Error
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
private void OnEditarMapaPreparacaoSolicitado()
|
private void OnEditarMapaPreparacaoSolicitado()
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
|
|
@ -1884,6 +2170,17 @@ namespace OperationControl.ViewModels
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if (_mapas.CriacaoMapaAtiva)
|
||||||
|
{
|
||||||
|
MessageBox.Show(
|
||||||
|
"Finalize ou cancele a criação do mapa antes de abrir o editor.",
|
||||||
|
"Criação de mapa ativa",
|
||||||
|
MessageBoxButton.OK,
|
||||||
|
MessageBoxImage.Information
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (_mapas.EdicaoAtiva)
|
if (_mapas.EdicaoAtiva)
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
|
|
@ -2106,6 +2403,16 @@ namespace OperationControl.ViewModels
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (_mapas.CriacaoMapaAtiva)
|
||||||
|
{
|
||||||
|
MessageBox.Show(
|
||||||
|
"Finalize ou cancele a criação atual antes de carregar outro mapa.",
|
||||||
|
"Criação de mapa ativa",
|
||||||
|
MessageBoxButton.OK,
|
||||||
|
MessageBoxImage.Information
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
_mapas.CarregarMapaArquivo(caminhoArquivo, tipo);
|
_mapas.CarregarMapaArquivo(caminhoArquivo, tipo);
|
||||||
|
|
||||||
|
|
@ -2132,6 +2439,21 @@ namespace OperationControl.ViewModels
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
if (
|
||||||
|
_mapas.CapturaBordaGnssAutomaticaAtiva ||
|
||||||
|
_mapas.CapturaCriacaoAutomaticaAtiva
|
||||||
|
)
|
||||||
|
{
|
||||||
|
MessageBox.Show(
|
||||||
|
"Finalize o levantamento GNSS automático antes de alterar " +
|
||||||
|
"a configuração física da estação.",
|
||||||
|
"Levantamento em andamento",
|
||||||
|
MessageBoxButton.OK,
|
||||||
|
MessageBoxImage.Warning
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (!(Models.Variaveis.GpsService.BaseFix?.FixLiberado ?? false))
|
if (!(Models.Variaveis.GpsService.BaseFix?.FixLiberado ?? false))
|
||||||
{
|
{
|
||||||
bool fixar = false;
|
bool fixar = false;
|
||||||
|
|
@ -2287,13 +2609,13 @@ namespace OperationControl.ViewModels
|
||||||
* durante uma captura automática da borda.
|
* durante uma captura automática da borda.
|
||||||
*/
|
*/
|
||||||
if (
|
if (
|
||||||
_mapas.CapturaBordaGnssAutomaticaAtiva
|
_mapas.CapturaBordaGnssAutomaticaAtiva ||
|
||||||
|
_mapas.CapturaCriacaoAutomaticaAtiva
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
MessageBox.Show(
|
MessageBox.Show(
|
||||||
"Existe um levantamento GNSS em andamento.\n\n" +
|
"Existe um levantamento GNSS automático em andamento.\n\n" +
|
||||||
"Finalize ou descarte a borda antes de alterar " +
|
"Finalize a captura antes de alterar o modo do receptor.",
|
||||||
"o modo do receptor.",
|
|
||||||
"Levantamento em andamento",
|
"Levantamento em andamento",
|
||||||
MessageBoxButton.OK,
|
MessageBoxButton.OK,
|
||||||
MessageBoxImage.Warning
|
MessageBoxImage.Warning
|
||||||
|
|
|
||||||
|
|
@ -510,6 +510,14 @@
|
||||||
Command="{Binding CarregarMapaCommand}"
|
Command="{Binding CarregarMapaCommand}"
|
||||||
IsEnabled="{Binding PodeCarregarMapa}"/>
|
IsEnabled="{Binding PodeCarregarMapa}"/>
|
||||||
|
|
||||||
|
<Button
|
||||||
|
Content="+ Criar novo mapa"
|
||||||
|
Style="{StaticResource PanelButtonStyle}"
|
||||||
|
Command="{Binding CriarMapaCommand}"
|
||||||
|
IsEnabled="{Binding PodeCriarMapa}"
|
||||||
|
Margin="0,8,0,0"
|
||||||
|
ToolTip="Cria um mapa por levantamento GNSS, rua por rua, sem exigir Rover."/>
|
||||||
|
|
||||||
<Button
|
<Button
|
||||||
Content="✎ Editar mapa"
|
Content="✎ Editar mapa"
|
||||||
Style="{StaticResource PanelButtonStyle}"
|
Style="{StaticResource PanelButtonStyle}"
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue