地图控件GMAP.NET
enjoyeclipse
深入理解最强桌面地图控件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测试数据/p/ypmap/source/browse/ 可以看到。
分类: WPF 3D
标签: WPF 3D , GMAP.NET 地图
作者: Leo_wl
出处: http://HdhCmsTestcnblogs测试数据/Leo_wl/
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。
版权信息