コード例 #1
0
        public void CanConvertLatLngToPixelOffset()
        {
            List <WGSPoint> latLngs = new List <WGSPoint>
            {
                new WGSPoint(36.210.LatDegreesToRadians(), -115.025.LonDegreesToRadians()),
                new WGSPoint(36.205.LatDegreesToRadians(), -115.029.LonDegreesToRadians()),
                new WGSPoint(36.200.LatDegreesToRadians(), -115.018.LonDegreesToRadians())
            };
            var topLeft     = new Point(100, 250);
            var pixelPoints = TileServiceUtils.LatLngToPixelOffset(latLngs, topLeft, 32768);

            var expectedPoints = new PointF[3]
            {
                new PointF {
                    X = 1513777.25F, Y = 3287930F
                },
                new PointF {
                    X = 1513684F, Y = 3288074.5F
                },
                new PointF {
                    X = 1513940.38F, Y = 3288218.75F
                },
            };

            for (int i = 0; i < 3; i++)
            {
                Assert.Equal(expectedPoints[i], pixelPoints[i]);
            }
        }
コード例 #2
0
        private async Task JoinDataOceanTiles(FileData dxfFile, MasterDataModels.Point tileTopLeft, MasterDataModels.Point tileBottomRight, Image <Rgba32> tileBitmap, int zoomLevel)
        {
            var fileName = DataOceanFileUtil.DataOceanFileName(dxfFile.Name,
                                                               dxfFile.ImportedFileType == ImportedFileType.SurveyedSurface || dxfFile.ImportedFileType == ImportedFileType.GeoTiff,
                                                               Guid.Parse(dxfFile.ImportedFileUid), dxfFile.SurveyedUtc);

            fileName = DataOceanFileUtil.GeneratedFileName(fileName, dxfFile.ImportedFileType);
            var dataOceanFileUtil = new DataOceanFileUtil($"{DataOceanUtil.PathSeparator}{dataOceanRootFolder}{dxfFile.Path}{DataOceanUtil.PathSeparator}{fileName}");

            log.LogDebug($"{nameof(JoinDataOceanTiles)}: fileName: {fileName} dataOceanFileUtil.FullFileName {dataOceanFileUtil.FullFileName}");

            for (int yTile = (int)tileTopLeft.y; yTile <= (int)tileBottomRight.y; yTile++)
            {
                for (int xTile = (int)tileTopLeft.x; xTile <= (int)tileBottomRight.x; xTile++)
                {
                    var targetFile = dataOceanFileUtil.GetTileFileName(zoomLevel, yTile, xTile);
                    log.LogDebug($"JoinDxfTiles: getting tile {targetFile}");
                    var file = await dataOceanClient.GetFile(targetFile, authn.CustomHeaders());

                    if (file != null)
                    {
                        Image <Rgba32> tile = Image.Load <Rgba32>(file);

                        Point offset = new Point(
                            (xTile - (int)tileTopLeft.x) * MasterDataModels.WebMercatorProjection.TILE_SIZE,
                            (yTile - (int)tileTopLeft.y) * MasterDataModels.WebMercatorProjection.TILE_SIZE);
                        tileBitmap.Mutate(ctx => ctx.DrawImage(tile, PixelBlenderMode.Normal, 1f, offset));
                    }
                }
            }
        }
