using Mapsui; using Mapsui.Layers; using Mapsui.Nts; using Mapsui.Styles; using NetTopologySuite.Geometries; using OperationControl.Mapas.Models; using Brush = Mapsui.Styles.Brush; using Font = Mapsui.Styles.Font; using Pen = Mapsui.Styles.Pen; namespace OperationControl.Mapas.Rendering { /// /// Converte o estado dinâmico de Base/Rovers /// em representação visual Mapsui. /// /// Não armazena estado operacional. /// public sealed class MapaEntidadeDinamicaRenderService { public const string NomeCamada = "MapaEntidadesDinamicasNovo"; public MemoryLayer CriarCamada( MapaEstadoDinamico estado, double resolution) { if (estado == null) { throw new ArgumentNullException( nameof(estado) ); } return new MemoryLayer { Name = NomeCamada, Features = CriarFeatures( estado, resolution ) }; } public void AtualizarCamada( MemoryLayer camada, MapaEstadoDinamico estado, double resolution) { if (camada == null) { throw new ArgumentNullException( nameof(camada) ); } if (estado == null) { throw new ArgumentNullException( nameof(estado) ); } camada.Features = CriarFeatures( estado, resolution ); } private static IEnumerable CriarFeatures( MapaEstadoDinamico estado, double resolution) { var features = new List(); if ( !double.IsFinite(resolution) || resolution <= 0 ) { resolution = 1.0; } foreach ( var entidade in estado.Entidades) { if (!entidade.PossuiPosicao) continue; double latitude = entidade.Latitude!.Value; double longitude = entidade.Longitude!.Value; var mercator = Mapsui.Projections .SphericalMercator .FromLonLat( longitude, latitude ); var centro = new MPoint( mercator.x, mercator.y ); if ( entidade.Tipo == MapaTipoEntidadeDinamica.Base ) { CriarBase( entidade, centro, resolution, features ); } else { CriarRover( entidade, centro, resolution, features ); } /* * Label e ponto central para futura * identificação/hit-test. */ CriarCentroELabel( entidade, centro, features ); } return features; } private static void CriarRover( MapaEntidadeDinamica entidade, MPoint centro, double resolution, List features) { /* * Aproximadamente 24 px no zoom atual. */ double comprimento = 24.0 * resolution; double largura = comprimento * 0.75; double frente = comprimento * 0.55; double traseira = comprimento * 0.45; double meiaLargura = largura * 0.5; /* * Convenção: * * 0° = Norte * 90° = Leste * 180° = Sul * 270° = Oeste */ double heading = entidade.Heading ?? 0.0; double rad = heading * Math.PI / 180.0; double ux = Math.Sin(rad); double uy = Math.Cos(rad); double px = Math.Cos(rad); double py = -Math.Sin(rad); var front = new Coordinate( centro.X + ux * frente, centro.Y + uy * frente ); var left = new Coordinate( centro.X - ux * traseira + px * meiaLargura, centro.Y - uy * traseira + py * meiaLargura ); var right = new Coordinate( centro.X - ux * traseira - px * meiaLargura, centro.Y - uy * traseira - py * meiaLargura ); var ring = new LinearRing( new[] { front, left, right, front } ); var feature = new GeometryFeature { Geometry = new Polygon( ring ) }; feature["EntidadeId"] = entidade.Id; feature["Tipo"] = "Rover"; var cor = new Mapsui.Styles.Color( 45, 140, 220, 255 ); feature.Styles.Add( new VectorStyle { Fill = new Brush( cor ), Outline = new Pen( Mapsui.Styles.Color.White, entidade.EmFoco ? 3 : 2 ) } ); features.Add( feature ); /* * Halo de foco. */ if (entidade.EmFoco) { var foco = new PointFeature( centro ); foco["EntidadeId"] = entidade.Id; foco.Styles.Add( new SymbolStyle { SymbolType = SymbolType.Ellipse, SymbolScale = 1.35, Fill = new Brush( new Mapsui.Styles.Color( cor.R, cor.G, cor.B, 40 ) ), Outline = new Pen( new Mapsui.Styles.Color( cor.R, cor.G, cor.B, 180 ), 2 ) } ); features.Add( foco ); } } private static void CriarBase( MapaEntidadeDinamica entidade, MPoint centro, double resolution, List features) { double raio = 22.0 * resolution; var coords = new List(); /* * Hexágono. */ for ( int i = 0; i < 6; i++) { double ang = Math.PI / 6.0 + i * Math.PI / 3.0; coords.Add( new Coordinate( centro.X + Math.Cos(ang) * raio, centro.Y + Math.Sin(ang) * raio ) ); } coords.Add( coords[0] ); var feature = new GeometryFeature { Geometry = new Polygon( new LinearRing( coords.ToArray() ) ) }; feature["EntidadeId"] = entidade.Id; feature["Tipo"] = "Base"; var cor = new Mapsui.Styles.Color( 220, 45, 45, 255 ); feature.Styles.Add( new VectorStyle { Fill = new Brush( cor ), Outline = new Mapsui.Styles.Pen( Mapsui.Styles.Color.White, entidade.EmFoco ? 3 : 2 ) } ); features.Add( feature ); /* * Centro branco da base. */ var centroFeature = new PointFeature( centro ); centroFeature["EntidadeId"] = entidade.Id; centroFeature.Styles.Add( new SymbolStyle { SymbolType = SymbolType.Ellipse, SymbolScale = 0.45, Fill = new Brush( Mapsui.Styles.Color.White ), Outline = null } ); features.Add( centroFeature ); } private static void CriarCentroELabel( MapaEntidadeDinamica entidade, MPoint centro, List features) { var ponto = new PointFeature( centro ); /* * Isso será muito útil no 7C: * * feature visual -> EntidadeId */ ponto["EntidadeId"] = entidade.Id; ponto["Tipo"] = entidade.Tipo.ToString(); /* * Pequeno ponto central. */ ponto.Styles.Add( new SymbolStyle { SymbolScale = 0.10, Fill = new Brush( Mapsui.Styles.Color.White ), Outline = null } ); ponto.Styles.Add( new LabelStyle { Text = entidade.Nome, ForeColor = Mapsui.Styles.Color.White, BackColor = new Brush( new Mapsui.Styles.Color( 0, 0, 0, 150 ) ), Offset = new Offset( 0, -34 ), Font = new Font { FontFamily = "Segoe UI", Size = 15 } } ); features.Add( ponto ); } } }