Пример #1
0
        /// <summary>
        ///
        /// </summary>
        /// <param name="layers">The layers to query for MapInfo</param>
        /// <param name="viewport">The current Viewport</param>
        /// <param name="screenPosition">The screenposition to query</param>
        /// <param name="symbolCache">The </param>
        /// <param name="margin">Margin of error in pixels. If the distance between screen position and geometry
        /// is smaller than the margin it is seen as a hit.</param>
        /// <returns></returns>
        public static MapInfo GetMapInfo(IEnumerable <ILayer> layers, IReadOnlyViewport viewport, Point screenPosition,
                                         ISymbolCache symbolCache, int margin = 0)
        {
            var worldPosition = viewport.ScreenToWorld(screenPosition);

            return(GetMapInfo(layers, worldPosition, screenPosition, viewport.Resolution, symbolCache, margin));
        }
Пример #2
0
        public MapInfo GetMapInfo(double x, double y, IReadOnlyViewport viewport, IEnumerable <ILayer> layers, int margin = 0)
        {
            // todo: use margin to increase the pixel area
            // todo: We will need to select on style instead of layer

            layers = layers
                     .Select(l => (l is RasterizingLayer rl) ? rl.ChildLayer : l)
                     .Where(l => l.IsMapInfoLayer);

            var list   = new List <MapInfoRecord>();
            var result = new MapInfo()
            {
                ScreenPosition = new Point(x, y),
                WorldPosition  = viewport.ScreenToWorld(x, y),
                Resolution     = viewport.Resolution
            };

            try
            {
                var width  = (int)viewport.Width;
                var height = (int)viewport.Height;

                var imageInfo = new SKImageInfo(width, height, SKImageInfo.PlatformColorType, SKAlphaType.Unpremul);

                var intX = (int)x;
                var intY = (int)y;

                using (var surface = SKSurface.Create(imageInfo))
                {
                    if (surface == null)
                    {
                        return(null);
                    }

                    surface.Canvas.ClipRect(new SKRect((float)(x - 1), (float)(y - 1), (float)(x + 1), (float)(y + 1)));
                    surface.Canvas.Clear(SKColors.Transparent);

                    var pixmap = surface.PeekPixels();
                    var color  = pixmap.GetPixelColor(intX, intY);

                    VisibleFeatureIterator.IterateLayers(viewport, layers, (v, layer, style, feature, opacity) => {
                        surface.Canvas.Save();
                        // 1) Clear the entire bitmap
                        surface.Canvas.Clear(SKColors.Transparent);
                        // 2) Render the feature to the clean canvas
                        RenderFeature(surface.Canvas, v, layer, style, feature, opacity);
                        // 3) Check if the pixel has changed.
                        if (color != pixmap.GetPixelColor(intX, intY))
                        {
                            // 4) Add feature and style to result
                            list.Add(new MapInfoRecord(feature, style, layer));
                        }
                        surface.Canvas.Restore();
                    });
                }

                if (list.Count == 0)
                {
                    return(result);
                }

                list.Reverse();
                var itemDrawnOnTop = list.First();

                result.Feature        = itemDrawnOnTop.Feature;
                result.Style          = itemDrawnOnTop.Style;
                result.Layer          = itemDrawnOnTop.Layer;
                result.MapInfoRecords = list;
            }
            catch (Exception exception)
            {
                Logger.Log(LogLevel.Error, "Unexpected error in skia renderer", exception);
            }

            return(result);
        }