コード例 #3
0
        /// <summary>
        /// Gets a tile at a higher zoom level and scales part of it for the requested tile
        /// </summary>
        /// <param name="topLeftTile">The top left tile coordinates</param>
        /// <param name="zoomLevel">The requested zoom level</param>
        /// <param name="path">The file path</param>
        /// <param name="generatedName">The name of the DXF file (for design and alignment files it is generated)</param>
        /// <param name="filespaceId">The filespace ID</param>
        /// <param name="maxZoomLevel">The maximum zoom level for which tiles have been generated</param>
        /// <param name="numTiles">The number of tiles for the requested zoom level</param>
        /// <returns>A scaled tile</returns>
        private async Task <byte[]> GetTileAtHigherZoom(Point topLeftTile, int zoomLevel, string path,
                                                        string generatedName, string filespaceId, int maxZoomLevel, int numTiles)
        {
            int zoomLevelFound = maxZoomLevel;

            // Calculate the tile coords of the higher zoom level tile that covers the requested tile
            Point ptRequestedTile  = new Point(topLeftTile.y, topLeftTile.x);
            Point ptRequestedPixel = WebMercatorProjection.TileToPixel(ptRequestedTile);

            int   numTilesAtRequestedZoomLevel = numTiles;
            Point ptRequestedWorld             =
                WebMercatorProjection.PixelToWorld(ptRequestedPixel, numTilesAtRequestedZoomLevel);

            int   numTilesAtFoundZoomLevel = TileServiceUtils.NumberOfTiles(maxZoomLevel);
            Point ptHigherPixel            = WebMercatorProjection.WorldToPixel(ptRequestedWorld, numTilesAtFoundZoomLevel);

            Point ptHigherTile = WebMercatorProjection.PixelToTile(ptHigherPixel);
            //Note PixelToTile uses Math.Floor so this tile coordinate will be the top left of the tile

            // With the new tile coords of the higher zoom level tile, see if it exists on TCC
            string fullHigherTileName =
                $"{FileUtils.ZoomPath(FileUtils.TilePath(path, generatedName), zoomLevelFound)}/{ptHigherTile.y}/{ptHigherTile.x}.png";

            log.LogDebug("DxfTileExecutor: looking for higher tile {0}", fullHigherTileName);

            byte[] tileData = await DownloadTile(filespaceId, fullHigherTileName, "higher");

            if (tileData != null)
            {
                tileData = ScaleTile(tileData, zoomLevel - zoomLevelFound, ptHigherTile, ptRequestedWorld,
                                     numTilesAtFoundZoomLevel);
            }
            return(tileData);
        }
コード例 #4
0
        public void MapPointToXYZ()
        {
            var gridPoint = new Point(1.234, 5.678);
            var xyz       = AutoMapperUtility.Automapper.Map <XYZ>(gridPoint);

            Assert.Equal(gridPoint.Longitude, xyz.X);
            Assert.Equal(gridPoint.Latitude, xyz.Y);
            Assert.Equal(0, xyz.Z);
        }
コード例 #5
0
        /// <summary>
        /// Gets a tile at the requested zoom level.
        /// </summary>
        /// <param name="topLeftTile">The top left tile coordinates</param>
        /// <param name="zoomLevel">The requested zoom level</param>
        /// <param name="path">The file path</param>
        /// <param name="fileName">The name of the DXF file</param>
        /// <returns>A generated tile</returns>
        protected Task <byte[]> GetTileAtRequestedZoom(Point topLeftTile, int zoomLevel, string path, string fileName)
        {
            //Work out tile location
            var fullTileName = GetFullTileName(topLeftTile, zoomLevel, path, fileName);

            log.LogDebug($"DxfTileExecutor: looking for requested tile {fullTileName}");

            return(DownloadTile(fullTileName, "requested"));
        }
コード例 #6
0
        /// <summary>
        /// Converts the lat/lng points to pixels and offsets them from the top left corner of the tile.
        /// </summary>
        /// <param name="latLngs">The list of points to convert in radians</param>
        /// <param name="pixelTopLeft">The top left corner of the tile in pixels</param>
        /// <param name="numTiles">The number of tiles for the zoom level</param>
        /// <returns>The points in pixels relative to the top left corner of the tile.</returns>
        public static PointF[] LatLngToPixelOffset(IEnumerable <WGSPoint> latLngs, MasterDataModels.Point pixelTopLeft, long numTiles)
        {
            List <PointF> pixelPoints = new List <PointF>();

            foreach (WGSPoint ll in latLngs)
            {
                MasterDataModels.Point pixelPt = LatLngToPixel(ll.Lat, ll.Lon, numTiles);
                pixelPoints.Add(new PointF((float)(pixelPt.x - pixelTopLeft.x), (float)(pixelPt.y - pixelTopLeft.y)));
            }
            return(pixelPoints.ToArray());
        }
