/// <summary> /// /// </summary> private void EnableBasemapLayer() { if (_baseMapLayer == null) { //Need to first initialize and add the basemap layer synchronously (it will fail if done in // another thread. //First create a temporary imageData with an Envelope (otherwise adding to the map will fail) var tempImageData = new InRamImageData(Properties.Resources.nodata, new Extent(1, 1, 2, 2)); _baseMapLayer = new MapImageLayer(tempImageData) { Projection = App.Map.Projection, LegendText = Properties.Resources.Legend_Title }; _baseMapLayer.RemoveItem += BaseMapLayerRemoveItem; AddBasemapLayerToMap(); } App.Map.MapFrame.ViewExtentsChanged += MapFrameExtentsChanged; }
/// <summary> /// Main method of this plugin: gets the tiles from the TileManager, stitches them together, and adds the layer to the map. /// </summary> private void UpdateStichedBasemap(DoWorkEventArgs e) { var map = App.Map as Map; if (map != null) { var rectangle = map.Bounds; var webMercExtent = map.ViewExtents; //Clip the reported Web Merc Envelope to be within possible Web Merc extents // This fixes an issue with Reproject returning bad results for very large (impossible) web merc extents reported from the Map var webMercTopLeftX = TileCalculator.Clip(webMercExtent.MinX, TileCalculator.MinWebMercX, TileCalculator.MaxWebMercX); var webMercTopLeftY = TileCalculator.Clip(webMercExtent.MaxY, TileCalculator.MinWebMercY, TileCalculator.MaxWebMercY); var webMercBtmRightX = TileCalculator.Clip(webMercExtent.MaxX, TileCalculator.MinWebMercX, TileCalculator.MaxWebMercX); var webMercBtmRightY = TileCalculator.Clip(webMercExtent.MinY, TileCalculator.MinWebMercY, TileCalculator.MaxWebMercY); //report progress and check for cancel _bw.ReportProgress(25); if (_bw.CancellationPending) { e.Cancel = true; return; } //Get the web mercator vertices of the current map view var mapVertices = new[] { webMercTopLeftX, webMercTopLeftY, webMercBtmRightX, webMercBtmRightY }; double[] z = { 0, 0 }; //Reproject from web mercator to WGS1984 geographic Reproject.ReprojectPoints(mapVertices, z, WebMercProj, Wgs84Proj, 0, mapVertices.Length / 2); var geogEnv = new Envelope(mapVertices[0], mapVertices[2], mapVertices[1], mapVertices[3]); //report progress and check for cancel _bw.ReportProgress(40); if (_bw.CancellationPending) { e.Cancel = true; return; } //Grab the tiles var tiles = _tileManager.GetTiles(geogEnv, rectangle); //report progress and check for cancel _bw.ReportProgress(60); if (_bw.CancellationPending) { e.Cancel = true; return; } //Stitch them into a single image var stitchedBasemap = TileCalculator.StitchTiles(tiles); stitchedBasemap = GetTransparentBasemapImage(stitchedBasemap, _opacity); var tileImage = new InRamImageData(stitchedBasemap); //report progress and check for cancel _bw.ReportProgress(70); if (_bw.CancellationPending) { e.Cancel = true; return; } //Tiles will have often slightly different bounds from what we are displaying on screen // so we need to get the top left and bottom right tiles' bounds to get the proper extent // of the tiled image var topLeftTile = tiles[0, 0]; var bottomRightTile = tiles[tiles.GetLength(0) - 1, tiles.GetLength(1) - 1]; var tileVertices = new[] { topLeftTile.Envelope.TopLeft().X, topLeftTile.Envelope.TopLeft().Y, bottomRightTile.Envelope.BottomRight().X, bottomRightTile.Envelope.BottomRight().Y }; //Reproject from WGS1984 geographic coordinates to web mercator so we can show on the map Reproject.ReprojectPoints(tileVertices, z, Wgs84Proj, WebMercProj, 0, tileVertices.Length / 2); tileImage.Bounds = new RasterBounds(stitchedBasemap.Height, stitchedBasemap.Width, new Extent(tileVertices[0], tileVertices[3], tileVertices[2], tileVertices[1])); //report progress and check for cancel _bw.ReportProgress(90); if (_bw.CancellationPending) { e.Cancel = true; return; } _baseMapLayer.Image = tileImage; //report progress and check for cancel _bw.ReportProgress(99); if (_bw.CancellationPending) { e.Cancel = true; return; } } }
/// <summary> /// Creates a new raster with the specified cell size. If the cell size /// is zero, this will default to the shorter of the width or height /// divided by 256. If the cell size produces a raster that is greater /// than 8, 000 pixels in either dimension, it will be re-sized to /// create an 8, 000 length or width raster. /// </summary> /// <param name="fs">The featureset to convert to a raster.</param> /// <param name="extent">Force the raster to this specified extent.</param> /// <param name="cellSize">The double extent of the cell.</param> /// <param name="fieldName">The integer field index of the file.</param> /// <param name="outputFileName">The fileName of the raster to create.</param> /// <param name="driverCode">The optional GDAL driver code to use if using GDAL /// for a format that is not discernable from the file extension. An empty string /// is usually perfectly acceptable here.</param> /// <param name="options">For GDAL rasters, they can be created with optional parameters /// passed in as a string array. In most cases an empty string is perfectly acceptable.</param> /// <param name="progressHandler">An interface for handling the progress messages.</param> /// <returns>Generates a raster from the vectors.</returns> public static IRaster ToRaster(IFeatureSet fs, Extent extent, double cellSize, string fieldName, string outputFileName, string driverCode, string[] options, IProgressHandler progressHandler) { Extent env = extent; if (cellSize == 0) { if (env.Width < env.Height) { cellSize = env.Width / 256; } else { cellSize = env.Height / 256; } } int w = (int)Math.Ceiling(env.Width / cellSize); if (w > 8000) { w = 8000; cellSize = env.Width / 8000; } int h = (int)Math.Ceiling(env.Height / cellSize); if (h > 8000) { h = 8000; } Bitmap bmp = new Bitmap(w, h); Graphics g = Graphics.FromImage(bmp); g.Clear(Color.Transparent); g.SmoothingMode = SmoothingMode.None; g.TextRenderingHint = TextRenderingHint.SingleBitPerPixel; g.InterpolationMode = InterpolationMode.NearestNeighbor; Hashtable colorTable; MapArgs args = new MapArgs(new Rectangle(0, 0, w, h), env, g); switch (fs.FeatureType) { case FeatureType.Polygon: { MapPolygonLayer mpl = new MapPolygonLayer(fs); PolygonScheme ps = new PolygonScheme(); colorTable = ps.GenerateUniqueColors(fs, fieldName); mpl.Symbology = ps; mpl.DrawRegions(args, new List<Extent> { env }); } break; case FeatureType.Line: { MapLineLayer mpl = new MapLineLayer(fs); LineScheme ps = new LineScheme(); colorTable = ps.GenerateUniqueColors(fs, fieldName); mpl.Symbology = ps; mpl.DrawRegions(args, new List<Extent> { env }); } break; default: { MapPointLayer mpl = new MapPointLayer(fs); PointScheme ps = new PointScheme(); colorTable = ps.GenerateUniqueColors(fs, fieldName); mpl.Symbology = ps; mpl.DrawRegions(args, new List<Extent> { env }); } break; } Type tp = fieldName == "FID" ? typeof(int) : fs.DataTable.Columns[fieldName].DataType; // We will try to convert to double if it is a string if (tp == typeof(string)) { tp = typeof(double); } InRamImageData image = new InRamImageData(bmp, env); ProgressMeter pm = new ProgressMeter(progressHandler, "Converting To Raster Cells", h); IRaster output; output = Raster.Create(outputFileName, driverCode, w, h, 1, tp, options); output.Bounds = new RasterBounds(h, w, env); double noDataValue = output.NoDataValue; if (fieldName != "FID") { // We can't use this method to calculate Max on a non-existent FID field. double dtMax = Convert.ToDouble(fs.DataTable.Compute("Max(" + fieldName + ")", "")); double dtMin = Convert.ToDouble(fs.DataTable.Compute("Min(" + fieldName + ")", "")); if (dtMin <= noDataValue && dtMax >= noDataValue) { if (dtMax != GetFieldValue(tp, "MaxValue")) { output.NoDataValue = noDataValue; } else if (dtMin != GetFieldValue(tp, "MinValue")) { output.NoDataValue = noDataValue; } } } List<RcIndex> locations = new List<RcIndex>(); List<string> failureList = new List<string>(); for (int row = 0; row < h; row++) { for (int col = 0; col < w; col++) { Color c = image.GetColor(row, col); if (c.A == 0) { output.Value[row, col] = output.NoDataValue; } else { if (colorTable.ContainsKey(c) == false) { if (c.A < 125) { output.Value[row, col] = output.NoDataValue; continue; } // Use a color matching distance to pick the closest member object val = GetCellValue(w, h, row, col, image, c, colorTable, locations); output.Value[row, col] = GetDouble(val, failureList); } else { output.Value[row, col] = GetDouble(colorTable[c], failureList); } } } pm.CurrentValue = row; } const int maxIterations = 5; int iteration = 0; while (locations.Count > 0) { List<RcIndex> newLocations = new List<RcIndex>(); foreach (RcIndex location in locations) { object val = GetCellValue(w, h, location.Row, location.Column, image, image.GetColor(location.Row, location.Column), colorTable, newLocations); output.Value[location.Row, location.Column] = GetDouble(val, failureList); } locations = newLocations; iteration++; if (iteration > maxIterations) { break; } } pm.Reset(); return output; }