using System; using System.Collections.Generic; using System.Text; using System.Data.SQLite; using System.Threading; namespace Kingo.Plugin.MakeTaskPackage.Entity { public delegate void ProgressReport(int sum, int current); public class WriteTilesToDataBase : IDisposable { public event ProgressReport Report; public SQLiteConnection Conn { get; set; } public int TileCount { get; set; } public int BlankImageSize { get; set; } private List needInsertDataList = new List(); public void InsertData(TileInfo data) { lock (needInsertDataList) { needInsertDataList.Add(data); } } public void InsertDataRange(TileInfo[] data) { lock (needInsertDataList) { needInsertDataList.AddRange(data); } } Thread doworkThread = null; public void DoWork() { doworkThread = new Thread(new ThreadStart(DoWork2)); doworkThread.IsBackground = true; //doworkThread.SetApartmentState(ApartmentState.STA); doworkThread.Name = "写入图片线程" + Guid.NewGuid().ToString(); //doworkThread.Priority = ThreadPriority.AboveNormal; doworkThread.Start(); } private void DoWork2() { 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) { //Console.WriteLine("Sleep"); Thread.Sleep(1000); } else { Console.WriteLine("record:" + datas.Length.ToString()); foreach (var item in datas) { if (item.Data == null || item.Data.Length == BlankImageSize)// 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(0); } cmd.CommandText = "CREATE INDEX tiles_index ON tiles (zoom_level,tile_column,tile_row);"; try { cmd.ExecuteNonQuery(); } catch { } pTan.Commit(); if (Done != null) { Done(null, null); } } finally { Conn.Close(); Conn.Dispose(); SQLiteConnection.ClearPool(Conn); Thread.Sleep(10); GC.Collect(); Thread.Sleep(10); } } public void DoWorkLevel() { doworkThread = new Thread(new ThreadStart(DoWork2Level)); doworkThread.IsBackground = true; //doworkThread.SetApartmentState(ApartmentState.STA); doworkThread.Name = "写入图片线程" + Guid.NewGuid().ToString(); //doworkThread.Priority = ThreadPriority.AboveNormal; doworkThread.Start(); } private void DoWork2Level() { 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,maxX,maxY,minX,minY,resolution) values(@zoom_level,@tile_column,@tile_row,@tile_data,@maxX,@maxY,@minX,@minY,@resolution)"; 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)); 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)); int dealTileCount = 0; while (dealTileCount < TileCount) { TileInfo[] datas = null; lock (needInsertDataList) { datas = needInsertDataList.ToArray(); needInsertDataList.Clear(); } if (datas == null || datas.Length == 0) { //Console.WriteLine("Sleep"); Thread.Sleep(1000); } else { //Console.WriteLine("record:" + datas.Length.ToString()); 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.Parameters[4].Value = item.Bound.XMax; cmd.Parameters[5].Value = item.Bound.YMax; cmd.Parameters[6].Value = item.Bound.XMin; cmd.Parameters[7].Value = item.Bound.YMin; cmd.Parameters[8].Value = item.Resolution; cmd.ExecuteNonQuery(); item.Data = null; } dealTileCount += datas.Length; if (Report != null) { Report(TileCount, dealTileCount); } } Thread.Sleep(0); } try { cmd.CommandText = "CREATE INDEX tiles_index ON tiles (zoom_level,tile_column,tile_row);"; cmd.ExecuteNonQuery(); cmd.CommandText = "CREATE INDEX bound_index ON tiles (maxX,maxY,minX,minY,resolution);"; cmd.ExecuteNonQuery(); } catch { } pTan.Commit(); if (Done != null) { Done(null, null); } } finally { Conn.Close(); Conn.Dispose(); SQLiteConnection.ClearPool(Conn); Thread.Sleep(10); GC.Collect(); Thread.Sleep(10); } } public event EventHandler Done; public void Stop() { Dispose(); } public void Dispose() { if (doworkThread != null) { try { doworkThread.Abort(); } catch { } finally { doworkThread = null; } } } private const double EARTH_RADIUS = 6378137; /// /// 计算两点位置的距离,返回两点的距离,单位 米 /// 该公式为GOOGLE提供,误差小于0.2米 /// /// 第一点纬度 /// 第一点经度 /// 第二点纬度 /// 第二点经度 /// public static double GetDistance(double lat1, double lng1, double lat2, double lng2) { double radLat1 = Rad(lat1); double radLng1 = Rad(lng1); double radLat2 = Rad(lat2); double radLng2 = Rad(lng2); double a = radLat1 - radLat2; double b = radLng1 - radLng2; double result = 2 * Math.Asin(Math.Sqrt(Math.Pow(Math.Sin(a / 2), 2) + Math.Cos(radLat1) * Math.Cos(radLat2) * Math.Pow(Math.Sin(b / 2), 2))) * EARTH_RADIUS; return result; } /// /// 经纬度转化成弧度 /// /// /// private static double Rad(double d) { return (double)d * Math.PI / 180d; } } }