离线地图基础开发

1. 下载离线瓦片地图

android mblites离线瓦片 如何在移动端使用 离线瓦片地图_Image

android mblites离线瓦片 如何在移动端使用 离线瓦片地图_Image_02


android mblites离线瓦片 如何在移动端使用 离线瓦片地图_Image_03


下载完成。瓦片路径可在源码中自行修改,我这里为了后面拼接方便,自定了路径与命名规则。

android mblites离线瓦片 如何在移动端使用 离线瓦片地图_Image_04


到此处,离线瓦片地图下载成功。

2. **

拼接瓦片地图

**
直接整代码吧:
注:以下代码仅仅是用于demo测试。所以仅仅学习思路即可

private void button1_Click(object sender, EventArgs e)
        {
            pictureBox1.Image = null; 
            int Zoom = Convert.ToInt32(numericUpDown1.Value);        //地图等级
            string tilePath1 = "D:\GisMap\_alllayers\" + Zoom;       //瓦片路径
            //遍历文件
            DirectoryInfo aaa = new DirectoryInfo(tilePath1);		
            DirectoryInfo[] files = aaa.GetDirectories();
            FileInfo[] pngFile = files[0].GetFiles(); 
            TilesBounds tilesBounds = new TilesBounds();
            tilesBounds.minCol = Convert.ToInt32(pngFile[0].Name.Replace(".png", ""));
            tilesBounds.maxCol = Convert.ToInt32(pngFile[pngFile.Length - 1].Name.Replace(".png", ""));
            tilesBounds.minRow = Convert.ToInt32(files[0].Name);
            tilesBounds.maxRow = Convert.ToInt32(files[files.Length - 1].Name);
            //计算切片个数
            int num = ((tilesBounds.maxCol - tilesBounds.minCol) + 1) * ((tilesBounds.maxRow - tilesBounds.minRow) + 1);
            progressBar1.Maximum = num;
            progressBar1.Step = 1; 
            label3.Text = num.ToString();
            tilesBounds.zoomLevel = Zoom;
            string outPutFileName = "D:\\" + Zoom + ".png";
            string tilePath = "D:\GisMap\_alllayers\";
            //拼接
            CombineTiles(tilesBounds, tilePath, outPutFileName);
            //MessageBox.Show("拼接完成");
            pictureBox1.Image = Image.FromFile(outPutFileName); 
        }
int a = 0;
        将单个切片的像素值赋值给拼接后的图片
        private void SaveBitmapBuffered(Bitmap mainbit, string bmppath, int x, int y)
        {
            a++;
            progressBar1.Value = a;
            x = x * 256;
            y = y * 256;
            label4.Text = a.ToString();
            Application.DoEvents();
            Bitmap bt = new Bitmap(bmppath);
            for (int i = 0; i < 256; i++)
            {
                for (int j = 0; j < 256; j++)
                {
                    mainbit.SetPixel(x + i, y + j, bt.GetPixel(i, j));
                }
            }
        }
  
        /// <summary>
        /// 遍历瓦片
        /// </summary>
        private void CombineTiles(TilesBounds tilesBounds, string tilePath, string outPutFileName)
        {
            a = 0;
            if (File.Exists(outPutFileName))
            {
                //File.Delete(outPutFileName);
            }
            int imageWidth = 256 * (tilesBounds.maxCol - tilesBounds.minCol + 1);
            int imageHeight = 256 * (tilesBounds.maxRow - tilesBounds.minRow + 1);
            Bitmap memoryimg = new Bitmap(imageWidth, imageHeight);//设置拼接后的图片大小,注意:如果图片很大,需要将程序设置成64位

            for (int row = tilesBounds.minRow; row <= tilesBounds.maxRow; row++)
            {
                for (int col = tilesBounds.minCol; col <= tilesBounds.maxCol; col++)
                {
                    try
                    { 
                        string sourceFileName = tilePath + tilesBounds.zoomLevel.ToString() + "\\" + row.ToString() + "\\" + col.ToString() + ".png";
                        if (File.Exists(sourceFileName))
                        {
                            SaveBitmapBuffered(memoryimg, sourceFileName, col - tilesBounds.minCol, row - tilesBounds.minRow);
                        }
                        else
                        {
                            Console.WriteLine("不存在:" + sourceFileName);
                        }
                    }
                    catch (Exception ex)
                    {
                        MessageBox.Show(ex.ToString());
                    }
                }
            }
            memoryimg.Save(outPutFileName);//保存合并后的图片
            memoryimg.Dispose();
        }

瓦片地图的定位

  1. 参考公式:

代码实现:

//地图等级
 			int zoom = Convert.ToInt32(numericUpDown1.Value); 
            TileModel _tileNew = new TileModel();//瓦片模型
            LnglatModel PointNew = new LnglatModel  //经纬度
            {
                Lat = double.Parse(tb_Lat.Text),
                Lng = double.Parse(tb_Lnt.Text)
            }; 
            _tileNew = TileTools.toTile(zoom, PointNew); //经纬度转瓦片信息
            int minR = _tileNew.Y - 1;
            int maxR = _tileNew.Y + 1;
            int minC = _tileNew.X - 1;
            int maxC = _tileNew.X + 1;  
            int imageWidth = 256 * (maxC - minC + 1);
            int imageHeight = 256 * (maxR - minR + 1);
            this.pictureBox1.Size = new Size(imageWidth, imageHeight);  
            int PixelX;
            int PixelY;
            TileTools.toPixel(zoom, PointNew, out PixelX, out PixelY);  
            pic_Location.Left = PixelX + 256- pic_Location.Width/2;
            pic_Location.Top = PixelY + 256 - pic_Location.Height/2; 
            Bitmap memoryimg = new Bitmap(imageWidth, imageHeight);//设置拼接后的图片大小,注意:如果图片很大,需要将程序设置成64位 
            for (int row = minR; row <= maxR; row++)
            {
                for (int col = minC; col <= maxC; col++)
                {
                    try
                    {
                        string sourceFileName = @"D:\GisMap\_alllayers\" + zoom + "\\" + row.ToString() + "\\" + col.ToString() + ".png";
                        if (File.Exists(sourceFileName))
                        {
                            WriteLog("找到瓦片:" + sourceFileName);
                            //拼接瓦片
                            BitMapTools.SaveBitmapBuffered(memoryimg, sourceFileName, col - minC, row - minR);
                        }
                        else
                        {
                            WriteLog("不存在瓦片:" + sourceFileName);
                        }
                    }
                    catch (Exception ex)
                    {
                        MessageBox.Show(ex.ToString());
                    }
                }
            }  
            Image NewMap = ;
            memoryimg.Save("D:\\test.png");//保存合并后的图片
            memoryimg.Dispose();
            WriteLog("定位成功");
static int a = 0;
        将单个切片的像素值赋值给拼接后的图片
        public static void SaveBitmapBuffered(Bitmap mainbit, string bmppath, int x, int y)
        {
            a++;
            x = x * 256;
            y = y * 256;
            //Application.DoEvents();
            Bitmap bt = new Bitmap(bmppath);
            for (int i = 0; i < 256; i++)
            {
                for (int j = 0; j < 256; j++)
                {
                    mainbit.SetPixel(x + i, y + j, bt.GetPixel(i, j));
                }
            }
        } 

// 下面是我整理的几个常用的函数。(此处缺一个像素转经纬度的函数,可以按照上面公式实现。后面有时间补上)

 
		//将tile(瓦片)坐标系转换为lnglat(地理)坐标系
        public static LnglatModel toLnglat(TileModel _Title)
        {
            double n = Math.Pow(2, _Title.Zoom);
            double lng = _Title.X / n * 360.0 - 180.0;
            double lat = Math.Atan(Math.Sinh(Math.PI * (1 - 2 * _Title.Y / n)));
            lat = lat * 180.0 / Math.PI;
            return new LnglatModel(lng, lat);
        }

        //将lnglat地理坐标系转换为tile瓦片坐标系 Fun_1
        public static TileModel toTile(int zoom, LnglatModel lnglat)
        {
            double n = Math.Pow(2, zoom);
            double tileX = ((lnglat.Lng + 180) / 360) * n;
            double tileY = (1 - (Math.Log(Math.Tan(lnglat.Lat * (Math.PI / 180)) + (1 / Math.Cos(lnglat.Lat * (Math.PI / 180)))) / Math.PI)) / 2 * n;
            return new TileModel((int)tileX, (int)tileY, zoom);
        }
      //将lnglat地理坐标系转换为tile瓦片坐标系 Fun_2
        public static String getTileNumber(double lat, double lon, int level)
        {
            int xtile = (int)Math.Floor((lon + 180) / 360 * (1 << level));
            int ytile = (int)Math.Floor((1 - Math.Log(Math.Tan(lat * (Math.PI / 180)) + 1 / Math.Cos(lat * (Math.PI / 180))) / Math.PI) / 2 * (1 << level));
            if (xtile < 0)
                xtile = 0;
            if (xtile >= (1 << level))
                xtile = ((1 << level) - 1);
            if (ytile < 0)
                ytile = 0;
            if (ytile >= (1 << level))
                ytile = ((1 << level) - 1);
            return (xtile + "/" + ytile);
        }
        //将lnglat地理坐标系转换为tile瓦片坐标系再转化为像素  
        public static void toPixel(int zoom, LnglatModel lnglat,  out int x, out int y)
        {
            double n = Math.Pow(2, zoom);
            double tileX = ((lnglat.Lng + 180) / 360) * n;
            double tileY = (1 - (Math.Log(Math.Tan(lnglat.Lat * (Math.PI / 180)) + (1 / Math.Cos(lnglat.Lat * (Math.PI / 180)))) / Math.PI)) / 2 * n;
            x = Convert.ToInt32((tileX * 265) % 265);
            y = Convert.ToInt32((tileY * 265) % 265); 
        }

图片的透明度处理

因为拼成的瓦片需要美化,所以进行图片透明化处理。效果如下:

android mblites离线瓦片 如何在移动端使用 离线瓦片地图_Text_05


android mblites离线瓦片 如何在移动端使用 离线瓦片地图_Image_06

public static Bitmap opacity(Image srcImage)
        {
            float[][] nArray ={ new float[] {1, 0, 0, 0, 0},
new float[] {0, 1, 0, 0, 0},
new float[] {0, 0, 1, 0, 0},
new float[] {0, 0, 0, 0.7F, 0},//0.7F 为透明度
new float[] {0, 0, 0, 0, 1}};
            ColorMatrix matrix = new ColorMatrix(nArray);
            ImageAttributes attributes = new ImageAttributes();
            attributes.SetColorMatrix(matrix, ColorMatrixFlag.Default, ColorAdjustType.Bitmap);
            //Image srcImage = Image.FromFile("D:\\test.png");
            Bitmap resultImage = new Bitmap(srcImage.Width, srcImage.Height);
            Graphics g = Graphics.FromImage(resultImage);
            g.DrawImage(srcImage, new Rectangle(0, 0, srcImage.Width, srcImage.Height), 0, 0, srcImage.Width, srcImage.Height, GraphicsUnit.Pixel, attributes);
            return resultImage;
        }