zoukankan      html  css  js  c++  java
  • 深入理解最强桌面地图控件GMAP.NET 街景地图(StreetView)

    很久没有更新博客了,今天无事把GMAP.NET的代码又重新翻了翻,看到了街景地图的例子。

    街景地图是谷歌最早提出来的,我不知道谷歌的街景地图是如何实现的,在这个例子中,运用了WPF 3D的原理,对街景地图进行了简单的实现,在我看来更像是全景地图(PanoramaViewer)。先看看实现的效果,在本地运行代码的时候,鼠标拖动后整个图像是可以360旋转的,这里是张静态图片而已。

    整篇文档需要对WPF 3D有个基本的了解,至少要知道Viewport3D(视野),PerspectiveCamera(摄像机),ModelVisual3D等概念,如果没有这些概念,可以先去msdn看一下相关的基础知识。因为整篇文档的技术部分其实和地图没有直接的关系,更多是讲3D。

    整个项目的所有代码就是3个文件,App.xaml,PanoramaViewer.cs,Window1.xaml。

    App.xaml是创建工程时默认生成的;

    Window1.xaml主要完成了加载图片并放入到PanoramaViewer的工作;

    PanormaViewer, Panorma的英文意思是全景,因此我们给它取了个名字叫全景查看器,这个类是整个项目的核心。

    1. 核心类 PanoramaViewer(全景查看器)

    整个PanormaViewer继承于Viewport3D,构造了一个最简单的3D模型,里面很多属性,例如FieldOfView, RotationX, RotationY, RotationZ,ModelVisual3D,GeometryModel3D等都是和WPF 3D息息相关的。只是PanoramaImage ImageSource的构造需要注意一下。

    具体的代码如下所示:

    View Code

    2. 图片的组织和加载

    Window1.xaml则承担了图片的组织和加载工作,和大部分图片加载一样,也是先尝试从本地加载,本地没有,则从网上下载。这里的图片是由许多

    小块组成的,看看图片文件夹的结构就清楚了。最后这些图片组成RenderTargetBitmap,赋给前面提到的PanoramaImage。

    下面是Window1.xaml的代码:

    View Code
    using System;
    using System.ComponentModel;
    using System.IO;
    using System.Net;
    using System.Windows;
    using System.Windows.Controls;
    using System.Windows.Input;
    using System.Windows.Media;
    using System.Windows.Media.Imaging;
    
    namespace Demo.StreetView
    {
       /// <summary>
       /// Interaction logic for Window1.xaml
       /// </summary>
       public partial class Window1 : Window
       {
          BackgroundWorker loader = new BackgroundWorker();
          StackPanel buff = new StackPanel();
    
          public Window1()
          {
             InitializeComponent();
             Viewer.MouseLeftButtonDown += Viewer_MouseLeftButtonDown;
             Viewer.MouseMove += Viewer_MouseMove;
    
             buff.Orientation = Orientation.Vertical;
    
             // removes white lines between tiles!
             SetValue(RenderOptions.EdgeModeProperty, EdgeMode.Aliased);
    
             loader.DoWork += loader_DoWork;
             loader.ProgressChanged += loader_ProgressChanged;
             loader.RunWorkerCompleted += loader_RunWorkerCompleted;
             loader.WorkerReportsProgress = true;
          }
    
          void loader_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
          {
             buff.UpdateLayout();
    
             Canvas canvas = new Canvas();
             canvas.Children.Add(buff);
             canvas.Width = 512 * 13;
             canvas.Height = 512 * 7;
    
             canvas.UpdateLayout();
    
             canvas.Measure(new Size((int)canvas.Width, (int)canvas.Height));
             canvas.Arrange(new Rect(new Size((int)canvas.Width, (int)canvas.Height)));
             int Height = ((int)(canvas.ActualHeight));
             int Width = ((int)(canvas.ActualWidth));
    
             RenderTargetBitmap _RenderTargetBitmap = new RenderTargetBitmap(Width, Height, 96, 96, PixelFormats.Pbgra32);
             _RenderTargetBitmap.Render(buff);
    
             Image img = new Image();
             img.Source = _RenderTargetBitmap;
    
             Viewer.PanoramaImage = _RenderTargetBitmap;
    
             Title = "Demo.StreetView, enjoy! ;}";
          }
    
          Vector RotationVector = new Vector();
          Point DownPoint = new Point();
          void Viewer_MouseMove(object sender, MouseEventArgs e)
          {
             if(e.LeftButton == MouseButtonState.Released)
                return;
             Vector Offset = Point.Subtract(e.GetPosition(Viewer), DownPoint) * 0.25;
    
             Viewer.RotationY = RotationVector.Y + Offset.X;
             Viewer.RotationX = RotationVector.X - Offset.Y;
          }
    
          void Viewer_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
          {
             DownPoint = e.GetPosition(Viewer);
             RotationVector.X = Viewer.RotationX;
             RotationVector.Y = Viewer.RotationY;
             Cursor = Cursors.SizeAll;
          }
    
          private void Viewer_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
          {
             Cursor = Cursors.Arrow;
          }
    
          void loader_ProgressChanged(object sender, ProgressChangedEventArgs e)
          {
             if(e.ProgressPercentage == 100)
             {
                Pass p = e.UserState as Pass;
    
                Title = "Demo.StreetView, please wait on first time loading: " + p.X + "|" + p.Y + " of 13";
                Image i = new Image();
    
                i.Source = p.src;
                (buff.Children[buff.Children.Count - 1] as StackPanel).Children.Add(i);
             }
             else if(e.ProgressPercentage == 0)
             {
                Title = "Demo.StreetView, please wait on first time loading: zooming...";
    
                StackPanel ph = new StackPanel();
                ph.Orientation = Orientation.Horizontal;
                buff.Children.Add(ph);
             }
          }
    
          void loader_DoWork(object sender, DoWorkEventArgs e)
          {
             string panoId = "4fe6hEN9GJC6thoQBcgv0Q";
             int zoom = 4;
    
             //0, 1
             //1, 2   
             //2, 4
             //3, 7   
             //4, 13  
             //5, 26  
    
             for(int y = 0; y <= zoom + 1; y++)
             {
                loader.ReportProgress(0);
    
                for(int x = 0; x < 13; x++)
                {
                   Pass p = new Pass();
                   p.Y = y;
                   p.X = x;
    
                   string fl = "Tiles\\" + zoom + "\\" + panoId + "\\img_" + x + "_" + y + ".jpg";
                   string dr = System.IO.Path.GetDirectoryName(fl);
                   if(!Directory.Exists(dr))
                   {
                      Directory.CreateDirectory(dr);
                   }
                   if(!File.Exists(fl))
                   {
                      ImageSource src = Get(string.Format("http://cbk{0}.{5}/cbk?output=tile&panoid={1}&zoom={2}&x={3}&y={4}&cb_client=maps_sv", (x + 2 * y) % 3, panoId, zoom, x, y, GMap.NET.MapProviders.GoogleMapProvider.Instance.Server));
                      p.src = src;
                      SaveImg(src, fl);
                   }
                   else
                   {
                      using(Stream s = File.OpenRead(fl))
                      {
                         p.src = FromStream(s);
                      }
                   }
    
                   loader.ReportProgress(100, p);
                }
             }
    
             GC.Collect();
             GC.WaitForPendingFinalizers();
             GC.Collect();
          }
    
          void SaveImg(ImageSource src, string file)
          {
             using(Stream s = File.OpenWrite(file))
             {
                JpegBitmapEncoder e = new JpegBitmapEncoder();
                e.Frames.Add(BitmapFrame.Create(src as BitmapSource));
                e.Save(s);
             }
          }
    
          private void Window_Loaded(object sender, RoutedEventArgs e)
          {
             loader.RunWorkerAsync();
          }
    
          public Stream CopyStream(Stream inputStream)
          {
             const int readSize = 256;
             byte[] buffer = new byte[readSize];
             MemoryStream ms = new MemoryStream();
    
             using(inputStream)
             {
                int count = inputStream.Read(buffer, 0, readSize);
                while(count > 0)
                {
                   ms.Write(buffer, 0, count);
                   count = inputStream.Read(buffer, 0, readSize);
                }
             }
             buffer = null;
             ms.Seek(0, SeekOrigin.Begin);
             return ms;
          }
    
          ImageSource FromStream(Stream stream)
          {
             ImageSource ret = null;
             if(stream != null)
             {
                {
                   // try png decoder
                   try
                   {
                      JpegBitmapDecoder bitmapDecoder = new JpegBitmapDecoder(stream, BitmapCreateOptions.PreservePixelFormat, BitmapCacheOption.OnLoad);
                      ImageSource m = bitmapDecoder.Frames[0];
    
                      if(m != null)
                      {
                         ret = m;
                      }
                   }
                   catch
                   {
                      ret = null;
                   }
    
                   // try jpeg decoder
                   if(ret == null)
                   {
                      try
                      {
                         stream.Seek(0, SeekOrigin.Begin);
    
                         PngBitmapDecoder bitmapDecoder = new PngBitmapDecoder(stream, BitmapCreateOptions.PreservePixelFormat, BitmapCacheOption.OnLoad);
                         ImageSource m = bitmapDecoder.Frames[0];
    
                         if(m != null)
                         {
                            ret = m;
                         }
                      }
                      catch
                      {
                         ret = null;
                      }
                   }
                }
             }
             return ret;
          }
    
          ImageSource Get(string url)
          {
             ImageSource ret;
             
              try
             {
                HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url);
                request.ServicePoint.ConnectionLimit = 50;
                request.Proxy = WebRequest.DefaultWebProxy;
    
                request.UserAgent = "Opera/9.62 (Windows NT 5.1; U; en) Presto/2.1.1";
                request.Timeout = 10 * 1000;
                request.ReadWriteTimeout = request.Timeout * 6;
                request.Referer = string.Format("http://maps.{0}/", GMap.NET.MapProviders.GoogleMapProvider.Instance.Server);
                request.KeepAlive = true;
    
                using(HttpWebResponse response = request.GetResponse() as HttpWebResponse)
                {
                   using(Stream responseStream = CopyStream(response.GetResponseStream()))
                   {
                      ret = FromStream(responseStream);
                   }
                }
             }
             catch(Exception)
             {
                ret = null;
             }
             return ret;
          }
       }
    
       class Pass
       {
          public ImageSource src;
          public int Y;
          public int X;
       }
    }

    整个代码在http://code.google.com/p/ypmap/source/browse/可以看到。

  • 相关阅读:
    《分布式系统关注点——数据一致性(上篇)》阅读笔记
    2.23寒假学习记录
    2.22寒假学习记录
    2.21寒假学习记录
    2.20寒假学习记录
    2.19寒假学习记录
    2.18寒假学习记录
    2.17寒假学习记录
    2.17周一毕设改进计划
    2.16寒假学习记录
  • 原文地址:https://www.cnblogs.com/enjoyeclipse/p/3033302.html
Copyright © 2011-2022 走看看