コード例 #7
0
        /// <summary>
        /// Scales a tile
        /// </summary>
        /// <param name="tileData">The tile to scale</param>
        /// <param name="zoomLevelDifference">The difference between the downloaded tile and the rqeuested tile zoom levels</param>
        /// <param name="ptHigherTile"></param>
        /// <param name="ptRequestedWorld"></param>
        /// <param name="numTilesAtFoundZoomLevel">The number of tiles for the higher zoom level</param>
        /// <returns>A scaled tile</returns>
        private byte[] ScaleTile(byte[] tileData, int zoomLevelDifference, Point ptHigherTile, Point ptRequestedWorld,
                                 int numTilesAtFoundZoomLevel)
        {
            // Calculate the tile coords of the BR corner of the higher zoom level tile
            // so that we can identify which sub-part of it to crop and scale
            Point ptHigherTileTopLeft  = ptHigherTile;
            Point ptHigherTileBotRight = new Point(ptHigherTile.y + 1, ptHigherTile.x + 1);

            // Calculate the sub-tile rectangle that we need to crop out of the  higher tile
            // using a simple proportion calculation based on which part of the higher tile
            // covers the original requested tile in world coordinates
            Point ptHigherWorldTopLeft =
                WebMercatorProjection.PixelToWorld(WebMercatorProjection.TileToPixel(ptHigherTileTopLeft),
                                                   numTilesAtFoundZoomLevel);
            Point ptHigherWorldBotRight =
                WebMercatorProjection.PixelToWorld(WebMercatorProjection.TileToPixel(ptHigherTileBotRight),
                                                   numTilesAtFoundZoomLevel);

            double ratioX = (ptRequestedWorld.x - ptHigherWorldTopLeft.x) /
                            (ptHigherWorldBotRight.x - ptHigherWorldTopLeft.x);
            double ratioY = (ptRequestedWorld.y - ptHigherWorldTopLeft.y) /
                            (ptHigherWorldBotRight.y - ptHigherWorldTopLeft.y);

            int startX = (int)Math.Floor(WebMercatorProjection.TILE_SIZE * ratioX);
            int startY = (int)Math.Floor(WebMercatorProjection.TILE_SIZE * ratioY);

            // Calculate how much up-scaling of higher level zoom tile we need to do
            // based on the difference between the requested and higher zoom levels
            int croppedTileSize = WebMercatorProjection.TILE_SIZE / (1 << zoomLevelDifference);

            // Set the crop rectangle and draw it into a new bitmap, scaling it up to the standard tile size
            Rectangle cropRect = new Rectangle(startX, startY, croppedTileSize, croppedTileSize);

            log.LogDebug("DxfTileExecutor: crop rectangle x = {0}, y = {1}, size = {2}", startX, startY,
                         croppedTileSize);

            //source bitmap
            using (var tileStream = new MemoryStream(tileData))
                using (Bitmap higherBitmap = new Bitmap(tileStream))
                    //destination bitmap
                    using (Bitmap target = new Bitmap(WebMercatorProjection.TILE_SIZE, WebMercatorProjection.TILE_SIZE))
                        using (Graphics g = Graphics.FromImage(target))
                        {
                            g.CompositingMode    = CompositingMode.SourceCopy;
                            g.CompositingQuality = CompositingQuality.HighQuality;
                            g.InterpolationMode  = InterpolationMode.HighQualityBicubic;
                            g.SmoothingMode      = SmoothingMode.HighQuality;
                            g.PixelOffsetMode    = PixelOffsetMode.HighQuality;
                            g.DrawImage(higherBitmap, new Rectangle(0, 0, target.Width, target.Height), cropRect,
                                        GraphicsUnit.Pixel);
                            g.Flush();
                            return(target.BitmapToByteArray());
                        }
        }
