Example #1
0
        public void CanConvertLatLngToPixel(double latDegrees, double lngDegrees, float xExpected, float yExpected)
        {
            var pixelPoint = TileServiceUtils.LatLngToPixel(latDegrees.LatDegreesToRadians(), lngDegrees.LonDegreesToRadians(), 32768);

            Assert.Equal(xExpected, pixelPoint.x, 0);
            Assert.Equal(yExpected, pixelPoint.y, 0);
        }
Example #2
0
        private void TryZoomIn(MapParameters parameters, out int requiredWidth, out int requiredHeight, out Point pixelMin, out Point pixelMax)
        {
            pixelMin = TileServiceUtils.LatLngToPixel(parameters.bbox.minLat, parameters.bbox.minLng, parameters.numTiles);
            pixelMax = TileServiceUtils.LatLngToPixel(parameters.bbox.maxLat, parameters.bbox.maxLng, parameters.numTiles);

            requiredWidth  = (int)Math.Abs(pixelMax.x - pixelMin.x);
            requiredHeight = (int)Math.Abs(pixelMax.y - pixelMin.y);

            //See if we can zoom in - occurs when the requested tile size is much larger than the bbox
            var   zoomedWidth    = requiredWidth;
            var   zoomedHeight   = requiredHeight;
            int   zoomLevel      = parameters.zoomLevel;
            Point zoomedPixelMin = pixelMin;
            Point zoomedPixelMax = pixelMax;
            long  numTiles       = parameters.numTiles;

            //allow a 15% margin extra otherwise if the tile is only a few pixels bigger than the calculated zoom
            //we use the smaller zoom level and end up with lots of space around the data.
            //AdjustBoundingBoxToFit handles the bigger size.
            var mapWidth  = parameters.mapWidth * 1.15;
            var mapHeight = parameters.mapHeight * 1.15;

            while (zoomedWidth < mapWidth && zoomedHeight < mapHeight && zoomLevel < MAX_ZOOM_LEVEL)
            {
                parameters.zoomLevel = zoomLevel;
                parameters.numTiles  = numTiles;
                requiredWidth        = zoomedWidth;
                requiredHeight       = zoomedHeight;
                pixelMin             = zoomedPixelMin;
                pixelMax             = zoomedPixelMax;

                zoomLevel++;
                numTiles = TileServiceUtils.NumberOfTiles(zoomLevel);

                zoomedPixelMin = TileServiceUtils.LatLngToPixel(parameters.bbox.minLat, parameters.bbox.minLng, numTiles);
                zoomedPixelMax = TileServiceUtils.LatLngToPixel(parameters.bbox.maxLat, parameters.bbox.maxLng, numTiles);

                zoomedWidth  = (int)Math.Abs(zoomedPixelMax.x - zoomedPixelMin.x);
                zoomedHeight = (int)Math.Abs(zoomedPixelMax.y - zoomedPixelMin.y);
            }
        }
Example #3
0
        /// <summary>
        /// Get the map parameters for the report tile
        /// </summary>
        public MapParameters GetMapParameters(string bbox, int width, int height, bool addMargin, bool adjustBoundingBox)
        {
            log.LogDebug($"GetMapParameters: bbox={bbox}, width={width}, height={height}, addMargin={addMargin}, adjustBoundingBox={adjustBoundingBox}");

            var            bboxRadians = boundingBoxHelper.GetBoundingBox(bbox);
            MapBoundingBox mapBox      = new MapBoundingBox
            {
                minLat = bboxRadians.BottomLeftLat,
                minLng = bboxRadians.BottomLeftLon,
                maxLat = bboxRadians.TopRightLat,
                maxLng = bboxRadians.TopRightLon
            };

            int  zoomLevel = TileServiceUtils.CalculateZoomLevel(mapBox.maxLat - mapBox.minLat, mapBox.maxLng - mapBox.minLng);
            long numTiles  = TileServiceUtils.NumberOfTiles(zoomLevel);

            MapParameters parameters = new MapParameters
            {
                bbox      = mapBox,
                zoomLevel = zoomLevel,
                numTiles  = numTiles,
                mapWidth  = width,
                mapHeight = height,
                addMargin = addMargin
            };

            if (adjustBoundingBox)
            {
                boundingBoxService.AdjustBoundingBoxToFit(parameters);
            }

            parameters.pixelTopLeft = TileServiceUtils.LatLngToPixel(mapBox.maxLat, mapBox.minLng, parameters.numTiles);
            log.LogDebug("MapParameters: " + JsonConvert.SerializeObject(parameters));

            return(parameters);
        }
