Source Code ServicesEditionSample CacheGenerator CS 120619.zip
CacheGeneratorProgressChangedEventArgs.cs
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;
}
}
}
CreatingCellsArgument.cs
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;
}
}
}
CreatingTilesArgument.cs
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; }
}
}
}
LayerProvider.cs
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;
}
}
}
MainForm.cs
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;
}
}
}
Program.cs
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());
}
}
}
TileCacheGenerator.cs
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;
}
}
}