Пример #3
0
        public void Draw(SKCanvas canvas, IReadOnlyViewport viewport, IWidget widget, float layerOpacity)
        {
            canvas.RotateDegrees((float)viewport.Rotation, 0.0f, 0.0f);


            var TL = viewport.ScreenToWorld(canvas.LocalClipBounds.Left, canvas.LocalClipBounds.Top);
            var BR = viewport.ScreenToWorld(canvas.LocalClipBounds.Right, canvas.LocalClipBounds.Bottom);

            var width  = viewport.Extent.Width;
            var height = viewport.Extent.Height;

            var usedLineOffset = lineOffset;

            IEnumerable <SKPaint> usedPaints = paints;

            if (viewport.Resolution > 0.5)
            {
                usedLineOffset *= 10;
                usedPaints      = usedPaints.Skip(1).ToArray();
            }

            if (viewport.Resolution > 3)
            {
                usedLineOffset *= 10;
                usedPaints      = usedPaints.Skip(1).ToArray();
            }


            int lineCount100M = (int)(100 / usedLineOffset);
            //How many lines are 1000m
            int lineCount1000M = (int)(1000 / usedLineOffset);

            if (lineCount100M == 0)
            {
                lineCount100M = 9000;                     //will never be reached, if we only render 1k's
            }
            double screenWidthPerLine  = canvas.LocalClipBounds.Width / (width / usedLineOffset);
            double screenHeightPerLine = canvas.LocalClipBounds.Height / (height / usedLineOffset);

            //World coordinates of first lineOffset line
            var first100mW = (TL.X + (usedLineOffset - TL.X % usedLineOffset));
            var first100mH = (TL.Y + (usedLineOffset - TL.Y % usedLineOffset));

            //Screen offset of first lineOffset line
            double offsetCW = ((first100mW - TL.X) / usedLineOffset) * screenWidthPerLine;
            double offsetCH = screenHeightPerLine + ((TL.Y - first100mH) / usedLineOffset) * screenHeightPerLine;

            //offset of next 1k
            int KOffsetW = (int)((first100mW % 1000) / usedLineOffset);

            if (KOffsetW < 0)
            {
                KOffsetW = 10 + KOffsetW;
            }
            int KOffsetH = (int)((first100mH % 1000) / usedLineOffset) - 1;

            if (lineCount1000M > 1)
            {
                KOffsetH = lineCount1000M - KOffsetH;
            }



            for (double curX = offsetCW; curX < canvas.LocalClipBounds.Right; curX += screenWidthPerLine)
            {
                SKPaint paint;
                if (KOffsetW >= 100 && KOffsetW % 100 == 0)
                {
                    paint = usedPaints.ElementAt(2);
                }
                else if (KOffsetW >= 10 && KOffsetW % 10 == 0)
                {
                    paint = usedPaints.ElementAt(1);
                }
                else
                {
                    paint = usedPaints.ElementAt(0);
                }

                if (KOffsetW == lineCount1000M)
                {
                    KOffsetW = 0;
                }

                canvas.DrawLine((float)curX, 0, (float)curX, canvas.LocalClipBounds.Height, paint);

                KOffsetW++;
            }

            for (double curH = offsetCH; curH < canvas.LocalClipBounds.Bottom; curH += screenHeightPerLine)
            {
                SKPaint paint;
                if (KOffsetH >= 100 && KOffsetH % 100 == 0)
                {
                    paint = usedPaints.ElementAt(2);
                }
                else if (KOffsetH >= 10 && KOffsetH % 10 == 0)
                {
                    paint = usedPaints.ElementAt(1);
                }
                else
                {
                    paint = usedPaints.ElementAt(0);
                }

                if (KOffsetH == lineCount1000M)
                {
                    KOffsetH = 0;
                }

                canvas.DrawLine(0, (float)curH, canvas.LocalClipBounds.Width, (float)curH, paint);

                KOffsetH++;
            }
        }
