好得很程序员自学网

<tfoot draggable='sEl'></tfoot>

地图控件GMAP.NET

地图控件GMAP.NET

 

深入理解最强桌面地图控件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/ 可以看到。

 

 

分类:  WPF 3D

标签:  WPF 3D ,  GMAP.NET 地图

作者: Leo_wl

    

出处: http://www.cnblogs.com/Leo_wl/

    

本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。

版权信息

查看更多关于地图控件GMAP.NET的详细内容...

  阅读:84次