コード例 #8
0
        /// <summary>
        /// Gets a tile at the requested zoom level.
        /// </summary>
        /// <param name="topLeftTile">The top left tile coordinates</param>
        /// <param name="zoomLevel">The requested zoom level</param>
        /// <param name="path">The file path</param>
        /// <param name="generatedName">The name of the DXF file (for design and alignment files it is generated)</param>
        /// <param name="filespaceId">The filespace ID</param>
        /// <returns>A generated tile</returns>
        private async Task <byte[]> GetTileAtRequestedZoom(Point topLeftTile, int zoomLevel, string path,
                                                           string generatedName, string filespaceId)
        {
            //Work out tile location
            string fullTileName = GetFullTileName(topLeftTile, zoomLevel, path, generatedName);

            log.LogDebug("DxfTileExecutor: looking for requested tile {0}", fullTileName);

            //Download the tile
            return(await DownloadTile(filespaceId, fullTileName, "requested"));
        }
コード例 #9
0
        public void MapPointToFencePoint()
        {
            var point = new Point
            {
                x = 10,
                y = 15
            };
            var fencePoint = AutoMapperUtility.Automapper.Map <FencePoint>(point);

            Assert.Equal(point.x, fencePoint.X);
            Assert.Equal(point.y, fencePoint.Y);
            Assert.Equal(0, fencePoint.Z);
        }
コード例 #10
0
        /// <summary>
        /// Scales a tile
        /// </summary>
        /// <param name="tileData">The tile to scale</param>
        /// <param name="zoomLevelDifference">The difference between the downloaded tile and the rqeuested tile zoom levels</param>
        /// <param name="ptHigherTile"></param>
        /// <param name="ptRequestedWorld"></param>
        /// <param name="numTilesAtFoundZoomLevel">The number of tiles for the higher zoom level</param>
        /// <returns>A scaled tile</returns>
        private byte[] ScaleTile(byte[] tileData, int zoomLevelDifference, Point ptHigherTile, Point ptRequestedWorld,
                                 int numTilesAtFoundZoomLevel)
        {
            // Calculate the tile coords of the BR corner of the higher zoom level tile
            // so that we can identify which sub-part of it to crop and scale
            Point ptHigherTileTopLeft  = ptHigherTile;
            Point ptHigherTileBotRight = new Point(ptHigherTile.y + 1, ptHigherTile.x + 1);

            // Calculate the sub-tile rectangle that we need to crop out of the  higher tile
            // using a simple proportion calculation based on which part of the higher tile
            // covers the original requested tile in world coordinates
            var ptHigherWorldTopLeft =
                WebMercatorProjection.PixelToWorld(WebMercatorProjection.TileToPixel(ptHigherTileTopLeft),
                                                   numTilesAtFoundZoomLevel);
            var ptHigherWorldBotRight =
                WebMercatorProjection.PixelToWorld(WebMercatorProjection.TileToPixel(ptHigherTileBotRight),
                                                   numTilesAtFoundZoomLevel);

            var ratioX = (ptRequestedWorld.x - ptHigherWorldTopLeft.x) /
                         (ptHigherWorldBotRight.x - ptHigherWorldTopLeft.x);
            var ratioY = (ptRequestedWorld.y - ptHigherWorldTopLeft.y) /
                         (ptHigherWorldBotRight.y - ptHigherWorldTopLeft.y);

            var startX = (int)Math.Floor(WebMercatorProjection.TILE_SIZE * ratioX);
            var startY = (int)Math.Floor(WebMercatorProjection.TILE_SIZE * ratioY);

            // Calculate how much up-scaling of higher level zoom tile we need to do
            // based on the difference between the requested and higher zoom levels
            var croppedTileSize = WebMercatorProjection.TILE_SIZE / (1 << zoomLevelDifference);

            // Set the crop rectangle and draw it into a new bitmap, scaling it up to the standard tile size
            var cropRect = new Rectangle(startX, startY, croppedTileSize, croppedTileSize);

            log.LogDebug("DxfTileExecutor: crop rectangle x = {0}, y = {1}, size = {2}", startX, startY,
                         croppedTileSize);

            //source bitmap
            using (var tileStream = new MemoryStream(tileData))
                using (var higherBitmap = Image.Load(tileStream))
                {
                    //destination bitmap
                    var target = higherBitmap.Clone(ctx => ctx.Crop(cropRect).Resize(WebMercatorProjection.TILE_SIZE, WebMercatorProjection.TILE_SIZE));
                    return(target.BitmapToByteArray());
                }
        }
