agrobot_base/AgroBase/OperationControl/Mapas/Rendering/MapaEdicaoRenderService.cs

365 lines
8.7 KiB
C#

using Mapsui;
using Mapsui.Layers;
using Mapsui.Nts;
using Mapsui.Projections;
using Mapsui.Providers;
using Mapsui.Styles;
using NetTopologySuite.Geometries;
using OperationControl.Mapas.Editing;
using Color = Mapsui.Styles.Color;
using Pen = Mapsui.Styles.Pen;
namespace OperationControl.Mapas.Rendering
{
public sealed class MapaEdicaoRenderService
{
public const string NomeCamada =
"MapaEdicaoNovo";
private static readonly VectorStyle
EstiloNormal =
new()
{
Line =
new Pen(
new Color(
46,
204,
113,
210
),
2
)
};
/*
* Cor própria da edição.
*
* Não confundir com o amarelo usado
* na seleção operacional da missão.
*/
private static readonly VectorStyle
EstiloSelecionado =
new()
{
Line =
new Pen(
new Color(
255,
64,
190,
255
),
5
)
};
public MapaRenderResult CriarCamada(
MapaEstadoEdicao estado)
{
if (estado == null)
{
throw new ArgumentNullException(
nameof(estado)
);
}
if (
!estado.EmEdicao ||
estado.DocumentoTrabalho == null
)
{
throw new InvalidOperationException(
"Não existe uma sessão de edição ativa."
);
}
var featuresPorRuaId =
new Dictionary<
string,
GeometryFeature>(
StringComparer.OrdinalIgnoreCase
);
var features =
new List<IFeature>();
foreach (
var rua
in estado.DocumentoTrabalho.Ruas)
{
if (
rua == null ||
rua.Geometria == null ||
rua.Geometria.IsEmpty ||
rua.Geometria.NumPoints < 2
)
{
continue;
}
/*
* Documento canônico:
*
* EPSG:4326
* X = longitude
* Y = latitude
*
* Mapsui:
*
* desenhamos diretamente em
* WebMercator EPSG:3857.
*/
var coordenadas =
rua.Geometria
.Coordinates
.Select(
coordenada =>
{
var mercator =
SphericalMercator
.FromLonLat(
coordenada.X,
coordenada.Y
);
return new Coordinate(
mercator.x,
mercator.y
);
}
)
.ToArray();
if (coordenadas.Length < 2)
continue;
var feature =
new GeometryFeature
{
Geometry =
new LineString(
coordenadas
)
};
/*
* Mantemos os mesmos atributos
* esperados pelo hit-test atual.
*/
feature["RuaId"] =
rua.Id;
feature["Id"] =
rua.Id;
feature["Tipo"] =
"RuaEdicao";
bool selecionada =
EstaSelecionada(
estado,
rua.Id
);
feature
.Styles
.Add(
selecionada
? EstiloSelecionado
: EstiloNormal
);
features.Add(
feature
);
featuresPorRuaId[
rua.Id
] =
feature;
}
/*
* MapaRenderResult trabalha com Layer,
* portanto seguimos exatamente esse
* contrato.
*/
var provider =
new MemoryProvider(
features
);
var camada =
new Layer
{
Name =
NomeCamada,
DataSource =
provider,
/*
* Cada feature possui seu
* próprio estilo.
*/
Style =
null
};
/*
* IMPORTANTE:
*
* MapaRenderResult NÃO possui
* construtor vazio.
*
* Layer e dicionário entram pelo
* construtor obrigatório.
*/
return new MapaRenderResult(
camada,
featuresPorRuaId
);
}
public void AtualizarEstiloRua(
MapaRenderResult render,
MapaEstadoEdicao estado,
string ruaId)
{
if (
render == null ||
estado == null ||
string.IsNullOrWhiteSpace(
ruaId
)
)
{
return;
}
/*
* Aproveitamos a API que já existe
* no próprio MapaRenderResult.
*/
var feature =
render.ObterFeature(
ruaId
);
if (feature == null)
return;
bool selecionada =
EstaSelecionada(
estado,
ruaId
);
feature
.Styles
.Clear();
feature
.Styles
.Add(
selecionada
? EstiloSelecionado
: EstiloNormal
);
}
public void AplicarSelecao(
MapaRenderResult render,
MapaEstadoEdicao estado)
{
if (
render == null ||
estado == null
)
{
return;
}
foreach (
var item
in render.FeaturesPorRuaId)
{
bool selecionada =
EstaSelecionada(
estado,
item.Key
);
item.Value
.Styles
.Clear();
item.Value
.Styles
.Add(
selecionada
? EstiloSelecionado
: EstiloNormal
);
}
}
private static bool EstaSelecionada(
MapaEstadoEdicao estado,
string ruaId)
{
if (
string.IsNullOrWhiteSpace(
ruaId
)
)
{
return false;
}
return estado
.RuasSelecionadas
.Any(
id =>
string.Equals(
id,
ruaId,
StringComparison
.OrdinalIgnoreCase
)
);
}
}
}