Example #4
0
        /// <summary>
        /// Joins standard size DXF tiles together to form one large tile for the report
        /// </summary>
        private async Task <byte[]> JoinDxfTiles(MapParameters parameters, FileData dxfFile)
        {
            log.LogDebug($"JoinDxfTiles: {dxfFile.ImportedFileUid}, {dxfFile.Name}");

            //Find the tiles that the bounding box fits into.
            MasterDataModels.Point tileTopLeft      = MasterDataModels.WebMercatorProjection.PixelToTile(parameters.pixelTopLeft);
            MasterDataModels.Point pixelBottomRight = TileServiceUtils.LatLngToPixel(
                parameters.bbox.minLat, parameters.bbox.maxLng, parameters.numTiles);
            MasterDataModels.Point tileBottomRight = MasterDataModels.WebMercatorProjection.PixelToTile(pixelBottomRight);

            int xnumTiles = (int)(tileBottomRight.x - tileTopLeft.x) + 1;
            int ynumTiles = (int)(tileBottomRight.y - tileTopLeft.y) + 1;
            int width     = xnumTiles * MasterDataModels.WebMercatorProjection.TILE_SIZE;
            int height    = ynumTiles * MasterDataModels.WebMercatorProjection.TILE_SIZE;

            using (Image <Rgba32> tileBitmap = new Image <Rgba32>(width, height))
            {
                //Find the offset of the bounding box top left point inside the top left tile
                var point = new MasterDataModels.Point
                {
                    x = tileTopLeft.x * MasterDataModels.WebMercatorProjection.TILE_SIZE,
                    y = tileTopLeft.y * MasterDataModels.WebMercatorProjection.TILE_SIZE
                };
                //Clip to the actual bounding box within the tiles.
                int clipWidth    = parameters.mapWidth;
                int clipHeight   = parameters.mapHeight;
                int xClipTopLeft = (int)(parameters.pixelTopLeft.x - point.x);
                int yClipTopLeft = (int)(parameters.pixelTopLeft.y - point.y);
                //Unlike System.Drawing, which allows the clipRect to have negative x, y and which moves as well as clips when used with DrawImage
                //as the source rectangle, ImageSharp does not respect negative values. So we will have to do extra work in this situation.
                if (xClipTopLeft < 0)
                {
                    clipWidth   += xClipTopLeft;
                    xClipTopLeft = 0;
                }
                if (yClipTopLeft < 0)
                {
                    clipHeight  += yClipTopLeft;
                    yClipTopLeft = 0;
                }
                var clipRect = new Rectangle(xClipTopLeft, yClipTopLeft, clipWidth, clipHeight);

                //Join all the DXF tiles into one large tile
                await JoinDataOceanTiles(dxfFile, tileTopLeft, tileBottomRight, tileBitmap, parameters.zoomLevel);

                //Now clip the large tile
                tileBitmap.Mutate(ctx => ctx.Crop(clipRect));
                if (clipWidth >= parameters.mapWidth && clipHeight >= parameters.mapHeight)
                {
                    return(tileBitmap.BitmapToByteArray());
                }

                //and resize it if required tile area was overlapping rather than within the large tile
                //(negative clip values above)
                using (Image <Rgba32> resizedBitmap = new Image <Rgba32>(parameters.mapWidth, parameters.mapHeight))
                {
                    Point offset = new Point(parameters.mapWidth - clipWidth, parameters.mapHeight - clipHeight);
                    resizedBitmap.Mutate(ctx => ctx.DrawImage(tileBitmap, PixelBlenderMode.Normal, 1f, offset));
                    return(resizedBitmap.BitmapToByteArray());
                }
            }
        }