コード例 #11
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());
                }
            }
        }
コード例 #12
0
        /// <summary>
        /// Converts the lat/lng point to pixels
        /// </summary>
        /// <param name="latitude">The latitude to convert in radians</param>
        /// <param name="longitude">The longitude to convert in radians</param>
        /// <param name="numTiles">The number of tiles</param>
        /// <returns>Pixel point</returns>
        public static Point LatLngToPixel(double latitude, double longitude, long numTiles)
        {
            var point = new Point(latitude.LatRadiansToDegrees(), longitude.LonRadiansToDegrees());

            return(WebMercatorProjection.LatLngToPixel(point, numTiles));
        }
コード例 #13
0
        protected override async Task <ContractExecutionResult> ProcessAsyncEx <T>(T item)
        {
            var request = item as DxfTileRequest;

            if (request == null)
            {
                ThrowRequestTypeCastException <DxfTileRequest>();
            }

            string filespaceId = FileDescriptorExtensions.GetFileSpaceId(configStore, log);

            //Calculate zoom level
            int zoomLevel = TileServiceUtils.CalculateZoomLevel(request.bbox.TopRightLat - request.bbox.BottomLeftLat,
                                                                request.bbox.TopRightLon - request.bbox.BottomLeftLon);

            log.LogDebug("DxfTileExecutor: BBOX differences {0} {1} {2}", request.bbox.TopRightLat - request.bbox.BottomLeftLat,
                         request.bbox.TopRightLon - request.bbox.BottomLeftLon, zoomLevel);
            int   numTiles      = TileServiceUtils.NumberOfTiles(zoomLevel);
            Point topLeftLatLng = new Point(request.bbox.TopRightLat.LatRadiansToDegrees(),
                                            request.bbox.BottomLeftLon.LonRadiansToDegrees());
            Point topLeftTile = WebMercatorProjection.LatLngToTile(topLeftLatLng, numTiles);

            log.LogDebug("DxfTileExecutor: zoomLevel={0}, numTiles={1}, xtile={2}, ytile={3}", zoomLevel, numTiles,
                         topLeftTile.x, topLeftTile.y);

            log.LogDebug("DxfTileExecutor: {0} files", request.files.Count());

            //Short circuit overlaying if there no files to overlay as ForAll is an expensive operation
            if (!request.files.Any())
            {
                byte[] emptyOverlayData = null;
                using (Bitmap bitmap = new Bitmap(WebMercatorProjection.TILE_SIZE, WebMercatorProjection.TILE_SIZE))
                {
                    emptyOverlayData = bitmap.BitmapToByteArray();
                }
                return(new TileResult(emptyOverlayData));
            }

            log.LogDebug(string.Join(",", request.files.Select(f => f.Name).ToList()));

            List <byte[]> tileList = new List <byte[]>();

            var fileTasks = request.files.Select(async file =>
            {
                //foreach (var file in request.files)
                //Check file type to see if it has tiles
                if (file.ImportedFileType == ImportedFileType.Alignment ||
                    file.ImportedFileType == ImportedFileType.DesignSurface ||
                    file.ImportedFileType == ImportedFileType.Linework)
                {
                    if (zoomLevel >= file.MinZoomLevel)
                    {
                        var suffix           = FileUtils.GeneratedFileSuffix(file.ImportedFileType);
                        string generatedName = FileUtils.GeneratedFileName(file.Name, suffix, FileUtils.DXF_FILE_EXTENSION);
                        byte[] tileData      = null;
                        if (zoomLevel <= file.MaxZoomLevel || file.MaxZoomLevel == 0) //0 means not calculated
                        {
                            tileData = await GetTileAtRequestedZoom(topLeftTile, zoomLevel, file.Path, generatedName, filespaceId);
                        }
                        else if (zoomLevel - file.MaxZoomLevel <= 5) //Don't try to scale if the difference is too excessive
                        {
                            tileData = await GetTileAtHigherZoom(topLeftTile, zoomLevel, file.Path, generatedName, filespaceId,
                                                                 file.MaxZoomLevel, numTiles);
                        }
                        else
                        {
                            log.LogDebug(
                                "DxfTileExecutor: difference between requested and maximum zooms too large; not even going to try to scale tile");
                        }
                        if (tileData != null)
                        {
                            tileList.Add(tileData);
                        }
                    }
                }
            });

            await Task.WhenAll(fileTasks);

            //Overlay the tiles. Return an empty tile if none to overlay.
            log.LogDebug("DxfTileExecutor: Overlaying {0} tiles", tileList.Count);
            byte[] overlayData          = null;
            System.Drawing.Point origin = new System.Drawing.Point(0, 0);
            using (Bitmap bitmap = new Bitmap(WebMercatorProjection.TILE_SIZE, WebMercatorProjection.TILE_SIZE))
                using (Graphics g = Graphics.FromImage(bitmap))
                {
                    foreach (byte[] tileData in tileList)
                    {
                        using (var tileStream = new MemoryStream(tileData))
                        {
                            Image image = Image.FromStream(tileStream);
                            g.DrawImage(image, origin);
                        }
                    }
                    overlayData = bitmap.BitmapToByteArray();
                }

            return(new TileResult(overlayData));
        }
