[转]Using Google Maps with ArcGIS Silverlight
The ArcGIS API for Microsoft Silverlight/WPF (and Windows Phone) includes an extensible framework for adding geographic data from a variety of sources. The core library (ESRI.ArcGIS.Client) contains the base classes for the framework and the implementation for the primary source of data, ArcGIS Server. In the initial version of the API, the framework was utilized to support the use of Bing Maps imagery. In version 2.0, the framework was leveraged to support other data sources, such as OpenStreetMap, WMS, and GeoRSS in the toolkit data sources assembly (ESRI.ArcGIS.Client.Toolkit.DataSources.dll) . You'll notice Google is missing from that list of data sources. This brings up a question, and the purpose for this blog post:
Can you use Google Maps imagery in an ArcGIS Silverlight/WPF/Windows Phone application?
There
are two answers; one technical, one legal. First, technically it can be
done. The Web Mercator projection and the tiling scheme used by Google
map and image tiles is virtually the same as Bing, new ArcGIS Online
services, and OpenStreetMap. The URL format to access Google tiles
directly can be discovered. For example, you can use Fiddler to view requests from a legitimate Google Maps application. Some folks even discuss the URL format and structure (e.g. Code Project).
Now
for the legal answer. In short, no. You cannot access Google Maps
imagery outside of an interface (read: APIs) provided by Google. This is
mentioned in an online FAQ which references an item in the terms of service.
The last statement in the terms of service appears to suggest that
direct access to map tiles outside of an API is possible via an explicit
agreement. In an email conversation with Thor Mitchell, Product Manager
for the Google Maps API, he clarified these terms by stating that such
agreements are rare and "they are generally limited to embedded device
partnerships such as in-car navigation systems and in-flight
entertainment systems." Thor also reminded me that the URL format to
access Google tiles is an undocumented interface, so it can change at
any time. And Google maintains a team that identifies and contacts
application developers that use Google tiles (and services) in an
unsupported way. If you try, you will likely be asked to stop,
followed by more punitive measures if ignored.
Since the custom layer will generate dynamic map images from a service, it can extend the DynamicMapServiceLayer class in the ArcGIS Silverlight API. You can override the Initialize method to set a few key properties, such as the full extent and spatial reference, but you'll also want to define the tiling scheme that matches Google Maps and will be used to define the scale level at which a dynamic image will be generated. These levels of detail (lods) will be used to determine the output size of the map image generated by the Static Maps API. The primary method to override in this case is GetUrl() which provides access to the map extent, pixel width and height, and a delegate to call when URL construction is complete and a request for a new map image should be generated. At runtime, each extent change in the Map control calls GetUrl() to generate a new map image.
using System;
using ESRI.ArcGIS.Client;
using ESRI.ArcGIS.Client.Geometry;
namespace CustomLayers
{
public class GoogleStaticMapLayer : DynamicMapServiceLayer
{
private static ESRI.ArcGIS.Client.Projection.WebMercator mercator =
new ESRI.ArcGIS.Client.Projection.WebMercator();
private const double cornerCoordinate = 20037508.3427892;
private const int WKID = 102100;
public GoogleStaticMapLayer() : base(){ }
private Lod[] Lods { get; set;}
public override void Initialize()
{
this.FullExtent =
new ESRI.ArcGIS.Client.Geometry.Envelope(-cornerCoordinate, -cornerCoordinate, cornerCoordinate, cornerCoordinate)
{
SpatialReference = new SpatialReference(WKID)
};
this.SpatialReference = new SpatialReference(WKID);
Lods = new Lod[21];
double resolution = cornerCoordinate * 2 / 256;
for (int i = 0; i < Lods.Length; i++)
{
Lods[i] = new Lod() { Resolution = resolution };
resolution /= 2;
}
base.Initialize();
}
public override void GetUrl(ESRI.ArcGIS.Client.Geometry.Envelope extent, int width, int height,
DynamicMapServiceLayer.OnUrlComplete onComplete)
{
MapPoint geogCenterPoint = null;
string mapURL = null;
try
{
if (width > 640 || height > 640)
throw new Exception("Width or height greater than 640");
double currentResolution = extent.Width / width;
int currentLodIndex = 0;
int requestWidth = 0;
int requestHeight = 0;
for (int i = 0; i < Lods.Length; i++)
{
Lod lod = Lods[i];
currentLodIndex = i;
if ((int)lod.Resolution <= (int)currentResolution)
{
requestWidth = (int)(extent.Width / lod.Resolution);
requestHeight = (int)(extent.Height / lod.Resolution);
break;
}
}
if (requestWidth > 640 || requestHeight > 640)
throw new Exception("Request width or height greater than 640");
geogCenterPoint = mercator.ToGeographic(extent.GetCenter()) as MapPoint;
mapURL = string.Format
("http://maps.google.com/maps/api/staticmap?center={0},{1}&zoom={2}&size={3}x{4}&maptype=roadmap&sensor=false",
geogCenterPoint.Y, geogCenterPoint.X, currentLodIndex, requestWidth, requestHeight);
}
catch (Exception ex)
{
// Message box just for
- The application must run in a Web browser (see 10.8). This means you cannot use it in a WPF, Silverlight out-of-browser, or Windows Phone application.
- All branding and attribution must remain visible at all times, and can not be obscured by overlays or UI elements in any way (see 7.4d). Although the Google copyright text and ESRI logo are close in an ArcGIS Silverlight application, you can still see\read the Google copyright details.
- The application should not attempt to stitch multiple static map images together to display a map that is larger than permitted in the Maps APIs Documentation (see 10.2). Basically you can't generate a bunch of dynamic images and stitch them together on the client for map sizes greater than 640 pixels on a side. Even if you could legally, you'll get a Google stamp on each image, which might show up in the middle of your map - it could get messy.