年度变更建库软件5.0版本
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1603 lines
59 KiB

4 months ago
using OSGeo.GDAL;
using OSGeo.OGR;
using OSGeo.OSR;
using System;
using System.Collections.Generic;
using System.Data.SQLite;
using System.Drawing;
using System.Drawing.Imaging;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace Kingo.Plugin.RasterToKOTilesApp.KoDataBase
{
public class RasterInfo : IDisposable
{
public string Projection { get; private set; }
public Dataset Dataset { get; private set; }
public int XSize { get; set; }
public int YSize { get; set; }
public double TransScale { get; set; }
public Envelope Extent { get; set; }
public double[] Geotransform { get; private set; }
public int Bands { get; private set; }
private RasterInfo() { }
public static RasterInfo Create(string fileName)
{
try
{
//消除中文路径无法识别的问题
OSGeo.GDAL.Gdal.SetConfigOption("GDAL_FILENAME_IS_UTF8", "YES");
Dataset dataset = Gdal.Open(fileName, Access.GA_ReadOnly);
return Create(dataset);
}
catch (Exception ex)
{
return null;
}
}
public static RasterInfo Create(Dataset dataset)
{
RasterInfo pRasterInfo = new RasterInfo();
pRasterInfo.Dataset = dataset;
pRasterInfo.XSize = pRasterInfo.Dataset.RasterXSize;
pRasterInfo.YSize = pRasterInfo.Dataset.RasterYSize;
pRasterInfo.Geotransform = new double[6];
pRasterInfo.Dataset.GetGeoTransform(pRasterInfo.Geotransform);
double north = pRasterInfo.Geotransform[3];
double south = pRasterInfo.Geotransform[3] + pRasterInfo.Geotransform[5] * pRasterInfo.YSize;
double east = pRasterInfo.Geotransform[0] + pRasterInfo.Geotransform[1] * pRasterInfo.XSize;
double west = pRasterInfo.Geotransform[0];
if (Math.Round(pRasterInfo.Geotransform[1] + pRasterInfo.Geotransform[5], 1) != 0)
throw new Exception("栅格对象被压缩");
pRasterInfo.TransScale = pRasterInfo.Geotransform[1];
pRasterInfo.Bands = pRasterInfo.Dataset.RasterCount;
//this.ScaleY = geotransform[5];
pRasterInfo.Projection = pRasterInfo.Dataset.GetProjection();
pRasterInfo.Extent = new Envelope()
{
XMax = east,
XMin = west,
YMax = north,
YMin = south
};
return pRasterInfo;
}
public void Dispose()
{
Dataset.Dispose();
}
}
public delegate List<TileInfo> CompareTileInfo(List<TileInfo> tileInfos);
public class MultRaster2MBTiles
{
static MultRaster2MBTiles()
{
}
public ImageFormat ImgFormat { get; set; }
public int Level { get; set; }
public Layer TopLayer { get; set; }
private List<RasterInfo> Rasters = new List<RasterInfo>();
private Dataset topRasterDs = null;
private RasterInfo topRaster = null;
public int CompressRate { get; set; } = 25;
/// <summary>
/// 相交
/// </summary>
public event CompareTileInfo CompareIntersect = null;
public EnumSaveType SaveType { get; set; }
public void Dispose()
{
if (topRasterDs != null)
topRasterDs.Dispose();
if (topRaster != null)
topRaster.Dispose();
}
public MultRaster2MBTiles()
{
//Rasters = new List<RasterInfo>();
//codecInfo = GetEncoder(ImageFormat.Png);
//System.Drawing.Imaging.Encoder myEncoder = System.Drawing.Imaging.Encoder.Quality;
//EncoderParameters myEncoderParameters = new EncoderParameters(1);
//EncoderParameter myEncoderParameter = new EncoderParameter(myEncoder,8);
//myEncoderParameters.Param[0] = myEncoderParameter;
//encoderParameters = myEncoderParameters;
ImgFormat = ImageFormat.Jpeg;
}
private Envelope rasterExtent;
public int TiledSize { get; set; }
public string MBTilesPath { get; set; }
private List<TileInfo> GetAllTiles(Envelope extent, Envelope envelopeCut = null)
{
List<TileInfo> tiles = new List<TileInfo>();
double originX = extent.XMin;
double originY = extent.YMax;
for (int level = 0; level < Level; level++)
{
int count = (int)Math.Pow(2, level);
double del = extent.Width / count;
for (int col = 0; col < count; col++)
{
for (int row = 0; row < count; row++)
{
double minx = originX + col * del;
double maxy = originY - row * del;
Envelope e = new Envelope()
{
XMin = minx,
YMin = maxy - del,
XMax = minx + del,
YMax = maxy
};
if (envelopeCut != null)
{
if (!e.Intersects(envelopeCut)) continue;
}
tiles.Add(new TileInfo(e, level, row, col));
}
}
}
return tiles;
}
public static Rectangle Envelope2Rect(RasterInfo rasterInfo, Envelope extent)
{
//int width = (int)((extent.XMax - extent.XMin) / rasterInfo.TransScale + 0.5);
//int height = (int)((extent.YMax - extent.YMin) / rasterInfo.TransScale + 0.5);
//int x = (int)((rasterInfo.Extent.XMax - extent.XMax) / rasterInfo.TransScale + 0.5);
//int y = (int)((rasterInfo.Extent.YMax - extent.YMax) / rasterInfo.TransScale + 0.5);
//return new Rectangle(x, y, width, height);
Rectangle rect = Envelope2Rect(rasterInfo.Extent, extent, rasterInfo.TransScale);
if (rect.Right > rasterInfo.XSize)
{
rect.Width -= rect.Right - rasterInfo.XSize;
}
if (rect.Bottom > rasterInfo.YSize)
{
rect.Height -= rect.Bottom - rasterInfo.YSize;
}
return rect;
}
public static Rectangle Envelope2Rect(Envelope baseExtent, Envelope extent, double resolution)
{
int width = (int)((extent.XMax - extent.XMin) / resolution + 0.5);
int height = (int)((extent.YMax - extent.YMin) / resolution + 0.5);
int x = (int)((extent.XMin - baseExtent.XMin) / resolution + 0.5);
int y = (int)((baseExtent.YMax - extent.YMax) / resolution + 0.5);
return new Rectangle(x, y, width, height);
}
private Envelope GetExtent()
{
return GetExtent(this.Rasters);
}
private static Envelope GetExtent(List<RasterInfo> rasters)
{
Envelope extent = rasters[0].Extent; ;
for (int i = 1; i < rasters.Count; i++)
{
extent = extent.Union(rasters[i].Extent);
}
return extent;
}
private static Envelope GetExtentZ(Envelope e)
{
Envelope extent = new Envelope()
{
XMax = e.XMax,
XMin = e.XMin,
YMax = e.YMax,
YMin = e.YMin
};
double del = (extent.Width - extent.Height) / 2;
if (del > 0)
{
extent.YMax += del;
extent.YMin -= del;
}
else
{
extent.XMax -= del;
extent.XMin += del;
}
return extent;
}
private Envelope maxExtent = null;
private string EnCode(object value)
{
if (value == null)
return "";
string str = value.ToString();
return str;
if (string.IsNullOrEmpty(str))
return "";
string outStr = "";
foreach (char item in str)
{
outStr += (char)(item + 22);
}
return outStr;
}
//多线程去切
private List<ReadRaster> readRasterList = new List<ReadRaster>();
private WriteDatabase pWriteDatabase = null;
public void CreateMulFilesKOTiles(List<string> files, int threadnumber, bool converWebMercator, SpatialReference spatialReference, Envelope envelopeCut = null)
{
foreach (var fileName in files)
{
try
{
RasterInfo raster = RasterInfo.Create(fileName);
if (converWebMercator == true)
{
if (spatialReference != null)
{
Dataset mercatorDataSet = GdalWarp(fileName, spatialReference);
if (mercatorDataSet != null)
raster = RasterInfo.Create(mercatorDataSet);
}
}
if (raster != null)
Rasters.Add(raster);
}
catch (Exception ex)
{
Console.WriteLine("获取影像信息失败:" + ex.Message);
};
}
//创建遮罩层
if (TopLayer != null)
CreateLayer();
//计算全部图层的最小外接正方形
this.rasterExtent = GetExtent();
maxExtent = GetExtentZ(rasterExtent);
//开始切片,获取范围内的瓦片
//根据层级开始计算网格个数
List<TileInfo> allTiles = GetAllTiles(maxExtent, envelopeCut);
List<List<TileInfo>> tileGroups = new List<List<TileInfo>>();
int start = 0;
int count = allTiles.Count / threadnumber;
if (topRasterDs != null)
topRaster = RasterInfo.Create(topRasterDs);
pWriteDatabase = new WriteDatabase();
for (int i = 0; i < threadnumber; i++)
{
if (i == threadnumber - 1)
{
count += allTiles.Count % threadnumber;
}
List<TileInfo> tileGroup = allTiles.GetRange(start, count);
start += count;
ReadRaster pReadRaster = new ReadRaster()
{
ImgFormat = ImgFormat,
TiledSize = TiledSize,
TileInfos = tileGroup,
TopRasterInfo = topRaster,
CompressRate = this.CompressRate,
Rasters = Rasters
};
pReadRaster.Dowork();
pReadRaster.Event2 += (d, e) => {
pWriteDatabase.InsertDataRange(d as TileInfo[]);
};
readRasterList.Add(pReadRaster);
}
SQLiteConnection conn = null;
if (SaveType == EnumSaveType.Level)
conn = CreateDataBase();
else if (SaveType == EnumSaveType.Resolution)
conn = CreateBestDataBase();
pWriteDatabase.Conn = conn;
pWriteDatabase.TileCount = allTiles.Count;
pWriteDatabase.Done += (s, e) =>
{
if (topRaster != null)
topRaster.Dispose();
if (topRasterDs != null)
{
topRasterDs.Dispose();
topRasterDs = null;
}
if (TopLayer != null)
{
TopLayer.Dispose();
TopLayer = null;
}
this.CreatDown(s, e);
};
pWriteDatabase.Report += (s, e) =>
{
if (Report != null)
{
Report(s, e);
}
};
if (SaveType == EnumSaveType.Level)
{
pWriteDatabase.DoWorkLevel();
}
else if (SaveType == EnumSaveType.Resolution)
{
pWriteDatabase.BestDoWork();
}
}
public void CreateMulFilesKOTiles(List<string> files, int threadnumber, bool converWebMercator, Envelope envelopeCut = null)
{
foreach (string file in files)
{
try
{
RasterInfo rasterInfo = RasterInfo.Create(file);
if (converWebMercator)
{
SpatialReference spatialReference = new SpatialReference("");
spatialReference.ImportFromEPSG(3857);
Dataset dataset = GdalWarp(file, spatialReference);
if (dataset != null)
{
rasterInfo = RasterInfo.Create(dataset);
}
}
if (rasterInfo != null)
{
Rasters.Add(rasterInfo);
}
}
catch
{
}
}
if (TopLayer != null)
{
CreateLayer();
}
rasterExtent = GetExtent();
maxExtent = GetExtentZ(rasterExtent);
List<TileInfo> allTiles = GetAllTiles(maxExtent, envelopeCut);
List<List<TileInfo>> list = new List<List<TileInfo>>();
int num = 0;
int num2 = allTiles.Count / threadnumber;
if (topRasterDs != null)
{
topRaster = RasterInfo.Create(topRasterDs);
}
pWriteDatabase = new WriteDatabase();
for (int i = 0; i < threadnumber; i++)
{
if (i == threadnumber - 1)
{
num2 += allTiles.Count % threadnumber;
}
List<TileInfo> range = allTiles.GetRange(num, num2);
num += num2;
ReadRaster readRaster = new ReadRaster(files, converWebMercator)
{
ImgFormat = ImgFormat,
TiledSize = TiledSize,
TileInfos = range,
TopRasterInfo = topRaster,
CompressRate = CompressRate
};
readRaster.Dowork();
readRaster.Event2 += delegate (object d, EventArgs e)
{
pWriteDatabase.InsertDataRange(d as TileInfo[]);
};
readRasterList.Add(readRaster);
}
SQLiteConnection conn = null;
if (SaveType == EnumSaveType.Level)
{
conn = CreateDataBase();
}
else if (SaveType == EnumSaveType.Resolution)
{
conn = CreateBestDataBase();
}
pWriteDatabase.Conn = conn;
pWriteDatabase.TileCount = allTiles.Count;
pWriteDatabase.Done += delegate (object s, EventArgs e)
{
if (topRaster != null)
{
topRaster.Dispose();
}
if (topRasterDs != null)
{
topRasterDs.Dispose();
topRasterDs = null;
}
if (TopLayer != null)
{
TopLayer.Dispose();
TopLayer = null;
}
this.CreatDown(s, e);
};
pWriteDatabase.Report += delegate (int s, int e)
{
if (this.Report != null)
{
this.Report(s, e);
}
};
if (SaveType == EnumSaveType.Level)
{
pWriteDatabase.DoWorkLevel();
}
else if (SaveType == EnumSaveType.Resolution)
{
pWriteDatabase.BestDoWork();
}
}
public static Dataset GdalWarp(string inputFile, SpatialReference tileSpatialReference)
{
Dataset inputDataset = Gdal.OpenShared(inputFile, Access.GA_ReadOnly);
OSGeo.OSR.SpatialReference sSpatialReference = inputDataset.GetSpatialRef();
if (sSpatialReference.IsSame(tileSpatialReference, null) > 0)
{
return inputDataset;
}
try
{
string tempFolder = System.IO.Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Temp");
if (!Directory.Exists(tempFolder))
{
Directory.CreateDirectory(tempFolder);
}
string outputFile = System.IO.Path.Combine(tempFolder, Guid.NewGuid().ToString().Replace("-", "") + ".VRT");
tileSpatialReference.ExportToWkt(out string wkt, null);
string[] options = new string[] { "-t_srs", wkt, "-r", "rms", "-of", "VRT" };
Gdal.GDALProgressFuncDelegate progressFuncDelegate = new Gdal.GDALProgressFuncDelegate((complete, msg, data) =>
{
if (complete >= 1)
{
//isProgressCompleted = true;
}
return 1;
});
return Gdal.Warp(outputFile, new Dataset[] { inputDataset }, new GDALWarpAppOptions(options), progressFuncDelegate, null);
}
finally
{
inputDataset.Dispose();
}
}
private SQLiteConnection CreateDataBase()
{
string connString = "Data Source=" + this.MBTilesPath;
if (File.Exists(this.MBTilesPath))
{
GC.Collect();
System.Windows.Forms.Application.DoEvents();
try
{
File.Delete(this.MBTilesPath);
}
catch (Exception ex)
{
Console.WriteLine("输出文件监测到被占用,请重试!" + ex.Message);
}
}
string dir = Path.GetDirectoryName(this.MBTilesPath);
if (!Directory.Exists(dir))
{
Directory.CreateDirectory(dir);
}
try
{
File.WriteAllBytes(this.MBTilesPath, Properties.Resources.Template);
}
catch (Exception ex)
{
Console.WriteLine("创建数据库失败:" + ex.Message);
}
System.Data.SQLite.SQLiteConnection conn = new System.Data.SQLite.SQLiteConnection(connString);
conn.Open();
try
{
SQLiteTransaction pTan = conn.BeginTransaction();
SQLiteCommand cmd = new SQLiteCommand(conn);
string sqlFormat = "insert into metadata values('{0}','{1}')";
//写入图片大小
cmd.CommandText = string.Format(sqlFormat, "Size", EnCode(this.TiledSize));
int result= cmd.ExecuteNonQuery();
//写入图片格式
cmd.CommandText = string.Format(sqlFormat, "Format", EnCode(ImgFormat.ToString()));
result=cmd.ExecuteNonQuery();
//写入空间参考
cmd.CommandText = string.Format(sqlFormat, "Projection", EnCode(this.Rasters[0].Dataset.GetProjection()));
result = cmd.ExecuteNonQuery();
//写入Extend
cmd.CommandText = string.Format(sqlFormat, "Bounds",
EnCode(string.Format("{0},{1},{2},{3}", this.rasterExtent.XMin, rasterExtent.YMin, rasterExtent.XMax, rasterExtent.YMax)));
result = cmd.ExecuteNonQuery();
//写入origin
cmd.CommandText = string.Format(sqlFormat, "Origin",
EnCode(string.Format("{0},{1}", maxExtent.XMin, maxExtent.YMax)));
result = cmd.ExecuteNonQuery();
//写入分辨率
double dbResolution = maxExtent.Width / this.TiledSize;
cmd.CommandText = string.Format(sqlFormat, "Resolution", EnCode(dbResolution));
result = cmd.ExecuteNonQuery();
//写入比例尺
double dbScale = (96 / 0.0254) * dbResolution;
cmd.CommandText = string.Format(sqlFormat, "Scale", EnCode(dbScale));
result = cmd.ExecuteNonQuery();
//写入Level
cmd.CommandText = string.Format(sqlFormat, "Level", EnCode(this.Level));
result = cmd.ExecuteNonQuery();
//写入Kingo
cmd.CommandText = string.Format(sqlFormat, "Kingo", "false");
cmd.ExecuteNonQuery();
cmd.Dispose();
pTan.Commit();
pTan.Dispose();
}
catch (Exception ex)
{
Console.WriteLine("写入metadata表数据失败:" + ex.Message);
}
finally
{
conn.Close();
GC.Collect();
}
return conn;
}
public event EventHandler CreatDown;
public event ProgressReport Report;
private void CreateLayer()
{
// 注册所有的驱动
// Ogr.RegisterAll();
//Gdal.AllRegister();
//消除中文路径无法识别的问题
OSGeo.GDAL.Gdal.SetConfigOption("GDAL_FILENAME_IS_UTF8", "YES");
//解决shape文件字段中文内容读取问题
OSGeo.GDAL.Gdal.SetConfigOption("SHAPE_ENCODING", "UTF-8");
//获取transform
Envelope maxEnvelope = GetExtent(this.Rasters);
int[] rasterSize = GetRasterSize(maxEnvelope);
double[] geoTransform = GetGeoTransform(maxEnvelope, rasterSize[0], rasterSize[1]);
Layer layer = TopLayer;
topRasterDs = null;
string tempFile = Application.StartupPath + "\\temp.img";
if (File.Exists(tempFile))
File.Delete(tempFile);
OSGeo.GDAL.Driver dirver = Gdal.GetDriverByName("HFA");//MEM HFA GTiff
topRasterDs = dirver.Create(tempFile, rasterSize[0], rasterSize[1], 1, DataType.GDT_Byte, null);
topRasterDs.SetProjection(this.Rasters[0].Projection);
topRasterDs.SetGeoTransform(geoTransform);
Gdal.GDALProgressFuncDelegate callback = new Gdal.GDALProgressFuncDelegate(GDALProgressFuncDelegate);
try
{
int rst = Gdal.RasterizeLayer(topRasterDs, 1, new int[] { 1 }, layer, IntPtr.Zero, IntPtr.Zero, 1, new double[] { 255 }, new string[] { "ALL_TOUCHED=TRUE" }, callback, "callback");
}
catch (Exception ex)
{
}
}
private double[] GetGeoTransform(Envelope envelope, int x, int y)
{
double[] geoTransform = new double[6];
geoTransform[0] = envelope.XMin;
geoTransform[1] = envelope.Width / x;
geoTransform[2] = 0;
geoTransform[3] = envelope.YMax;
geoTransform[4] = 0;
geoTransform[5] = -envelope.Height / y;
return geoTransform;
}
private int[] GetRasterSize(Envelope envelope)
{
int[] rasterSize = new int[2];
rasterSize[0] = (int)(envelope.Width / 10);
rasterSize[1] = (int)(envelope.Height / 10);
return rasterSize;
}
bool isComplete = false;
private int GDALProgressFuncDelegate(double Complete, IntPtr Message, IntPtr Data)
{
if (Complete >= 1)
{
isComplete = true;
}
return 1;
}
#region 裁取图斑最高分辨率 2015-11-11 chendewen
private SQLiteConnection CreateBestDataBase()
{
string connString = "Data Source=" + this.MBTilesPath;
if (File.Exists(this.MBTilesPath))
{
GC.Collect();
System.Windows.Forms.Application.DoEvents();
try
{
File.Delete(this.MBTilesPath);
}
catch (Exception ex)
{
throw new Exception("输出文件监测到被占用,请重试!");
}
}
string dir = Path.GetDirectoryName(this.MBTilesPath);
if (!Directory.Exists(dir))
{
Directory.CreateDirectory(dir);
}
File.WriteAllBytes(this.MBTilesPath, Properties.Resources.model);
System.Data.SQLite.SQLiteConnection conn = new System.Data.SQLite.SQLiteConnection(connString);
return conn;
}
#endregion
}
public class TileInfo
{
public Envelope Bound { get; private set; }
public int Level { get; private set; }
public int Row { get; private set; }
public int Column { get; private set; }
public byte[] Data { get; set; }
public double Resolution { get; set; }
public TileInfo(Envelope bound, int level, int row, int col)
{
this.Bound = bound;
this.Level = level;
this.Row = row;
this.Column = col;
}
}
internal class ReadRaster : IDisposable
{
public ImageFormat ImgFormat { get; set; }
public int TiledSize { get; set; }
public List<RasterInfo> Rasters { get; set; }
public List<TileInfo> TileInfos { get; set; }
public int CompressRate { get; set; } = 25;
public ReadRaster()
{
}
public RasterInfo TopRasterInfo { get; set; }
public ReadRaster(List<string> files, bool converWebMercator)
{
Rasters = new List<RasterInfo>();
foreach (var fileName in files)
{
try
{
RasterInfo raster = RasterInfo.Create(fileName);
if (converWebMercator == true)
{
SpatialReference spatialReference = new SpatialReference("");
spatialReference.ImportFromEPSG(3857);
Dataset mercatorDataSet = GdalWarp(fileName, spatialReference);
if (mercatorDataSet != null)
raster = RasterInfo.Create(mercatorDataSet);
}
if (raster != null)
Rasters.Add(raster);
}
catch { };
}
}
private static Dataset GdalWarp(string inputFile, SpatialReference tileSpatialReference)
{
Dataset inputDataset = Gdal.OpenShared(inputFile, Access.GA_ReadOnly);
OSGeo.OSR.SpatialReference sSpatialReference = inputDataset.GetSpatialRef();
if (sSpatialReference.IsSame(tileSpatialReference, null) > 0)
{
return inputDataset;
}
try
{
string tempFolder = System.IO.Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Temp");
if (!Directory.Exists(tempFolder))
{
Directory.CreateDirectory(tempFolder);
}
string outputFile = System.IO.Path.Combine(tempFolder, Guid.NewGuid().ToString().Replace("-", "") + ".VRT");
tileSpatialReference.ExportToWkt(out string wkt, null);
string[] options = new string[] { "-t_srs", wkt, "-r", "rms", "-of", "VRT" };
Gdal.GDALProgressFuncDelegate progressFuncDelegate = new Gdal.GDALProgressFuncDelegate((complete, msg, data) =>
{
if (complete >= 1)
{
//isProgressCompleted = true;
}
return 1;
});
return Gdal.Warp(outputFile, new Dataset[] { inputDataset }, new GDALWarpAppOptions(options), progressFuncDelegate, null);
}
finally
{
inputDataset.Dispose();
}
}
//创建单个瓦片
private void CreateKOTiles(TileInfo tile)
{
try
{
byte[] bgra = new byte[TiledSize * TiledSize * 4];
double resolution = tile.Bound.Width / this.TiledSize;
bool isExist = false;
byte[] rgbTop = null;
Rectangle dTopRect = new Rectangle();
if (TopRasterInfo != null)
{
Envelope topEnvelope = tile.Bound.Intersection(TopRasterInfo.Extent);
if (topEnvelope != null)
{
try
{
Rectangle sTopRect = MultRaster2MBTiles.Envelope2Rect(TopRasterInfo, topEnvelope);
dTopRect = MultRaster2MBTiles.Envelope2Rect(tile.Bound, topEnvelope, resolution);
rgbTop = new byte[dTopRect.Width * dTopRect.Height];
CPLErr err = TopRasterInfo.Dataset.GetRasterBand(1).ReadRaster(sTopRect.X, sTopRect.Y, sTopRect.Width, sTopRect.Height, rgbTop, dTopRect.Width, dTopRect.Height, 0, 0);
if (err != CPLErr.CE_None)
{
Console.WriteLine(string.Format("读取Level:{0},Column:{1},Row:{2}的瓦片出错!", tile.Level, tile.Column, tile.Row));
}
}
catch (Exception ex)
{
//Console.WriteLine(string.Format("读取Level:{0},Column:{1},Row:{2}的瓦片出错!", tile.Level, tile.Column, tile.Row));
}
//填充数据到bgra
for (int i = 0; i < dTopRect.Width; i++)
{
for (int j = 0; j < dTopRect.Height; j++)
{
try
{
int offset = i + j * dTopRect.Width;
byte rVal = rgbTop[offset];
if (rVal > 250)
{
isExist = true;
break;
}
}
catch (Exception ex)
{
Console.WriteLine("填充数据到bgra失败:" + ex.Message);
}
}
}
}
//没有数据
if (!isExist)
return;
}
foreach (var raster in Rasters)
{
Envelope pEnvelope = tile.Bound.Intersection(raster.Extent);
if (pEnvelope == null)
continue;
Rectangle sRect = MultRaster2MBTiles.Envelope2Rect(raster, pEnvelope);
Rectangle dRect = MultRaster2MBTiles.Envelope2Rect(tile.Bound, pEnvelope, resolution);
if (raster.Bands > 2)
{
byte[] rgb = new byte[dRect.Width * dRect.Height * 3];
try
{
CPLErr err = raster.Dataset.ReadRaster(sRect.X, sRect.Y, sRect.Width, sRect.Height, rgb, dRect.Width, dRect.Height, 3, new int[] { 1, 2, 3 }, 0, 0, 0);
if (err != CPLErr.CE_None)
{
Console.WriteLine(string.Format("读取Level:{0},Column:{1},Row:{2}的瓦片出错!", tile.Level, tile.Column, tile.Row));
}
}
catch (Exception ex)
{
}
//填充数据到bgra
for (int i = 0; i < dRect.Width; i++)
{
for (int j = 0; j < dRect.Height; j++)
{
try
{
int offset = i + j * dRect.Width;
byte rVal = rgb[offset];
byte gVal = rgb[offset + dRect.Width * dRect.Height];
byte bVal = rgb[offset + dRect.Width * dRect.Height * 2];
if ((rVal == 0 && gVal == 0 && bVal == 0) || (rVal == 255 && gVal == 255 && bVal == 255))
{
continue;
}
int pixelPos = (dRect.X + i) + (dRect.Y + j) * this.TiledSize;
bgra[pixelPos * 4] = bVal;
bgra[pixelPos * 4 + 1] = gVal;
bgra[pixelPos * 4 + 2] = rVal;
bgra[pixelPos * 4 + 3] = 255;
}
catch (Exception ex)
{
Console.WriteLine("填充数据到bgra失败:" +ex.Message);
}
}
}
}
else
{
byte[] r = new byte[dRect.Width * dRect.Height];
try
{
CPLErr err = raster.Dataset.GetRasterBand(1).ReadRaster(sRect.X, sRect.Y, sRect.Width, sRect.Height, r, dRect.Width, dRect.Height, 0, 0);
if (err != CPLErr.CE_None)
{
Console.WriteLine(string.Format("读取Level:{0},Column:{1},Row:{2}的瓦片出错!", tile.Level, tile.Column, tile.Row));
}
}
catch (Exception ex)
{
}
//填充数据到bgra
for (int i = 0; i < dRect.Width; i++)
{
for (int j = 0; j < dRect.Height; j++)
{
try
{
int offset = i + j * dRect.Width;
byte rVal = r[offset];
if (rVal < 5)
continue;
int pixelPos = (dRect.X + i) + (dRect.Y + j) * this.TiledSize;
bgra[pixelPos * 4] = rVal;
bgra[pixelPos * 4 + 1] = rVal;
bgra[pixelPos * 4 + 2] = rVal;
bgra[pixelPos * 4 + 3] = 255;
}
catch (Exception ex)
{
Console.WriteLine("填充数据到bgra失败:" + ex.Message);
}
}
}
}
}
if (rgbTop != null)
{
//填充数据到bgra
for (int i = 0; i < dTopRect.Width; i++)
{
for (int j = 0; j < dTopRect.Height; j++)
{
try
{
int offset = i + j * dTopRect.Width;
byte rVal = rgbTop[offset];
if (rVal > 250)
{
continue;
}
int pixelPos = (dTopRect.X + i) + (dTopRect.Y + j) * this.TiledSize;
bgra[pixelPos * 4] = 255;
bgra[pixelPos * 4 + 1] = 255;
bgra[pixelPos * 4 + 2] = 255;
bgra[pixelPos * 4 + 3] = 0;
}
catch (Exception ex)
{
Console.WriteLine("填充数据到bgra失败:" + ex.Message);
}
}
}
}
int dataHasValue = 0;
for (int i = 0; i < TiledSize * TiledSize; i++)
{
if (bgra[i * 4 + 3] != 0)
{
dataHasValue++;
}
}
//没有数据
if (dataHasValue < 1)
return;
//写入数据文件
using (MemoryStream ms = new MemoryStream())
{
Bitmap bitmap = new Bitmap(TiledSize, TiledSize, System.Drawing.Imaging.PixelFormat.Format32bppArgb);
try
{
BitmapData bitmapData = bitmap.LockBits(new Rectangle(0, 0, bitmap.Width, bitmap.Height), System.Drawing.Imaging.ImageLockMode.ReadWrite, System.Drawing.Imaging.PixelFormat.Format32bppArgb);
try
{
Marshal.Copy(bgra, 0, bitmapData.Scan0, bgra.Length);
}
catch (Exception ex)
{
Console.WriteLine("拷贝bgra失败:" + ex.Message);
}
finally
{
bitmap.UnlockBits(bitmapData);
}
if (ImageFormat.Jpeg.Equals(ImgFormat) || dataHasValue > this.TiledSize * (this.TiledSize - 1))
{
EncoderParameter p;
EncoderParameters ps;
ps = new EncoderParameters(1);
p = new EncoderParameter(System.Drawing.Imaging.Encoder.Quality, (long)this.CompressRate);
ps.Param[0] = p;
ImageCodecInfo pngEncoder = GetEncoder(ImageFormat.Jpeg);
bitmap.Save(ms, pngEncoder, ps);
}
else
{
string path = AppDomain.CurrentDomain.BaseDirectory + @"pngquant\pngquant.exe";
if (File.Exists(path))
{
PngQuant.Run(bitmap, ms, path);
}
else
{
bitmap.Save(ms, ImageFormat.Png);
}
}
}
catch (Exception ex)
{
Console.WriteLine("写入数据文件失败:" + ex.Message);
}
finally
{
bitmap.Dispose();
}
tile.Data = ms.ToArray();
tile.Resolution = resolution;
}
}
catch (Exception ex)
{
Console.WriteLine("创建单个瓦片失败:" + ex.Message);
}
}
bool isY = false;
private ImageCodecInfo GetEncoder(ImageFormat format)
{
ImageCodecInfo[] codecs = ImageCodecInfo.GetImageDecoders();
foreach (ImageCodecInfo codec in codecs)
{
if (codec.FormatID == format.Guid)
{
return codec;
}
}
return null;
}
private Thread doThread;
public event EventHandler Event2;
public void Dowork()
{
doThread = new Thread(new ThreadStart(read));
doThread.IsBackground = true;
doThread.Name = "读取图片线程" + Guid.NewGuid().ToString();
doThread.Priority = ThreadPriority.Highest;
doThread.Start();
}
private List<TileInfo> doneList = new List<TileInfo>();
public void read()
{
foreach (var item in TileInfos)
{
try
{
CreateKOTiles(item);
}
catch (Exception ex)
{
Console.WriteLine("读取图片线程异常" + ex.Message);
}
finally
{
doneList.Add(item);
if (doneList.Count > 20)
{
Event2?.Invoke(doneList.ToArray(), null);
doneList.Clear();
}
}
}
if (doneList.Count > 0)
{
Event2?.Invoke(doneList.ToArray(), null);
doneList.Clear();
}
Console.WriteLine(doThread.Name + "结束");
}
public void Stop()
{
this.Dispose();
}
public void Dispose()
{
if (this.doThread != null)
{
try
{
this.doThread.Abort();
}
catch { }
finally
{
this.doThread = null;
}
}
}
}
public delegate void ProgressReport(int sum, int current);
internal class WriteDatabase : IDisposable
{
public event ProgressReport Report;
public SQLiteConnection Conn { get; set; }
public int TileCount { get; set; }
private List<TileInfo> needInsertDataList = new List<TileInfo>();
public void InsertDataRange(TileInfo[] data)
{
lock (needInsertDataList)
{
needInsertDataList.AddRange(data);
}
}
Thread doworkThread = null;
public event EventHandler Done;
public void Dispose()
{
if (doworkThread != null)
{
try
{
doworkThread.Abort();
}
catch
{
}
finally
{
doworkThread = null;
}
}
}
public void BestDoWork()
{
doworkThread = new Thread(new ThreadStart(WriteTodb));
doworkThread.IsBackground = true;
doworkThread.Name = "写入图片线程" + Guid.NewGuid().ToString();
doworkThread.Start();
}
private void WriteTodb()
{
Conn.Open();
try
{
SQLiteTransaction pTan = Conn.BeginTransaction();
SQLiteCommand cmd = new SQLiteCommand(Conn);
cmd.CommandText = "insert into tiles (centerX,centerY,maxX,maxY,minX,minY,resolution,tile_Data) values(@centerX,@centerY,@maxX,@maxY,@minX,@minY,@resolution,@tile_Data)";
cmd.Parameters.Add(new SQLiteParameter("@centerX", System.Data.DbType.Double));
cmd.Parameters.Add(new SQLiteParameter("@centerY", System.Data.DbType.Double));
cmd.Parameters.Add(new SQLiteParameter("@maxX", System.Data.DbType.Double));
cmd.Parameters.Add(new SQLiteParameter("@maxY", System.Data.DbType.Double));
cmd.Parameters.Add(new SQLiteParameter("@minX", System.Data.DbType.Double));
cmd.Parameters.Add(new SQLiteParameter("@minY", System.Data.DbType.Double));
cmd.Parameters.Add(new SQLiteParameter("@resolution", System.Data.DbType.Double));
cmd.Parameters.Add(new SQLiteParameter("@tile_Data", System.Data.DbType.Binary));
int dealTileCount = 0;
while (dealTileCount < TileCount)
{
TileInfo[] datas = null;
lock (needInsertDataList)
{
datas = needInsertDataList.ToArray();
needInsertDataList.Clear();
}
if (datas == null || datas.Length == 0)
{
Thread.Sleep(1000);
}
else
{
foreach (var item in datas)
{
if (item.Data == null)
continue;
cmd.Parameters[0].Value = (item.Bound.XMax - item.Bound.XMin) / 2 + item.Bound.XMin;
cmd.Parameters[1].Value = (item.Bound.YMax - item.Bound.YMin) / 2 + item.Bound.YMin;
cmd.Parameters[2].Value = item.Bound.XMax;
cmd.Parameters[3].Value = item.Bound.YMax;
cmd.Parameters[4].Value = item.Bound.XMin;
cmd.Parameters[5].Value = item.Bound.YMin;
cmd.Parameters[6].Value = item.Resolution;
cmd.Parameters[7].Value = item.Data;
cmd.ExecuteNonQuery();
item.Data = null;
}
dealTileCount += datas.Length;
if (Report != null)
{
Report(TileCount, dealTileCount);
}
}
Thread.Sleep(0);
}
cmd.CommandText = "CREATE INDEX tiles_index ON tiles (centerX,centerY,maxX,maxY,minX,minY);";
cmd.ExecuteNonQuery();
pTan.Commit();
pTan.Dispose();
if (Done != null)
{
Done(null, null);
}
}
finally
{
Conn.Close();
Conn.Dispose();
SQLiteConnection.ClearPool(Conn);
Thread.Sleep(10);
GC.Collect();
Thread.Sleep(10);
}
}
Thread doworkThreadLevel = null;
public void DoWorkLevel()
{
//doworkThreadLevel = new Thread(new ThreadStart(WriteTodbLevel));
//doworkThreadLevel.IsBackground = true;
//doworkThreadLevel.Name = "写入图片线程" + Guid.NewGuid().ToString();
//doworkThreadLevel.Start();
WriteTodbLevel();
}
private void WriteTodbLevel()
{
Conn.Open();
try
{
SQLiteTransaction pTan = Conn.BeginTransaction();
SQLiteCommand cmd = new SQLiteCommand(Conn);
cmd.CommandText = "insert into tiles (zoom_level,tile_column,tile_row,tile_data) values(@zoom_level,@tile_column,@tile_row,@tile_data)";
cmd.Parameters.Add(new SQLiteParameter("@zoom_level", System.Data.DbType.Int32));
cmd.Parameters.Add(new SQLiteParameter("@tile_column", System.Data.DbType.Int32));
cmd.Parameters.Add(new SQLiteParameter("@tile_row", System.Data.DbType.Int32));
cmd.Parameters.Add(new SQLiteParameter("@tile_data", System.Data.DbType.Binary));
int dealTileCount = 0;
while (dealTileCount < TileCount)
{
TileInfo[] datas = null;
lock (needInsertDataList)
{
datas = needInsertDataList.ToArray();
needInsertDataList.Clear();
}
if (datas == null || datas.Length == 0)
{
Thread.Sleep(1000);
}
else
{
foreach (var item in datas)
{
if (item.Data == null)
continue;
cmd.Parameters[0].Value = item.Level;
cmd.Parameters[1].Value = item.Column;
cmd.Parameters[2].Value = item.Row;
cmd.Parameters[3].Value = item.Data;
cmd.ExecuteNonQuery();
item.Data = null;
}
dealTileCount += datas.Length;
if (Report != null)
{
Report(TileCount, dealTileCount);
}
}
//Thread.Sleep(3000);
Thread.Sleep(0);
}
cmd.CommandText = "CREATE INDEX tiles_index ON tiles (zoom_level,tile_column,tile_row);";
cmd.ExecuteNonQuery();
cmd.Dispose();
pTan.Commit();
pTan.Dispose();
if (Done != null)
{
Done(null, null);
}
}
catch (Exception ex)
{
Console.WriteLine("图片写入db失败:" + ex.Message);
}
finally
{
Conn.Close();
Conn.Dispose();
SQLiteConnection.ClearPool(Conn);
Thread.Sleep(10);
GC.Collect();
Thread.Sleep(10);
}
}
}
public class UnionVector
{
public static Layer UnionVectorLayers(List<Layer> layers, double distance = 100.0)
{
Layer rstLayer = null;
Geometry rstGeometry = null;
foreach (Layer item in layers)
{
rstGeometry = UnionGeometry(rstGeometry, UnionVectorLayer(item));
}
//double distance = 100.0;
//double.TryParse(System.Configuration.ConfigurationManager.AppSettings["BufferDistance"], out distance);
if (rstGeometry == null) return null;
rstGeometry = rstGeometry.Buffer(distance, 30);
OSGeo.OGR.Driver ogrDirver = Ogr.GetDriverByName("Memory");
DataSource dsLayers = ogrDirver.CreateDataSource("", null);
rstLayer = dsLayers.CreateLayer("", null, wkbGeometryType.wkbPolygon, null);
Feature f = new Feature(rstLayer.GetLayerDefn());
f.SetGeometry(rstGeometry);
rstLayer.CreateFeature(f);
return rstLayer;
}
public static Geometry UnionVectorLayer(Layer layer)
{
Feature feature = layer.GetNextFeature();
if (feature == null) return null;
Geometry rstGeometry = feature.GetGeometryRef();
while ((feature = layer.GetNextFeature()) != null)
{
Geometry geo = feature.GetGeometryRef();
try
{
rstGeometry = rstGeometry.Union(geo);
}
catch
{
}
}
return rstGeometry;
}
public static Geometry UnionGeometry(Geometry geometry1, Geometry geometry2)
{
if (geometry1 == null)
return geometry2;
return geometry1.Union(geometry2);
}
public static Layer UnionVectorLayers(List<LayerInfo> layerPaths, double distance = 100.0)
{
//消除中文路径无法识别的问题
OSGeo.GDAL.Gdal.SetConfigOption("GDAL_FILENAME_IS_UTF8", "YES");
//解决shape文件字段中文内容读取问题
OSGeo.GDAL.Gdal.SetConfigOption("SHAPE_ENCODING", "UTF-8");
List<Layer> layers = new List<Layer>();
foreach (LayerInfo item in layerPaths)
{
DataSource dataSource = Ogr.Open(item.LayerSourcePath, 0);
if (string.IsNullOrEmpty(item.LayerName))
layers.Add(dataSource.GetLayerByIndex(0));
else
layers.Add(dataSource.GetLayerByName(item.LayerName));
}
return UnionVectorLayers(layers, distance);
}
public static Layer CreateLayer(List<Geometry> geometrys, double distance = 100.0)
{
//消除中文路径无法识别的问题
OSGeo.GDAL.Gdal.SetConfigOption("GDAL_FILENAME_IS_UTF8", "YES");
//解决shape文件字段中文内容读取问题
OSGeo.GDAL.Gdal.SetConfigOption("SHAPE_ENCODING", "UTF-8");
Geometry rstGeometry = null;
foreach (Geometry item in geometrys)
{
rstGeometry = UnionGeometry(rstGeometry, item);
}
if (rstGeometry == null) return null;
Layer rstLayer = null;
rstGeometry = rstGeometry.Buffer(distance, 30);
OSGeo.OGR.Driver ogrDirver = Ogr.GetDriverByName("Memory");
DataSource dsLayers = ogrDirver.CreateDataSource("", null);
rstLayer = dsLayers.CreateLayer("", null, wkbGeometryType.wkbPolygon, null);
Feature f = new Feature(rstLayer.GetLayerDefn());
f.SetGeometry(rstGeometry);
rstLayer.CreateFeature(f);
return rstLayer;
}
public static List<FeatureInfo> GetVectorLayerFeatures(List<LayerInfo> layerPaths)
{
//消除中文路径无法识别的问题
OSGeo.GDAL.Gdal.SetConfigOption("GDAL_FILENAME_IS_UTF8", "YES");
//解决shape文件字段中文内容读取问题
OSGeo.GDAL.Gdal.SetConfigOption("SHAPE_ENCODING", "UTF-8");
List<FeatureInfo> layers = new List<FeatureInfo>();
foreach (LayerInfo item in layerPaths)
{
DataSource dataSource = Ogr.Open(item.LayerSourcePath, 0);
Layer layer = null;
if (string.IsNullOrEmpty(item.LayerName))
{
layer = dataSource.GetLayerByIndex(0);
}
else
{
layer = dataSource.GetLayerByName(item.LayerName);
}
if (layer != null)
layers.AddRange(GetLayerFeatures(layer));
}
return layers;
}
private static List<FeatureInfo> GetLayerFeatures(Layer layer)
{
List<FeatureInfo> lst = new List<FeatureInfo>();
Feature feature = layer.GetNextFeature();
if (feature == null) return null;
int fieldNameIndex = layer.FindFieldIndex("XIJXZQMC", 0);
int fieldCodeIndex = layer.FindFieldIndex("XIJXZQDM", 0);
while ((feature = layer.GetNextFeature()) != null)
{
FeatureInfo featureInfo = new FeatureInfo();
if (fieldCodeIndex >= 0)
{
featureInfo.Code = feature.GetFieldAsString("XIJXZQDM");
}
if (fieldNameIndex >= 0)
{
featureInfo.Name = feature.GetFieldAsString("XIJXZQMC");
}
featureInfo.Shape = feature;
lst.Add(featureInfo);
}
return lst;
}
public static Layer CreateVectorLayer(FeatureInfo featureInfo)
{
Layer rstLayer = null;
OSGeo.OGR.Driver ogrDirver = Ogr.GetDriverByName("Memory");
DataSource dsLayers = ogrDirver.CreateDataSource("", null);
rstLayer = dsLayers.CreateLayer("", null, wkbGeometryType.wkbPolygon, null);
rstLayer.CreateFeature(featureInfo.Shape);
return rstLayer;
}
/// <summary>
/// 获取影像
/// </summary>
/// <param name="layerInfo"></param>
/// <param name="distance"></param>
/// <returns></returns>
public static List<TileInfo> GetTileInfosByLayer(LayerInfo layerInfo, double distance = 100.0)
{
DataSource dataSource = null;
Layer layer = null;
try
{
List<TileInfo> tileInfos = new List<TileInfo>();
dataSource = Ogr.Open(layerInfo.LayerSourcePath, 0);
if (string.IsNullOrEmpty(layerInfo.LayerName))
layer = dataSource.GetLayerByIndex(0);
else
layer = dataSource.GetLayerByName(layerInfo.LayerName);
Feature feature = null;
OSGeo.OGR.Envelope geoEnvelope = new OSGeo.OGR.Envelope();
while ((feature = layer.GetNextFeature()) != null)
{
Geometry geo = feature.GetGeometryRef();
geo = geo.Buffer(distance, 30);
geo.GetEnvelope(geoEnvelope);
if (geoEnvelope != null)
{
Envelope e = new Envelope()
{
XMin = geoEnvelope.MinX,
YMin = geoEnvelope.MinY,
XMax = geoEnvelope.MaxX,
YMax = geoEnvelope.MaxY
};
tileInfos.Add(new TileInfo(e, 0, 0, 0));
geoEnvelope.Dispose();
geoEnvelope = new OSGeo.OGR.Envelope();
}
}
return tileInfos;
}
catch (Exception ex)
{
throw ex;
}
finally
{
if (dataSource != null)
{
dataSource.Dispose();
}
if (layer != null)
{
layer.Dispose();
}
}
}
}
public class LayerInfo
{
public string LayerSourcePath { get; set; }
public string LayerName { get; set; }
public int LayerIndex { get; set; }
}
public class FeatureInfo
{
public string Name { get; set; }
public string Code { get; set; }
public Feature Shape { get; set; }
}
public enum EnumSaveType
{
Level = 0, Resolution = 1
}
}