using Mapsui; using Mapsui.Layers; using Mapsui.Nts; using Mapsui.Projections; using Mapsui.Styles; using NetTopologySuite.Geometries; using OperationControl.Mapas.Models; using Color = Mapsui.Styles.Color; using Pen = Mapsui.Styles.Pen; namespace OperationControl.Mapas.Rendering { public sealed class MapaRastroRenderService { public const string NomeCamada = "MapaRastroNovo"; /* * Mesma ideia da paleta do legado: * cada RoverId recebe uma cor estável. * * A cor é responsabilidade de render, * portanto não precisa entrar no domínio. */ private static readonly Color[] Paleta = { new Color(0, 191, 255, 255), // DeepSkyBlue new Color(50, 205, 50, 255), // LimeGreen new Color(255, 215, 0, 255), // Gold new Color(255, 165, 0, 255), // Orange new Color(147, 112, 219, 255), // MediumPurple new Color(0, 255, 255, 255), // Cyan new Color(255, 0, 255, 255), // Magenta new Color(0, 255, 127, 255), // SpringGreen new Color(255, 127, 80, 255), // Coral new Color(255, 255, 0, 255) // Yellow }; public MemoryLayer CriarCamada( MapaEstadoMovimento estado) { if (estado == null) { throw new ArgumentNullException( nameof(estado) ); } return new MemoryLayer { Name = NomeCamada, Features = CriarFeatures( estado ), Style = null }; } public void AtualizarCamada( MemoryLayer camada, MapaEstadoMovimento estado) { if (camada == null) { throw new ArgumentNullException( nameof(camada) ); } if (estado == null) { throw new ArgumentNullException( nameof(estado) ); } camada.Features = CriarFeatures( estado ); } private static List CriarFeatures( MapaEstadoMovimento estado) { var features = new List(); foreach ( var movimento in estado.Rovers) { Color corRover = ObterCorRover( movimento.RoverId ); foreach ( var trecho in movimento.Trechos) { if ( trecho == null || trecho.Pontos.Count < 2 ) { continue; } var coordenadas = new List(); foreach ( var ponto in trecho.Pontos) { var mercator = SphericalMercator .FromLonLat( ponto.Longitude, ponto.Latitude ); coordenadas.Add( new Coordinate( mercator.x, mercator.y ) ); } if ( coordenadas.Count < 2 ) { continue; } var feature = new GeometryFeature { Geometry = new LineString( coordenadas .ToArray() ) }; feature["RoverId"] = movimento.RoverId; feature["Tipo"] = "Rastro"; feature["Pulverizando"] = trecho.Pulverizando ? "1" : "0"; feature.Styles.Add( CriarEstilo( corRover, trecho.Pulverizando ) ); features.Add( feature ); } } return features; } private static VectorStyle CriarEstilo( Color cor, bool pulverizando) { /* * Mantemos a semântica visual do legado: * * normal: * mais transparente e fino * * pulverizando: * opaco e mais grosso */ Color corLinha = pulverizando ? new Color( cor.R, cor.G, cor.B, 255 ) : new Color( cor.R, cor.G, cor.B, 180 ); return new VectorStyle { Line = new Pen( corLinha, pulverizando ? 4 : 2 ) }; } private static Color ObterCorRover( string roverId) { if ( string.IsNullOrWhiteSpace( roverId ) ) { return Paleta[0]; } /* * Hash determinístico. * * Não usamos string.GetHashCode() * porque ele não precisa ser estável * entre execuções do processo. */ uint hash = 2166136261; foreach ( char caractere in roverId .Trim() .ToUpperInvariant()) { unchecked { hash ^= caractere; hash *= 16777619; } } int indice = (int)( hash % (uint)Paleta.Length ); return Paleta[ indice ]; } } }