Пример #4
0
        public MapInfo?GetMapInfo(double x, double y, IReadOnlyViewport viewport, IEnumerable <ILayer> layers, int margin = 0)
        {
            // todo: use margin to increase the pixel area
            // todo: We will need to select on style instead of layer

            layers = layers
                     .Select(l => (l is ISourceLayer sl) ? sl.SourceLayer : l)
                     .Where(l => l.IsMapInfoLayer);

            var list   = new List <MapInfoRecord>();
            var result = new MapInfo
            {
                ScreenPosition = new MPoint(x, y),
                WorldPosition  = viewport.ScreenToWorld(x, y),
                Resolution     = viewport.Resolution
            };

            if (!viewport.Extent?.Contains(viewport.ScreenToWorld(result.ScreenPosition)) ?? false)
            {
                return(result);
            }

            try
            {
                var width  = (int)viewport.Width;
                var height = (int)viewport.Height;

                var imageInfo = new SKImageInfo(width, height, SKImageInfo.PlatformColorType, SKAlphaType.Unpremul);

                var intX = (int)x;
                var intY = (int)y;

                if (intX >= width || intY >= height)
                {
                    return(result);
                }

                using (var surface = SKSurface.Create(imageInfo))
                {
                    if (surface == null)
                    {
                        return(null);
                    }

                    surface.Canvas.ClipRect(new SKRect((float)(x - 1), (float)(y - 1), (float)(x + 1), (float)(y + 1)));
                    surface.Canvas.Clear(SKColors.Transparent);

                    using var pixmap = surface.PeekPixels();
                    var color = pixmap.GetPixelColor(intX, intY);


                    VisibleFeatureIterator.IterateLayers(viewport, layers, 0, (v, layer, style, feature, opacity, iteration) => {
                        // ReSharper disable AccessToDisposedClosure // There is no delayed fetch. After IterateLayers returns all is done. I do not see a problem.
                        surface.Canvas.Save();
                        // 1) Clear the entire bitmap
                        surface.Canvas.Clear(SKColors.Transparent);
                        // 2) Render the feature to the clean canvas
                        RenderFeature(surface.Canvas, v, layer, style, feature, opacity, 0);
                        // 3) Check if the pixel has changed.
                        if (color != pixmap.GetPixelColor(intX, intY))
                        {
                            // 4) Add feature and style to result
                            list.Add(new MapInfoRecord(feature, style, layer));
                        }
                        surface.Canvas.Restore();
                        // ReSharper restore AccessToDisposedClosure
                    });
                }

                if (list.Count == 0)
                {
                    return(result);
                }

                list.Reverse();
                var itemDrawnOnTop = list.First();

                result.Feature        = itemDrawnOnTop.Feature;
                result.Style          = itemDrawnOnTop.Style;
                result.Layer          = itemDrawnOnTop.Layer;
                result.MapInfoRecords = list;
            }
            catch (Exception exception)
            {
                Logger.Log(LogLevel.Error, "Unexpected error in skia renderer", exception);
            }

            return(result);
        }