コード例 #14
0
 /// <summary>
 /// Gets the full file name for a tile
 /// </summary>
 /// <param name="topLeftTile">The top left tile coordinates</param>
 /// <param name="zoomLevel">The zoom level of the tile</param>
 /// <param name="path">The file path</param>
 /// <param name="generatedName">The name of the DXF file (for design and alignment files it is generated)</param>
 /// <returns></returns>
 private string GetFullTileName(Point topLeftTile, int zoomLevel, string path, string generatedName)
 {
     return
         ($"{FileUtils.ZoomPath(FileUtils.TilePath(path, generatedName), zoomLevel)}/{topLeftTile.y}/{topLeftTile.x}.png");
 }
コード例 #15
0
        protected override async Task <ContractExecutionResult> ProcessAsyncEx <T>(T item)
        {
            List <FileData>     files       = null;
            int                 zoomLevel   = 0;
            Point               topLeftTile = null;
            int                 numTiles    = 0;
            BoundingBox2DLatLon bbox        = null;

            if (item is DxfTileRequest request)
            {
                files = request.files?.ToList();
                bbox  = request.bbox;

                //Calculate zoom level
                zoomLevel = TileServiceUtils.CalculateZoomLevel(request.bbox.TopRightLat - request.bbox.BottomLeftLat,
                                                                request.bbox.TopRightLon - request.bbox.BottomLeftLon);
                log.LogDebug("DxfTileExecutor: BBOX differences {0} {1} {2}", request.bbox.TopRightLat - request.bbox.BottomLeftLat,
                             request.bbox.TopRightLon - request.bbox.BottomLeftLon, zoomLevel);
                numTiles = TileServiceUtils.NumberOfTiles(zoomLevel);
                Point topLeftLatLng = new Point(request.bbox.TopRightLat.LatRadiansToDegrees(),
                                                request.bbox.BottomLeftLon.LonRadiansToDegrees());
                topLeftTile = WebMercatorProjection.LatLngToTile(topLeftLatLng, numTiles);
                log.LogDebug($"DxfTileExecutor: zoomLevel={zoomLevel}, numTiles={numTiles}, xtile={topLeftTile.x}, ytile={topLeftTile.y}");
            }
            else if (item is DxfTile3dRequest request3d)
            {
                files = request3d.files?.ToList();

                zoomLevel   = request3d.zoomLevel;
                numTiles    = TileServiceUtils.NumberOfTiles(zoomLevel);
                topLeftTile = new Point {
                    x = request3d.xTile, y = request3d.yTile
                };
            }
            else
            {
                ThrowRequestTypeCastException <DxfTileRequest>();
            }

            log.LogDebug($"DxfTileExecutor: {files?.Count ?? 0} files");

            //Short circuit overlaying if there no files to overlay as ForAll is an expensive operation
            if (files == null || !files.Any())
            {
                byte[] emptyOverlayData;
                using (var bitmap = new Image <Rgba32>(WebMercatorProjection.TILE_SIZE, WebMercatorProjection.TILE_SIZE))
                {
                    emptyOverlayData = bitmap.BitmapToByteArray();
                }

                return(new TileResult(emptyOverlayData));
            }

            log.LogDebug(string.Join(",", files.Select(f => f.Name).ToList()));

            var          tileList = new List <byte[]>();
            const string DATA_OCEAN_ROOT_FOLDER_ID_KEY = "DATA_OCEAN_ROOT_FOLDER_ID";
            var          dataOceanRootFolder           = configStore.GetValueString(DATA_OCEAN_ROOT_FOLDER_ID_KEY);

            if (string.IsNullOrEmpty(dataOceanRootFolder))
            {
                throw new ArgumentException($"Missing environment variable {DATA_OCEAN_ROOT_FOLDER_ID_KEY}");
            }

            //For GeoTIFF files, use the latest version of a file
            var geoTiffFiles = files.Where(x => x.ImportedFileType == ImportedFileType.GeoTiff).ToList();

            if (geoTiffFiles.Any())
            {
                //Find any with multiple versions and remove old ones from the list
                var latestFiles = geoTiffFiles.GroupBy(g => g.Name).Select(g => g.OrderBy(o => o.SurveyedUtc).Last()).ToList();
                foreach (var geoTiffFile in geoTiffFiles)
                {
                    if (!latestFiles.Contains(geoTiffFile))
                    {
                        files.Remove(geoTiffFile);
                    }
                }
            }

            var fileTasks = files.Select(async file =>
            {
                //foreach (var file in request.files)
                //Check file type to see if it has tiles
                if (file.ImportedFileType == ImportedFileType.Linework ||
                    file.ImportedFileType == ImportedFileType.GeoTiff)
                {
                    var fullPath = DataOceanFileUtil.DataOceanPath(dataOceanRootFolder, file.CustomerUid, file.ProjectUid);
                    var fileName = DataOceanFileUtil.DataOceanFileName(file.Name,
                                                                       file.ImportedFileType == ImportedFileType.SurveyedSurface || file.ImportedFileType == ImportedFileType.GeoTiff,
                                                                       Guid.Parse(file.ImportedFileUid), file.SurveyedUtc);
                    fileName = DataOceanFileUtil.GeneratedFileName(fileName, file.ImportedFileType);

                    if (zoomLevel >= file.MinZoomLevel)
                    {
                        byte[] tileData = null;
                        if (zoomLevel <= file.MaxZoomLevel || file.MaxZoomLevel == 0) //0 means not calculated
                        {
                            tileData = await GetTileAtRequestedZoom(topLeftTile, zoomLevel, fullPath, fileName);
                        }
                        else if (zoomLevel - file.MaxZoomLevel <= 5) //Don't try to scale if the difference is too excessive
                        {
                            tileData = await GetTileAtHigherZoom(topLeftTile, zoomLevel, fullPath, fileName,
                                                                 file.MaxZoomLevel, numTiles);
                        }
                        else
                        {
                            log.LogDebug(
                                "DxfTileExecutor: difference between requested and maximum zooms too large; not even going to try to scale tile");
                        }

                        if (tileData != null && tileData.Length > 0)
                        {
                            tileList.Add(tileData);
                        }
                    }
                }
            });

            await Task.WhenAll(fileTasks);

            log.LogDebug($"DxfTileExecutor: Overlaying {tileList.Count} tiles");
            byte[] overlayData = TileOverlay.OverlayTiles(tileList);

            return(new TileResult(overlayData));
        }
コード例 #16
0
 /// <summary>
 /// Gets the full file name for a tile
 /// </summary>
 private static string GetFullTileName(Point topLeftTile, int zoomLevel, string path, string fileName)
 {
     return(new DataOceanFileUtil($"{path}{DataOceanUtil.PathSeparator}{fileName}").GetTileFileName(zoomLevel, (int)topLeftTile.y, (int)topLeftTile.x));
 }