ThinkGeo Cloud
ThinkGeo UI Controls
ThinkGeo Open Source
Help and Support
External Resources
ThinkGeo Cloud
ThinkGeo UI Controls
ThinkGeo Open Source
Help and Support
External Resources
using System.ComponentModel; namespace CacheGenerator { class CacheGeneratorProgressChangedEventArgs : ProgressChangedEventArgs { private int currentTileIndex; private long totalTileCount; public int CurrentTileIndex { get { return currentTileIndex; } set { currentTileIndex = value; } } public long TotalTilesCount { get { return totalTileCount; } set { totalTileCount = value; } } private CacheGeneratorProgressChangedEventArgs() : this(0, null, 0, 0) { } public CacheGeneratorProgressChangedEventArgs(int progressPercentage, object userState, int currentTileIndex, long totalTilesCount) : base(progressPercentage, userState) { this.currentTileIndex = currentTileIndex; this.totalTileCount = totalTilesCount; } } }
using ThinkGeo.MapSuite.Core; namespace CacheGenerator { class CreatingCellsArgument { private FileBitmapTileCache tileCache; private long currentRowIndex = 0; private long currentColumnIndex = 0; private long rowCount; private long columnCount; private double cellWidth; private double cellHeight; private double startRowIndex; private double startColumnIndex; public CreatingCellsArgument() { } public FileBitmapTileCache TileCache { get { return tileCache; } set { tileCache = value; } } public long CurrentRowIndex { get { return currentRowIndex; } set { currentRowIndex = value; } } public long CurrentColumnIndex { get { return currentColumnIndex; } set { currentColumnIndex = value; } } public long RowCount { get { return rowCount; } set { rowCount = value; } } public long ColumnCount { get { return columnCount; } set { columnCount = value; } } public double CellWidth { get { return cellWidth; } set { cellWidth = value; } } public double CellHeight { get { return cellHeight; } set { cellHeight = value; } } public double StartRowIndex { get { return startRowIndex; } set { startRowIndex = value; } } public double StartColumnIndex { get { return startColumnIndex; } set { startColumnIndex = value; } } public RectangleShape GetCurrentCellExtent() { RectangleShape boundingBox = TileCache.TileMatrix.BoundingBox; PointShape upperLeftPoint = new PointShape(boundingBox.UpperLeftPoint.X + CurrentColumnIndex * CellWidth + StartColumnIndex * CellWidth, boundingBox.UpperLeftPoint.Y - CurrentRowIndex * CellHeight - StartRowIndex * CellHeight); PointShape lowerRightPoint = new PointShape(boundingBox.UpperLeftPoint.X + (CurrentColumnIndex + 1) * CellWidth + StartColumnIndex * CellWidth, boundingBox.UpperLeftPoint.Y - (CurrentRowIndex + 1) * CellHeight - StartRowIndex * CellHeight); RectangleShape totalExtent = new RectangleShape(upperLeftPoint, lowerRightPoint); return totalExtent; } } }
using System; using System.Collections.Generic; using System.Text; using ThinkGeo.MapSuite.Core; namespace CacheGenerator { class CreatingTilesArgument { private FileBitmapTileCache tileCache; private RectangleShape extent; private int bitmapWidth; private int bitmapHeight; public CreatingTilesArgument(FileBitmapTileCache tileCache, RectangleShape extent, int bitmapWidth, int bitmapHeight) { this.tileCache = tileCache; this.extent = extent; this.bitmapWidth = bitmapWidth; this.bitmapHeight = bitmapHeight; } public FileBitmapTileCache TileCache { get { return tileCache; } set { tileCache = value; } } public RectangleShape Extent { get { return extent; } set { extent = value; } } public int BitmapWidth { get { return bitmapWidth; } set { bitmapWidth = value; } } public int BitmapHeight { get { return bitmapHeight; } set { bitmapHeight = value; } } } }
using System.Collections.ObjectModel; using ThinkGeo.MapSuite.Core; namespace CacheGenerator { class LayerProvider { // You can insert your layer to "layersToCache" in this function, they will be used for cache. public static Collection<Layer> GetLayersToCache() { Collection<Layer> layersToCache = new Collection<Layer>(); ShapeFileFeatureLayer layer = new ShapeFileFeatureLayer(@"..\..\App_Data\cntry02.shp", ShapeFileReadWriteMode.ReadOnly); layer.ZoomLevelSet.ZoomLevel01.DefaultAreaStyle = AreaStyles.Country1; layer.ZoomLevelSet.ZoomLevel01.ApplyUntilZoomLevel = ApplyUntilZoomLevel.Level20; layersToCache.Add(layer); return layersToCache; } // You can insert your scales to "scalesToCache" in this function, they will be used for cache. public static Collection<double> GetScalesToCache() { ZoomLevelSet zoomLevelSet = new ZoomLevelSet(); Collection<double> scalesToCache = new Collection<double>(); scalesToCache.Add(zoomLevelSet.ZoomLevel01.Scale); scalesToCache.Add(zoomLevelSet.ZoomLevel02.Scale); scalesToCache.Add(zoomLevelSet.ZoomLevel03.Scale); scalesToCache.Add(zoomLevelSet.ZoomLevel04.Scale); scalesToCache.Add(zoomLevelSet.ZoomLevel05.Scale); scalesToCache.Add(zoomLevelSet.ZoomLevel06.Scale); scalesToCache.Add(zoomLevelSet.ZoomLevel07.Scale); scalesToCache.Add(zoomLevelSet.ZoomLevel08.Scale); scalesToCache.Add(zoomLevelSet.ZoomLevel09.Scale); scalesToCache.Add(zoomLevelSet.ZoomLevel10.Scale); scalesToCache.Add(zoomLevelSet.ZoomLevel11.Scale); scalesToCache.Add(zoomLevelSet.ZoomLevel12.Scale); scalesToCache.Add(zoomLevelSet.ZoomLevel13.Scale); scalesToCache.Add(zoomLevelSet.ZoomLevel14.Scale); scalesToCache.Add(zoomLevelSet.ZoomLevel15.Scale); scalesToCache.Add(zoomLevelSet.ZoomLevel16.Scale); scalesToCache.Add(zoomLevelSet.ZoomLevel17.Scale); scalesToCache.Add(zoomLevelSet.ZoomLevel18.Scale); scalesToCache.Add(zoomLevelSet.ZoomLevel19.Scale); scalesToCache.Add(zoomLevelSet.ZoomLevel20.Scale); return scalesToCache; } } }
using System; using System.Collections.ObjectModel; using System.Drawing; using System.Text; using System.Windows.Forms; using ThinkGeo.MapSuite.Core; namespace CacheGenerator { public partial class MainForm : Form { delegate void InvokeMethod(); DateTime startTime; TileCacheGenerator tileCacheGenerator; GeographyUnit mapUnit = GeographyUnit.DecimalDegree; public MainForm() { InitializeComponent(); } private void CachedImagesGenerateroForm_Load(object sender, EventArgs e) { cmbStartZoomLevel.Text = "ZoomLevel01"; cmbEndZoomLevel.Text = "ZoomLevel07"; cmbTileImageType.Text = "PNG"; } private Collection<double> GetScalesToCache() { Collection<double> scales = LayerProvider.GetScalesToCache(); if (cmbStartZoomLevel.SelectedIndex > cmbEndZoomLevel.SelectedIndex) { cmbStartZoomLevel.SelectedIndex = cmbEndZoomLevel.SelectedIndex; } Collection<double> scalesToCache = new Collection<double>(); for (int i = cmbStartZoomLevel.SelectedIndex; i <= cmbEndZoomLevel.SelectedIndex; i++) { scalesToCache.Add(scales[i]); } return scalesToCache; } private void btnGenerate_Click(object sender, EventArgs e) { btnGenerate.Enabled = false; tileCacheGenerator = new TileCacheGenerator(); tileCacheGenerator.ProgressChanged += new EventHandler<CacheGeneratorProgressChangedEventArgs>(tileCacheGenerator_ProgressChanged); tileCacheGenerator.GenerationCompleted += new EventHandler<EventArgs>(tileCacheGenerator_GenerationCompleted); if (cmbTileImageType.Text.ToUpperInvariant() == "PNG") { tileCacheGenerator.TileImageFormat = TileImageFormat.Png; } else if (cmbTileImageType.Text.ToUpperInvariant() == "JPEG") { tileCacheGenerator.TileImageFormat = TileImageFormat.Jpeg; tileCacheGenerator.JpegQuality = Int16.Parse(txtJpegQuality.Text); } tileCacheGenerator.ScalesToCache = GetScalesToCache(); tileCacheGenerator.LayersToCache = LayerProvider.GetLayersToCache(); string[] upperLeftPointInString = txtUpperLeftX.Text.Split(','); string[] lowerRightPointInString = txtLowerRightX.Text.Split(','); tileCacheGenerator.CachingExtent = new RectangleShape(double.Parse(upperLeftPointInString[0]), double.Parse(upperLeftPointInString[1]), double.Parse(lowerRightPointInString[0]), double.Parse(lowerRightPointInString[1])); if (checkBoxWatermark.Checked) { tileCacheGenerator.WatermarkBitmap = new Bitmap(txtWatermarkPath.Text); } if (checkBoxRestrict.Checked) { tileCacheGenerator.RestrictShapeFilePathName = txtRestrictionLayerPath.Text; int gridSize = Convert.ToInt32(txtGridSize.Text); if (gridSize != 0) { GridRestrictionLayer(txtRestrictionLayerPath.Text, tileCacheGenerator.CachingExtent, gridSize, txtRestrictionLayerPath.Text.Replace(".shp", "_Grid.shp")); tileCacheGenerator.RestrictShapeFilePathName = txtRestrictionLayerPath.Text.Replace(".shp", "_Grid.shp"); } } tileCacheGenerator.MapUnit = mapUnit; tileCacheGenerator.CacheFolder = txtCacheFolder.Text; tileCacheGenerator.ThreadsCount = Convert.ToInt32(txtThreadsCount.Text); startTime = System.DateTime.Now; tileCacheGenerator.GenerateTiles(); } private void GridRestrictionLayer(string restrictShapePathFileName, RectangleShape extentToGrid, int gridSize, string gridedRestrictShapePathFileName) { ShapeFileFeatureSource.BuildIndexFile(restrictShapePathFileName, BuildIndexMode.DoNotRebuild); ShapeFileFeatureLayer restrictionLayer = new ShapeFileFeatureLayer(restrictShapePathFileName); restrictionLayer.Open(); if (restrictionLayer.GetShapeFileType() == ShapeFileType.Polygon) { ShapeFileFeatureSource.CreateShapeFile(ShapeFileType.Polygon, gridedRestrictShapePathFileName, new Collection<DbfColumn>() { new DbfColumn("RECID", DbfColumnType.Integer, 10, 0) }, Encoding.Default, OverwriteMode.Overwrite); ShapeFileFeatureSource gridedRestrictionLayer = new ShapeFileFeatureSource(gridedRestrictShapePathFileName, ShapeFileReadWriteMode.ReadWrite); gridedRestrictionLayer.Open(); gridedRestrictionLayer.BeginTransaction(); double startX = extentToGrid.UpperLeftPoint.X; double startY = extentToGrid.UpperLeftPoint.Y; double cellWidth = extentToGrid.Width / gridSize; double cellHeight = extentToGrid.Height / gridSize; for (int x = 0; x < gridSize; x++) { for (int y = 0; y < gridSize; y++) { RectangleShape boundingBox = new RectangleShape(startX + x * cellWidth, startY - y * cellHeight, startX + x * cellWidth + cellWidth, startY - y * cellHeight - cellHeight); Collection<Feature> fearures = restrictionLayer.QueryTools.GetFeaturesInsideBoundingBox(boundingBox, new Collection<string>() { "RECID" }); foreach (Feature feature in fearures) { MultipolygonShape polygon = (MultipolygonShape)feature.GetShape(); BaseShape areaIntersection = polygon.GetIntersection(boundingBox); if (areaIntersection != null) { Feature newFeature = new Feature(areaIntersection); newFeature.ColumnValues.Add("RECID", feature.ColumnValues["RECID"].ToString()); gridedRestrictionLayer.AddFeature(newFeature); } lblTotalTime.Text = string.Format("Griding the restrict file: Row {0} of {1}, Column {2} of {3}", x, gridSize, y, gridSize); lblCurrentImageCount.Text = string.Empty; Application.DoEvents(); } } } gridedRestrictionLayer.CommitTransaction(); gridedRestrictionLayer.Close(); } } void tileCacheGenerator_ProgressChanged(object sender, CacheGeneratorProgressChangedEventArgs e) { // Make the label update every 100 tiles. if (e.CurrentTileIndex % 100 != 0 && e.CurrentTileIndex < e.TotalTilesCount) { return; } TimeSpan timeSpan = DateTime.Now - startTime; lblCurrentImageCount.Invoke((InvokeMethod)delegate() { lblCurrentImageCount.Text = string.Format("Current Progress: {0} %", e.ProgressPercentage); }); lblTileStatus.Invoke((InvokeMethod)delegate { lblTileStatus.Text = String.Format("{0:N0} Tiles Generated. ", e.CurrentTileIndex); }); double totalMilliseconds = timeSpan.TotalMilliseconds; double averageMilliseconds = totalMilliseconds / e.CurrentTileIndex; double remainingTime = (e.TotalTilesCount - e.CurrentTileIndex) * averageMilliseconds; if (remainingTime < 0) { remainingTime = 0; } lblTotalTime.Invoke((InvokeMethod)delegate() { lblTotalTime.Text = String.Format("TotalTime: {0}; RemainingTime: {1}; AverageTime: {2} ms/Tile", FormattedTimeString(timeSpan), FormattedTimeString(TimeSpan.FromMilliseconds(remainingTime)), averageMilliseconds.ToString("N1")); }); } void tileCacheGenerator_GenerationCompleted(object sender, EventArgs e) { btnGenerate.Invoke((InvokeMethod)delegate() { btnGenerate.Enabled = true; }); lblCurrentImageCount.Invoke((InvokeMethod)delegate() { lblCurrentImageCount.Text = "Current Progress: 100%"; }); MessageBox.Show("Generation Completed!"); } public static string FormattedTimeString(TimeSpan ts) { if (ts.Days > 0) { return String.Format("{0} Days {1} Hours", ts.Days.ToString(), ts.Hours.ToString()); } else if (ts.Hours > 0) { return String.Format("{0} Hours {1} Minutes", ts.Hours.ToString(), ts.Minutes.ToString()); } else if (ts.Minutes > 0) { return String.Format("{0} Minutes {1} Seconds", ts.Minutes.ToString(), ts.Seconds.ToString()); } else { return String.Format("{0} Seconds", ts.Seconds.ToString()); } } private void btnPreview_Click(object sender, EventArgs e) { TileCacheGenerator tileCacheGenerator = new TileCacheGenerator(); tileCacheGenerator.MapUnit = mapUnit; tileCacheGenerator.ScalesToCache = GetScalesToCache(); string[] upperLeftPointInString = txtUpperLeftX.Text.Split(','); string[] lowerRightPointInString = txtLowerRightX.Text.Split(','); tileCacheGenerator.CachingExtent = new RectangleShape(double.Parse(upperLeftPointInString[0]), double.Parse(upperLeftPointInString[1]), double.Parse(lowerRightPointInString[0]), double.Parse(lowerRightPointInString[1])); if (checkBoxRestrict.Checked) { tileCacheGenerator.RestrictShapeFilePathName = txtRestrictionLayerPath.Text; } Collection<long> tilesCount = tileCacheGenerator.GetTilesCountsForScales(); long totalTilesCount = 0; int startIndex = cmbStartZoomLevel.SelectedIndex; StringBuilder sb = new StringBuilder(); sb.AppendLine(); sb.AppendLine(); for (int i = 0; i < tilesCount.Count; i++) { totalTilesCount += tilesCount[i]; sb.AppendFormat("Tiles Count In {0}: {1:N0}", cmbStartZoomLevel.Items[startIndex++], tilesCount[i]); sb.AppendLine(); } sb.Insert(0, string.Format("Total Tiles Count: {0:N0}", totalTilesCount)); tileCacheGenerator.Close(); MessageBox.Show(sb.ToString()); } private void btnSelectCacheFolder_Click(object sender, EventArgs e) { FolderBrowserDialog folderBrowserDialog = new FolderBrowserDialog(); if (folderBrowserDialog.ShowDialog() == DialogResult.OK) { txtCacheFolder.Text = folderBrowserDialog.SelectedPath; } } private void btnSelectWatermark_Click(object sender, EventArgs e) { OpenFileDialog openFileDialog = new OpenFileDialog(); openFileDialog.InitialDirectory = Application.StartupPath; openFileDialog.Filter = "Image File(*.jpg,*.gif,*.bmp,*.png)|*.jpg;*.gif;*.bmp;*.png|All File(*.*)|*.*"; if (openFileDialog.ShowDialog() == DialogResult.OK) { txtWatermarkPath.Text = openFileDialog.FileName; } } private void btnSelectRestrictionLayer_Click(object sender, EventArgs e) { OpenFileDialog openFileDialog = new OpenFileDialog(); openFileDialog.InitialDirectory = Application.StartupPath; openFileDialog.Filter = "Shape File(*.shp)|*.shp|All File(*.*)|*.*"; if (openFileDialog.ShowDialog() == DialogResult.OK) { txtRestrictionLayerPath.Text = openFileDialog.FileName; } } private void cmbTileImageType_SelectedIndexChanged(object sender, EventArgs e) { txtJpegQuality.Enabled = (cmbTileImageType.Text == "JPEG"); lblJpegQuality.Enabled = txtJpegQuality.Enabled; } private void btnCancel_Click(object sender, EventArgs e) { this.Close(); } private void MainForm_FormClosing(object sender, FormClosingEventArgs e) { if (tileCacheGenerator != null) { tileCacheGenerator.Close(); } } private void checkBoxRestrict_CheckedChanged(object sender, EventArgs e) { txtRestrictionLayerPath.ReadOnly = !checkBoxRestrict.Checked; txtGridSize.ReadOnly = !checkBoxRestrict.Checked; } private void checkBoxWatermark_CheckedChanged(object sender, EventArgs e) { txtWatermarkPath.ReadOnly = !checkBoxWatermark.Checked; } } }
using System; using System.Windows.Forms; using System.IO; namespace CacheGenerator { static class Program { /// <summary> /// The main entry point for the application. /// </summary> [STAThread] static void Main(string[] args) { Application.EnableVisualStyles(); Application.SetCompatibleTextRenderingDefault(false); Application.Run(new MainForm()); } } }
using System; using System.Collections.Generic; using System.Collections.ObjectModel; using System.Drawing; using System.IO; using System.Threading; using ThinkGeo.MapSuite.Core; namespace CacheGenerator { class TileCacheGenerator { private int tileWidth = 256; private int tileHeight = 256; // We have this maxTileCountInOneBitmap for optimization. we would rather draw a 4096*4096 bitmap once and split it to 256 tiles, // than draw a 256*256 tile for 256 times. private int maxTileCountInOneBitmap = 16; private int threadsCount; private short jpegQuality; private TileImageFormat tileImageFormat; Collection<Layer> layersToCache; GeographyUnit mapUnit; Collection<double> scales; RectangleShape cachingExtent; string cacheFolder; string restrictShapeFilePathName; Bitmap watermarkBitmap; ShapeFileFeatureLayer restrictionLayer; int currentTileIndex = 0; long totalTilesCount = 0; Collection<Thread> workingThreads; int workingThreadCount; public event EventHandler<CacheGeneratorProgressChangedEventArgs> ProgressChanged; public event EventHandler<EventArgs> GenerationCompleted; Collection<CreatingCellsArgument> cellsArguments = new Collection<CreatingCellsArgument>(); public TileCacheGenerator() { ThreadsCount = 4; } public int ThreadsCount { get { return threadsCount; } set { threadsCount = value; } } public int TileWidth { get { return tileWidth; } set { tileWidth = value; } } public int TileHeight { get { return tileHeight; } set { tileHeight = value; } } public TileImageFormat TileImageFormat { get { return tileImageFormat; } set { tileImageFormat = value; } } public short JpegQuality { get { return jpegQuality; } set { jpegQuality = value; } } public Collection<Layer> LayersToCache { get { return layersToCache; } set { layersToCache = value; } } public GeographyUnit MapUnit { get { return mapUnit; } set { mapUnit = value; } } public Collection<double> ScalesToCache { get { return scales; } set { scales = value; } } public RectangleShape CachingExtent { get { return cachingExtent; } set { cachingExtent = value; } } public string CacheFolder { get { return cacheFolder; } set { cacheFolder = value; } } public string RestrictShapeFilePathName { get { return restrictShapeFilePathName; } set { restrictShapeFilePathName = value; } } public Bitmap WatermarkBitmap { get { return watermarkBitmap; } set { watermarkBitmap = value; } } public void GenerateTiles() { if (!string.IsNullOrEmpty(restrictShapeFilePathName)) { restrictionLayer = new ShapeFileFeatureLayer(restrictShapeFilePathName, ShapeFileReadWriteMode.ReadOnly); restrictionLayer.Open(); } currentTileIndex = 0; totalTilesCount = GetTilesCount(); workingThreads = new Collection<Thread>(); Thread thread = new Thread(new ParameterizedThreadStart(GenerateTiles)); thread.Start(scales); workingThreads.Add(thread); } private void GenerateTiles(object scales) { workingThreadCount = this.ThreadsCount; Collection<double> doubleScales = (Collection<double>)scales; foreach (double scale in doubleScales) { GenerateTilesForOneScale(scale); } ManualResetEvent manualResetEvent = new ManualResetEvent(false); for (int i = 0; i < this.ThreadsCount; i++) { Thread thread = new Thread(new ParameterizedThreadStart(CreateTiles)); thread.Start(manualResetEvent); workingThreads.Add(thread); } manualResetEvent.WaitOne(); foreach (Layer layer in layersToCache) { if (layer.IsOpen) { layer.Close(); } } if (restrictionLayer != null && restrictionLayer.IsOpen) { restrictionLayer.Close(); } OnGenerationCompleted(new EventArgs()); } private void GenerateTilesForOneScale(object scale) { MapSuiteTileMatrix tileMatrix = new MapSuiteTileMatrix((double)scale, tileWidth, tileHeight, mapUnit); tileMatrix.BoundingBoxUnit = mapUnit; FileBitmapTileCache tileCache = new FileBitmapTileCache(cacheFolder, string.Empty, TileImageFormat, tileMatrix); tileCache.JpegQuality = JpegQuality; RectangleShape matrixBoundingBox = tileCache.TileMatrix.BoundingBox; RowColumnRange rowColumnRange = tileCache.TileMatrix.GetIntersectingRowColumnRange(matrixBoundingBox); int deltaColumnIndex = (int)(rowColumnRange.MaxColumnIndex - rowColumnRange.MinColumnIndex); int deltaRowIndex = (int)(rowColumnRange.MaxRowIndex - rowColumnRange.MinRowIndex); int deltaIndex = Math.Max(deltaColumnIndex, deltaRowIndex); double cellWidth = tileCache.TileMatrix.CellWidth; double cellHeight = tileCache.TileMatrix.CellHeight; if (deltaIndex < maxTileCountInOneBitmap) { int bitMapWidth = tileWidth * (deltaColumnIndex + 1); int bitMapHeight = tileHeight * (deltaRowIndex + 1); if (deltaIndex == 0) { CreateTiles(tileCache, matrixBoundingBox, bitMapWidth, bitMapHeight, watermarkBitmap, restrictionLayer); } else { CreateTiles(tileCache, cachingExtent, bitMapWidth, bitMapHeight, watermarkBitmap, restrictionLayer); } } else { long bigCellRowCount = (deltaRowIndex + 1) / (maxTileCountInOneBitmap); long bigCellColumnCount = (deltaColumnIndex + 1) / (maxTileCountInOneBitmap); CreatingCellsArgument cellArgument = new CreatingCellsArgument(); cellArgument.CellWidth = cellWidth * maxTileCountInOneBitmap; cellArgument.CellHeight = cellHeight * maxTileCountInOneBitmap; cellArgument.StartRowIndex = rowColumnRange.MinRowIndex; cellArgument.StartColumnIndex = rowColumnRange.MinColumnIndex; cellArgument.ColumnCount = bigCellColumnCount; cellArgument.RowCount = bigCellRowCount; cellArgument.TileCache = tileCache; cellsArguments.Add(cellArgument); } } private void CreateTiles(object manualResetEvent) { ManualResetEvent resetEvent = (ManualResetEvent)manualResetEvent; Bitmap clonedWatermarkBitmap = GetWatermarkBitmap(); ShapeFileFeatureLayer clonedRestrictedLayer = GetRestrictionLayer(); while (true) { CreatingTilesArgument currentArgument = GetTilesCreatingArgument(); if (currentArgument != null) { CreateTiles(currentArgument.TileCache, currentArgument.Extent, currentArgument.BitmapWidth, currentArgument.BitmapHeight, clonedWatermarkBitmap, clonedRestrictedLayer); } else { break; } } if (clonedRestrictedLayer != null) { clonedRestrictedLayer.Close(); } if (Interlocked.Decrement(ref workingThreadCount) == 0) { resetEvent.Set(); } } private CreatingTilesArgument GetTilesCreatingArgument() { CreatingTilesArgument tilesCreatingArgument = null; lock (cellsArguments) { if (cellsArguments.Count == 0) { return null; } CreatingCellsArgument tileArgument = cellsArguments[0]; if (tileArgument.CurrentRowIndex == tileArgument.RowCount) { cellsArguments.RemoveAt(0); tilesCreatingArgument = GetTilesCreatingArgument(); } else if (tileArgument.CurrentColumnIndex == tileArgument.ColumnCount) { tileArgument.CurrentColumnIndex = 0; tileArgument.CurrentRowIndex++; tilesCreatingArgument = GetTilesCreatingArgument(); } else { RectangleShape totalExtent = tileArgument.GetCurrentCellExtent(); // This is a workaround of an issue or RectangleShape. MultipolygonShape intersection = ((AreaBaseShape)cachingExtent).GetIntersection(totalExtent); if (intersection != null) { tilesCreatingArgument = new CreatingTilesArgument(tileArgument.TileCache, totalExtent, maxTileCountInOneBitmap * tileWidth, maxTileCountInOneBitmap * tileHeight); } tileArgument.CurrentColumnIndex++; } } return tilesCreatingArgument; } private void CreateTiles(FileBitmapTileCache tileCache, RectangleShape extent, int bitmapWidth, int bitmapHeight, Bitmap watermarkBitmap, ShapeFileFeatureLayer restrictionLayer) { if (restrictionLayer == null || restrictionLayer.QueryTools.GetFeaturesIntersecting(extent, ReturningColumnsType.NoColumns).Count > 0) { Bitmap bitmap = new Bitmap(bitmapWidth, bitmapHeight); DrawOnBitmap(LayersToCache, mapUnit, extent, bitmap); SaveBitmapToTiles(tileCache, bitmap, extent, cachingExtent, watermarkBitmap, restrictionLayer, tileWidth, tileHeight); bitmap.Dispose(); } } public void DrawOnBitmap(IEnumerable<Layer> layersTmp, GeographyUnit mapUnit, RectangleShape extent, Bitmap bitmap) { GeoCanvas canvas = new GdiPlusGeoCanvas(); canvas.BeginDrawing(bitmap, extent, mapUnit); Collection<Layer> layers = LayerProvider.GetLayersToCache(); foreach (Layer layer in layers) { if (!layer.IsOpen) { layer.Open(); } layer.Draw(canvas, new Collection<SimpleCandidate>()); } canvas.EndDrawing(); } private void SaveBitmapToTiles(FileBitmapTileCache tileCache, Bitmap bitmap, RectangleShape bitmapExtent, RectangleShape cachingExtent, Bitmap watermarkBitmap, ShapeFileFeatureLayer restrictionLayer, int tileWidth, int tileHeight) { MultipolygonShape resultShapes = ((AreaBaseShape)cachingExtent).GetIntersection(bitmapExtent); if (resultShapes != null) { RectangleShape cachingExtentInBitmapExtent = resultShapes.Polygons[0].GetBoundingBox(); Collection<TileMatrixCell> cells = tileCache.TileMatrix.GetIntersectingCells(cachingExtentInBitmapExtent); foreach (TileMatrixCell cell in cells) { if (restrictionLayer == null || restrictionLayer.QueryTools.GetFeaturesIntersecting(cell.BoundingBox, ReturningColumnsType.NoColumns).Count > 0) { // If the tile exists, do nothing. String tileImageFileName = tileCache.GetTileImageFileName(cell.Row, cell.Column); bool isTileExisting = File.Exists(tileImageFileName); if (!isTileExisting) { Bitmap cellBitmap = GetCellFromBitmap(bitmap, bitmapExtent, cell.BoundingBox, tileWidth, tileHeight); BitmapTile savingBitmapTile = new BitmapTile(cellBitmap, cell.BoundingBox, tileCache.TileMatrix.Scale); if (watermarkBitmap != null && savingBitmapTile != null) { using (Graphics graphics = Graphics.FromImage(savingBitmapTile.Bitmap)) { graphics.DrawImageUnscaled(watermarkBitmap, 0, 0); } } tileCache.SaveTile(savingBitmapTile); cellBitmap.Dispose(); savingBitmapTile.Dispose(); } lock (this) { currentTileIndex++; int percentage = (int)(currentTileIndex * 100 / totalTilesCount); if (percentage > 100) { percentage = 100; } OnProgressChanged(new CacheGeneratorProgressChangedEventArgs(percentage, null, currentTileIndex, totalTilesCount)); } } } } } public Bitmap GetCellFromBitmap(Bitmap sourceBitmap, RectangleShape sourceExtent, RectangleShape cellExtent, int tileWidth, int tileHeight) { Bitmap cellBitmap = null; if (sourceBitmap != null) { Graphics graphics = null; try { ScreenPointF upperLeftPoint = ExtentHelper.ToScreenCoordinate(sourceExtent, cellExtent.UpperLeftPoint, Convert.ToSingle(sourceBitmap.Width), Convert.ToSingle(sourceBitmap.Height)); cellBitmap = new Bitmap(tileWidth, tileHeight); graphics = Graphics.FromImage(cellBitmap); graphics.DrawImageUnscaled(sourceBitmap, -(int)Math.Round(upperLeftPoint.X), -(int)Math.Round(upperLeftPoint.Y)); } finally { if (graphics != null) { graphics.Dispose(); } } } return cellBitmap; } public long GetTilesCount() { long tilesCount = 0; Collection<long> cells = GetTilesCountsForScales(); foreach (long cellCount in cells) { tilesCount += cellCount; } return tilesCount; } public Collection<long> GetTilesCountsForScales() { if (!string.IsNullOrEmpty(restrictShapeFilePathName)) { restrictionLayer = new ShapeFileFeatureLayer(restrictShapeFilePathName, ShapeFileReadWriteMode.ReadOnly); restrictionLayer.Open(); } Collection<long> cells = new Collection<long>(); foreach (double scale in scales) { MapSuiteTileMatrix tileMatrix = new MapSuiteTileMatrix(scale, tileWidth, tileHeight, mapUnit); RowColumnRange rowColumnRange = tileMatrix.GetIntersectingRowColumnRange(cachingExtent); long deltaColumn = rowColumnRange.MaxColumnIndex - rowColumnRange.MinColumnIndex + 1; long deltaRow = rowColumnRange.MaxRowIndex - rowColumnRange.MinRowIndex + 1; long cellsCountUnderScale = deltaColumn * deltaRow; if (restrictionLayer != null) { Collection<Feature> features = restrictionLayer.QueryTools.GetFeaturesInsideBoundingBox(cachingExtent, ReturningColumnsType.NoColumns); double totalArea = cachingExtent.Width * cachingExtent.Height; double area = 0; foreach (Feature feature in features) { // Use the same unit here (Meter and SquarMeter) to just make the calculation easy. area += ((AreaBaseShape)feature.GetShape()).GetIntersection(cachingExtent).GetArea(GeographyUnit.Meter, AreaUnit.SquareMeters); } cellsCountUnderScale = (long)Math.Ceiling(cellsCountUnderScale * area / totalArea); } cells.Add(cellsCountUnderScale); } return cells; } public void Close() { if (workingThreads != null) { foreach (Thread workingThread in workingThreads) { if (workingThread != null && workingThread.IsAlive) { workingThread.Abort(); } } } if (layersToCache != null) { foreach (Layer layer in layersToCache) { if (layer.IsOpen) { layer.Close(); } } } if (restrictionLayer != null && restrictionLayer.IsOpen) { restrictionLayer.Close(); } } protected virtual void OnProgressChanged(CacheGeneratorProgressChangedEventArgs e) { EventHandler<CacheGeneratorProgressChangedEventArgs> handler = ProgressChanged; if (handler != null) { handler(this, e); } } protected virtual void OnGenerationCompleted(EventArgs e) { EventHandler<EventArgs> handler = GenerationCompleted; if (handler != null) { handler(this, e); } } private Bitmap GetWatermarkBitmap() { if (watermarkBitmap == null) { return null; } Bitmap clonedWatermarkBitmap = null; lock (watermarkBitmap) { clonedWatermarkBitmap = (Bitmap)watermarkBitmap.Clone(); } return clonedWatermarkBitmap; } private ShapeFileFeatureLayer GetRestrictionLayer() { if (restrictionLayer == null) { return null; } ShapeFileFeatureLayer clonedRestrictionLayer = new ShapeFileFeatureLayer(restrictionLayer.ShapePathFileName, ShapeFileReadWriteMode.ReadOnly); clonedRestrictionLayer.Open(); return clonedRestrictionLayer; } } }