Пример #5
0
        public void Draw(SKCanvas canvas, IReadOnlyViewport viewport, IWidget widget, float layerOpacity)
        {
            canvas.RotateDegrees((float)viewport.Rotation, 0.0f, 0.0f);


            var TL = viewport.ScreenToWorld(canvas.LocalClipBounds.Left, canvas.LocalClipBounds.Top);
            var BR = viewport.ScreenToWorld(canvas.LocalClipBounds.Right, canvas.LocalClipBounds.Bottom);

            var width  = viewport.Extent.Width;
            var height = viewport.Extent.Height;

            var  usedLineOffset    = lineOffset;
            uint usedLineOffsetInt = (uint)usedLineOffset;

            IEnumerable <SKPaint> usedPaints = paints;

            if (viewport.Resolution > 0.25)
            {
                usedLineOffset    *= 10; // hide 10m layer
                usedLineOffsetInt *= 10; // hide 10m layer
                usedPaints         = paintsL2;
            }

            if (viewport.Resolution > 3)
            {
                usedLineOffset    *= 10; // hide 100m layer
                usedLineOffsetInt *= 10; // hide 100m layer
                usedPaints         = paintsL3;
            }

            int lineCount100M = (int)(100 / usedLineOffset);
            //How many lines are 1000m
            int lineCount1000M = (int)(1000 / usedLineOffset);

            if (lineCount100M == 0)
            {
                lineCount100M = 9000;                     //will never be reached, if we only render 1k's
            }
            double screenWidthPerLine  = canvas.LocalClipBounds.Width / (width / usedLineOffset);
            double screenHeightPerLine = canvas.LocalClipBounds.Height / (height / usedLineOffset);

            //World coordinates of first lineOffset line
            var first100mW = (TL.X + (usedLineOffset - TL.X % usedLineOffset));
            var first100mH = (TL.Y + (usedLineOffset - TL.Y % usedLineOffset));

            //Screen offset of first lineOffset line
            double offsetCW = ((first100mW - TL.X) / usedLineOffset) * screenWidthPerLine;
            double offsetCH = screenHeightPerLine + ((TL.Y - first100mH) / usedLineOffset) * screenHeightPerLine;

            //offset of next 1k
            int KOffsetW = (int)((first100mW % 1000) / usedLineOffset);

            if (KOffsetW < 0)
            {
                KOffsetW = 10 + KOffsetW;
            }
            int KOffsetH = (int)((first100mH % 1000) / usedLineOffset) - 1;

            if (lineCount1000M > 1)
            {
                KOffsetH = lineCount1000M - KOffsetH;
            }

            for (double curX = offsetCW; curX < canvas.LocalClipBounds.Right; curX += screenWidthPerLine)
            {
                var worldPos  = viewport.ScreenToWorld(curX, 0).X;
                var Xgrid10KM = (uint)(worldPos / 10000) % 10;
                var Xgrid1KM  = (uint)(worldPos / 1000) % 10;
                var Xgrid100m = (uint)(worldPos / 100) % 10;
                //var Xgrid10m = (uint)(worldPos / 10) % 10;


                string gridPosString;
                if (usedLineOffsetInt == 1000)
                {
                    gridPosString = $"{Xgrid10KM}{Xgrid1KM}";
                }
                else if (usedLineOffsetInt == 100)
                {
                    gridPosString = $"{Xgrid10KM}{Xgrid1KM}{Xgrid100m}";
                }
                else
                {
                    gridPosString = $"{Xgrid10KM}{Xgrid1KM}{Xgrid100m}{(uint)(worldPos / 10) % 10}";
                }


                SKPaint paint;
                if (KOffsetW >= 1000 && KOffsetW % 1000 == 0)
                {
                    paint = usedPaints.ElementAt(0);
                }
                if (KOffsetW >= 100 && KOffsetW % 100 == 0)
                {
                    paint = usedPaints.ElementAt(2);
                }
                else if (KOffsetW >= 10 && KOffsetW % 10 == 0)
                {
                    paint = usedPaints.ElementAt(1);
                }
                else
                {
                    paint = usedPaints.ElementAt(0);
                }

                if (KOffsetW == lineCount1000M)
                {
                    KOffsetW = 0;
                }

                canvas.DrawLine((float)curX, 0, (float)curX, canvas.LocalClipBounds.Height, paint);



                using (var gtext = SKTextBlob.Create(gridPosString, markerFont))
                    canvas.DrawText(gtext, (float)(curX + screenWidthPerLine / 2) - gtext.Bounds.MidX,
                                    20 + gtext.Bounds.MidY,
                                    paint100m);

                KOffsetW++;
            }

            for (double curH = offsetCH; curH < canvas.LocalClipBounds.Bottom; curH += screenHeightPerLine)
            {
                var worldPos  = viewport.ScreenToWorld(0, curH).Y;
                var Xgrid10KM = (uint)(worldPos / 10000) % 10;
                var Xgrid1KM  = (uint)(worldPos / 1000) % 10;
                var Xgrid100m = (uint)(worldPos / 100) % 10;
                //var Xgrid10m = (uint)(worldPos / 10) % 10;

                string gridPosString;
                if (usedLineOffsetInt == 1000)
                {
                    gridPosString = $"{Xgrid10KM}{Xgrid1KM}";
                }
                else if (usedLineOffsetInt == 100)
                {
                    gridPosString = $"{Xgrid10KM}{Xgrid1KM}{Xgrid100m}";
                }
                else
                {
                    gridPosString = $"{Xgrid10KM}{Xgrid1KM}{Xgrid100m}{(uint)(worldPos / 10) % 10}";
                }

                SKPaint paint;
                if (KOffsetH >= 100 && KOffsetH % 100 == 0)
                {
                    paint = usedPaints.ElementAt(2);
                }
                else if (KOffsetH >= 10 && KOffsetH % 10 == 0)
                {
                    paint = usedPaints.ElementAt(1);
                }
                else
                {
                    paint = usedPaints.ElementAt(0);
                }



                if (KOffsetH == lineCount1000M)
                {
                    KOffsetH = 0;
                }

                canvas.DrawLine(0, (float)curH, canvas.LocalClipBounds.Width, (float)curH, paint);

                using (var gtext = SKTextBlob.Create(gridPosString, markerFont))
                    canvas.DrawText(gtext, 0,
                                    (float)(curH + screenWidthPerLine / 2) - gtext.Bounds.MidY,
                                    paint100m);


                KOffsetH++;
            }
        }