agrobot_base/AgroBase/OperationControl/Mapas/Controller/MapaOperacaoController.Inte...

722 lines
18 KiB
C#

using NetTopologySuite.Geometries;
using OperationControl.Controls;
using OperationControl.Mapas.Editing;
using OperationControl.Mapas.Interaction;
namespace OperationControl.Mapas
{
public sealed partial class MapaOperacaoController
{
/*
* =========================================================
* CONFIGURAÇÃO DE INTERAÇÃO
* =========================================================
*/
/// <summary>
/// Define explicitamente como o MapViewControl deve
/// interpretar a interação do operador.
///
/// Se a View estiver em uma sessão de edição ativa,
/// o modo Edicao tem prioridade até a sessão terminar.
/// </summary>
public void DefinirModoInteracao(
MapViewControl? mapaControl,
MapaModoInteracao modo)
{
if (
mapaControl?.Mapa?.Map == null
)
{
return;
}
RegistrarMapa(
mapaControl
);
MapaModoInteracao modoEfetivo =
_estadoEdicao.EmEdicao &&
_mapasEmEdicao.Contains(
mapaControl
)
? MapaModoInteracao.Edicao
: modo;
AplicarModoInteracao(
mapaControl,
modoEfetivo
);
}
private void AplicarModoInteracao(
MapViewControl mapaControl,
MapaModoInteracao modo)
{
if (
mapaControl.ModoInteracao ==
modo
)
{
return;
}
var anterior =
mapaControl.ModoInteracao;
mapaControl.DefinirModoInteracao(
modo
);
Log(
"[MAPA][INTERACAO] " +
$"Anterior={anterior} | " +
$"Atual={modo}"
);
}
/*
* =========================================================
* RUA
* =========================================================
*/
private void OnMapaNovoRuaClicada(string ruaId)
{
try
{
/*
* =============================================
* MODO EDIÇÃO
* =============================================
*
* A seleção operacional fica completamente
* intocada.
*/
if (_estadoEdicao.EmEdicao)
{
/*
* Uma rua só responde ao clique direto
* enquanto a ferramenta Selecionar
* estiver ativa.
*/
if (
_ferramentaEdicaoAtual !=
MapaFerramentaEdicao.Selecionar
)
{
return;
}
AlternarRuaEdicao(
ruaId
);
Log(
"[MAPA][EDICAO][CLIQUE] " +
$"Rua={ruaId} | " +
$"Selecionadas=" +
$"{QuantidadeRuasSelecionadasEdicao}"
);
return;
}
/*
* =============================================
* MODO NORMAL
* =============================================
*/
AlternarRuaOperacao(
ruaId
);
string ruas =
string.Join(
" -> ",
ObterRuasPercorrer()
);
Log(
"[MAPA][CLIQUE] " +
$"Rua={ruaId} | " +
$"Percurso=[{ruas}]"
);
}
catch (Exception ex)
{
Log(
"[MAPA][CLIQUE][ERRO] " +
ex.Message
);
}
}
/*
* =========================================================
* RETORNO
* =========================================================
*/
private void OnMapaNovoPontoRetornoClicado(
double latitude,
double longitude)
{
try
{
AlternarPontoRetorno(
latitude,
longitude
);
double distancia =
ObterDistanciaRotaRetornoMetros();
Log(
"[MAPA][RETORNO][CLIQUE] " +
$"Pontos={QuantidadePontosRetorno} | " +
$"Distancia={distancia:F2} m"
);
}
catch (Exception ex)
{
Log(
"[MAPA][RETORNO][CLIQUE][ERRO] " +
ex.Message
);
}
}
/*
* =========================================================
* ENTIDADE
* =========================================================
*/
private void OnMapaNovaEntidadeClicada(
string entidadeId)
{
try
{
var entidade =
ObterEntidade(
entidadeId
);
if (entidade == null)
return;
Log(
"[MAPA][ENTIDADE][CLIQUE] " +
$"Id={entidade.Id} | " +
$"Tipo={entidade.Tipo}"
);
/*
* Fim da responsabilidade do mapa.
*
* Dock decidirá o que significa
* selecionar Base ou Rover.
*/
EntidadeClicada?
.Invoke(
entidade.Id
);
}
catch (Exception ex)
{
Log(
"[MAPA][ENTIDADE][CLIQUE][ERRO] " +
ex.Message
);
}
}
/*
* =========================================================
* VIEWPORT
* =========================================================
*/
private void OnMapaNovoViewportAlterado(
MapViewControl mapaControl)
{
/*
* Somente entidades dependem da resolução
* atual para manter tamanho visual adequado.
*/
RenderizarEntidadesDinamicasNoMapa(
mapaControl
);
mapaControl
.Mapa
.Refresh();
}
private void OnMapaEditorFerramentaSelecionada(MapViewControl mapaControl, MapaFerramentaEdicao ferramenta)
{
if (
!_estadoEdicao.EmEdicao ||
!_mapasEmEdicao.Contains(
mapaControl
)
)
{
return;
}
DefinirFerramentaEdicao(
ferramenta
);
}
private void OnMapaEditorLimparSelecaoSolicitado(MapViewControl mapaControl)
{
if (
!_estadoEdicao.EmEdicao ||
!_mapasEmEdicao.Contains(
mapaControl
)
)
{
return;
}
LimparSelecaoEdicao();
}
private void OnMapaEditorRetanguloSelecionado(MapViewControl mapaControl, MapaRetanguloSelecao retangulo)
{
if (
!_estadoEdicao.EmEdicao ||
!_mapasEmEdicao.Contains(
mapaControl
) ||
_ferramentaEdicaoAtual !=
MapaFerramentaEdicao
.SelecionarRetangulo
)
{
return;
}
try
{
var encontrados =
_edicaoService
.SelecionarPorRetangulo(
_estadoEdicao,
retangulo
.MinLatitude,
retangulo
.MinLongitude,
retangulo
.MaxLatitude,
retangulo
.MaxLongitude,
substituirSelecao:
true
);
foreach (
var mapa
in _mapasEmEdicao
.ToArray())
{
if (
_rendersMapa.TryGetValue(
mapa,
out var render
)
)
{
_edicaoRenderService
.AplicarSelecao(
render,
_estadoEdicao
);
mapa.Mapa.Refresh();
}
}
SincronizarCockpitEdicao();
EstadoEdicaoAlterado?
.Invoke();
Log(
"[MAPA][EDICAO][RETANGULO] " +
$"Encontradas={encontrados.Count} | " +
$"Selecionadas=" +
$"{QuantidadeRuasSelecionadasEdicao}"
);
}
catch (Exception ex)
{
Log(
"[MAPA][EDICAO][RETANGULO][ERRO] " +
ex.Message
);
}
}
private void OnMapaEditorPoligonoRecorteDefinido(MapViewControl mapaControl, MapaPoligonoRecorte recorte)
{
bool ferramentaPoligono =
_ferramentaEdicaoAtual ==
MapaFerramentaEdicao.RecorteLivre
||
_ferramentaEdicaoAtual ==
MapaFerramentaEdicao.RecortePorPontos;
if (
!_estadoEdicao.EmEdicao ||
!_mapasEmEdicao.Contains(
mapaControl
) ||
!ferramentaPoligono
)
{
return;
}
if (
recorte == null ||
recorte.QuantidadePontos < 3
)
{
return;
}
try
{
/*
* Fronteira UI → domínio.
*
* DTO:
* Latitude / Longitude
*
* NTS:
* X = longitude
* Y = latitude
*/
Coordinate[] pontos =
recorte
.Pontos
.Select(
p =>
new Coordinate(
p.Longitude,
p.Latitude
)
)
.ToArray();
/*
* V1:
* o próprio polígono define o escopo.
*
* Depois adicionaremos a opção
* "Somente ruas selecionadas".
*/
if (_estadoRecorte.SomenteSelecionadas && !_estadoEdicao.PossuiSelecao)
{
Log(
"[MAPA][EDICAO][RECORTE][IGNORADO] " +
"Escopo=SomenteSelecionadas | " +
"Nenhuma rua selecionada."
);
SincronizarCockpitEdicao();
return;
}
MapaResultadoRecorte resultado =
_edicaoService
.RecortarPorPoligono(
_estadoEdicao,
pontos,
somenteSelecionadas: _estadoRecorte.SomenteSelecionadas
);
/*
* Mesmo sem alteração podemos ter
* ruas ambíguas importantes para log.
*/
if (!resultado.HouveAlteracao)
{
string tipoRecorte =
_ferramentaEdicaoAtual ==
MapaFerramentaEdicao.RecorteLivre
? "RECORTE-LIVRE"
: "RECORTE-PONTOS";
Log(
$"[MAPA][EDICAO][{tipoRecorte}] " +
$"Escopo={_estadoRecorte.Escopo} | " +
resultado
);
return;
}
/*
* É alteração estrutural/geometria.
*
* Não basta atualizar estilo.
*/
RenderizarDocumentoEdicaoAtual();
SincronizarCockpitEdicao();
EstadoEdicaoAlterado?
.Invoke();
Log(
"[MAPA][EDICAO][RECORTE-LIVRE] " +
resultado
);
}
catch (Exception ex)
{
/*
* O MapaEdicaoService já restaura
* o snapshot transacional em caso
* de erro.
*/
Log(
"[MAPA][EDICAO][RECORTE-LIVRE][ERRO] " +
ex.Message
);
}
}
private void OnMapaEditorDesfazerSolicitado(MapViewControl mapaControl)
{
if (
!_estadoEdicao.EmEdicao ||
!_mapasEmEdicao.Contains(
mapaControl
)
)
{
return;
}
DesfazerEdicao();
}
private void OnMapaEditorRefazerSolicitado(MapViewControl mapaControl)
{
if (
!_estadoEdicao.EmEdicao ||
!_mapasEmEdicao.Contains(
mapaControl
)
)
{
return;
}
RefazerEdicao();
}
private void OnMapaEditorExcluirSelecionadasSolicitado(MapViewControl mapaControl)
{
if (
!_estadoEdicao.EmEdicao ||
!_mapasEmEdicao.Contains(
mapaControl
) ||
!_estadoEdicao.PossuiSelecao
)
{
return;
}
RemoverRuasSelecionadasEdicao();
}
private void OnMapaEditorAplicarEdicaoSolicitado(MapViewControl mapaControl)
{
if (!_estadoEdicao.EmEdicao || !_mapasEmEdicao.Contains(mapaControl))
{
return;
}
AplicarEdicao();
}
private void OnMapaEditorCancelarEdicaoSolicitado(MapViewControl mapaControl)
{
if (!_estadoEdicao.EmEdicao || !_mapasEmEdicao.Contains(mapaControl))
{
return;
}
CancelarEdicao(mapaControl);
}
private void OnMapaEditorEscopoRecorteAlterado(MapViewControl mapaControl, MapaEscopoRecorte escopo)
{
if (!_estadoEdicao.EmEdicao || !_mapasEmEdicao.Contains(mapaControl))
return;
_estadoRecorte.Escopo = escopo;
SincronizarCockpitEdicao();
Log(
"[MAPA][EDICAO][RECORTE][ESCOPO] " +
$"Atual={escopo}"
);
}
private void OnMapaEditorBordaGnssAcaoSolicitada(MapViewControl mapaControl, MapaAcaoBordaGnss acao)
{
if (
!_estadoEdicao.EmEdicao ||
!_mapasEmEdicao.Contains(mapaControl) ||
_ferramentaEdicaoAtual != MapaFerramentaEdicao.RecorteBordaGnss
)
{
return;
}
switch (acao)
{
case MapaAcaoBordaGnss
.RegistrarPonto:
RegistrarPontoBordaGnssManual();
break;
case MapaAcaoBordaGnss
.RemoverUltimo:
RemoverUltimoPontoBordaGnss();
break;
case MapaAcaoBordaGnss
.Finalizar:
FinalizarCapturaBordaGnss();
break;
case MapaAcaoBordaGnss
.Continuar:
ContinuarCapturaBordaGnss();
break;
case MapaAcaoBordaGnss
.Descartar:
DescartarCapturaBordaGnss();
break;
case MapaAcaoBordaGnss.Aplicar:
AplicarBordaGnss();
break;
case MapaAcaoBordaGnss.DefinirModoManual:
DefinirModoCapturaBordaGnss(MapaModoCapturaGnss.Manual);
break;
case MapaAcaoBordaGnss.DefinirModoAutomatico:
DefinirModoCapturaBordaGnss(MapaModoCapturaGnss.Automatico);
break;
case MapaAcaoBordaGnss.IniciarGravacaoAutomatica:
IniciarGravacaoBordaGnssAutomatica();
break;
}
}
private void OnMapaEditorRestaurarFonteSolicitado(MapViewControl mapaControl)
{
if (!_estadoEdicao.EmEdicao || !_mapasEmEdicao.Contains(mapaControl))
{
return;
}
RestaurarMapaFonteEdicao();
}
}
}