Example #1
0
        private static RectangleF RoundToPixel(Geometries.Point min, Geometries.Point max)
        {
            // To get seamless aligning you need to round the
            // corner coordinates to pixel. The new width and
            // height will be a result of that.
            var x      = Math.Round(min.X);
            var y      = Math.Round(min.Y);
            var width  = Math.Round(max.X) - Math.Round(min.X);
            var height = Math.Round(max.Y) - Math.Round(min.Y);

            return(new RectangleF((float)x, (float)y, (float)width, (float)height));
        }
Example #2
0
        public static RectangleF ConvertPointBoundingBox(SymbolStyle symbolStyle, BoundingBox boundingBox, IViewport viewport)
        {
            var screenMin = viewport.WorldToScreen(boundingBox.Min);
            var screenMax = viewport.WorldToScreen(boundingBox.Max);

            //boundingBox.Offset = symbolStyle.SymbolOffset;
            //var newMin = boundingBox.Min;
            //var newMax = boundingBox.Max;

            if (symbolStyle.SymbolOffset != null)
            {
                screenMin = new Geometries.Point(
                    screenMin.X - symbolStyle.SymbolOffset.X,
                    screenMin.Y - symbolStyle.SymbolOffset.Y);
                screenMax = new Geometries.Point(
                    screenMax.X - symbolStyle.SymbolOffset.X,
                    screenMax.Y - symbolStyle.SymbolOffset.Y);

                var w = viewport.ScreenToWorld(screenMin);

                boundingBox.Offset(new Geometries.Point(w.X - boundingBox.MinX, w.Y - boundingBox.MinY));

                screenMin = viewport.WorldToScreen(boundingBox.Min);
                screenMax = viewport.WorldToScreen(boundingBox.Max);
            }


            var min = new Geometries.Point(screenMin.X - (32 / 2), screenMax.Y - (32 / 2)); //!!!
            var max = new Geometries.Point((min.X + 32), (min.Y + 32));                     //!!!

            var frame = RoundToPixel(min, max);

            //if(symbolStyle.SymbolOffset != null)
            //	frame.Offset ((float)symbolStyle.SymbolOffset.X, (float)symbolStyle.SymbolOffset.Y);

            return(frame);
        }
        public static Canvas Render(IViewport viewport, LabelLayer layer)
        {
            // todo: Move stack functionality to Mapsui core.
            // step 1) Split RenderStackedLabelLayer into a method
            // GetFeaturesInViewStacked en a RenderStackedLabel 
            // which can later be replace by normal label rendering.
            // The method GetFeaturesInViewStacked 
            // returns a style with an offset determined by the stackoffset
            // and a position determined by CenterX en Cluster.Box.Bottom.
            // step 2) Move GetFeaturesInViewStacked to a GetFeaturesInView
            // method of a new StackedLabelLayed.

            var canvas = new Canvas { Opacity = layer.Opacity };

            // todo: take into account the priority 
            var features = layer.GetFeaturesInView(viewport.Extent, viewport.Resolution).ToArray();
            var margin = viewport.Resolution * 50;

            const int symbolSize = 32; // todo: determine margin by symbol size
            const int boxMargin = symbolSize / 2;

            var clusters = new List<Cluster>();
            //todo: repeat until there are no more merges
            ClusterFeatures(clusters, features, margin, layer.Style, viewport.Resolution);
            const int textHeight = 18;
            foreach (var cluster in clusters)
            {
                var stackOffsetY = double.NaN;

                var orderedFeatures = cluster.Features.OrderBy(f => f.Geometry.GetBoundingBox().GetCentroid().Y);

                if (cluster.Features.Count > 1) canvas.Children.Add(RenderBox(cluster.Box, viewport));

                foreach (var feature in orderedFeatures)
                {
                    if (double.IsNaN(stackOffsetY)) // first time
                        stackOffsetY = textHeight * 0.5 + boxMargin;
                    else
                        stackOffsetY += textHeight; //todo: get size from text (or just pass stack nr)

                    LabelStyle style;
                    if (layer.Style is IThemeStyle)
                    {
                        style = (LabelStyle)((IThemeStyle)layer.Style).GetStyle(feature);
                    }
                    else
                    {
                        style = (LabelStyle)layer.Style;
                    }

                    var labelStyle = new LabelStyle(style)
                    {
                        Text = layer.GetLabelText(feature) //we only use the layer for the text, this should be returned by style
                    };
                    labelStyle.Offset.Y += stackOffsetY;

                    // since the box can be rotated, find the minimal Y value of all 4 corners
                    var rotatedBox = cluster.Box.Rotate(-viewport.Rotation);
                    var minY = rotatedBox.Vertices.Select(v => v.Y).Min();
                    var position = new Geometries.Point(cluster.Box.GetCentroid().X, minY);

                    var labelText = labelStyle.GetLabelText(feature);
                    canvas.Children.Add(SingleLabelRenderer.RenderLabel(position, labelStyle, viewport, labelText));
                }
            }
            return canvas;
        }
        public static Canvas Render(IViewport viewport, LabelLayer layer)
        {
            // todo: Move stack functionality to Mapsui core.
            // step 1) Split RenderStackedLabelLayer into a method
            // GetFeaturesInViewStacked en a RenderStackedLabel
            // which can later be replace by normal label rendering.
            // The method GetFeaturesInViewStacked
            // returns a style with an offset determined by the stackoffset
            // and a position determined by CenterX en Cluster.Box.Bottom.
            // step 2) Move GetFeaturesInViewStacked to a GetFeaturesInView
            // method of a new StackedLabelLayed.

            var canvas = new Canvas {
                Opacity = layer.Opacity
            };

            // todo: take into account the priority
            var features = layer.GetFeaturesInView(viewport.Extent, viewport.Resolution).ToArray();
            var margin   = viewport.Resolution * 50;

            const int symbolSize = 32; // todo: determine margin by symbol size
            const int boxMargin  = symbolSize / 2;

            var clusters = new List <Cluster>();

            //todo: repeat until there are no more merges
            ClusterFeatures(clusters, features, margin, layer.Style, viewport.Resolution);
            const int textHeight = 18;

            foreach (var cluster in clusters)
            {
                var stackOffsetY = double.NaN;

                var orderedFeatures = cluster.Features.OrderBy(f => f.Geometry.GetBoundingBox().GetCentroid().Y);

                if (cluster.Features.Count > 1)
                {
                    canvas.Children.Add(RenderBox(cluster.Box, viewport));
                }

                foreach (var feature in orderedFeatures)
                {
                    if (double.IsNaN(stackOffsetY)) // first time
                    {
                        stackOffsetY = textHeight * 0.5 + boxMargin;
                    }
                    else
                    {
                        stackOffsetY += textHeight; //todo: get size from text (or just pass stack nr)
                    }
                    LabelStyle style;
                    if (layer.Style is IThemeStyle)
                    {
                        style = (LabelStyle)((IThemeStyle)layer.Style).GetStyle(feature);
                    }
                    else
                    {
                        style = (LabelStyle)layer.Style;
                    }

                    var labelStyle = new LabelStyle(style)
                    {
                        Text = layer.GetLabelText(feature) //we only use the layer for the text, this should be returned by style
                    };
                    labelStyle.Offset.Y += stackOffsetY;

                    // since the box can be rotated, find the minimal Y value of all 4 corners
                    var rotatedBox = cluster.Box.Rotate(-viewport.Rotation);
                    var minY       = rotatedBox.Vertices.Select(v => v.Y).Min();
                    var position   = new Geometries.Point(cluster.Box.GetCentroid().X, minY);

                    var labelText = labelStyle.GetLabelText(feature);
                    canvas.Children.Add(SingleLabelRenderer.RenderLabel(position, labelStyle, viewport, labelText));
                }
            }
            return(canvas);
        }