Subversion Repositories Projects

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
2498 - 1
 
2
namespace GMap.NET.MapProviders
3
{
4
   using System;
5
   using System.Collections.Generic;
6
   using System.Diagnostics;
7
   using System.Globalization;
8
   using System.Xml;
9
   using GMap.NET.Internals;
10
   using GMap.NET.Projections;
11
 
12
   public abstract class OpenStreetMapProviderBase : GMapProvider, RoutingProvider, GeocodingProvider
13
   {
14
      public OpenStreetMapProviderBase()
15
      {
16
         MaxZoom = null;
17
         RefererUrl = "http://www.openstreetmap.org/";
18
         Copyright = string.Format("© OpenStreetMap - Map data ©{0} OpenStreetMap", DateTime.Today.Year);
19
      }
20
 
21
      public readonly string ServerLetters = "abc";
22
      public int MinExpectedRank = 0;
23
 
24
      #region GMapProvider Members
25
 
26
      public override Guid Id
27
      {
28
         get
29
         {
30
            throw new NotImplementedException();
31
         }
32
      }
33
 
34
      public override string Name
35
      {
36
         get
37
         {
38
            throw new NotImplementedException();
39
         }
40
      }
41
 
42
      public override PureProjection Projection
43
      {
44
         get
45
         {
46
            return MercatorProjection.Instance;
47
         }
48
      }
49
 
50
      public override GMapProvider[] Overlays
51
      {
52
         get
53
         {
54
            throw new NotImplementedException();
55
         }
56
      }
57
 
58
      public override PureImage GetTileImage(GPoint pos, int zoom)
59
      {
60
         throw new NotImplementedException();
61
      }
62
 
63
      #endregion
64
 
65
      #region GMapRoutingProvider Members
66
 
67
      public MapRoute GetRoute(PointLatLng start, PointLatLng end, bool avoidHighways, bool walkingMode, int Zoom)
68
      {
69
         List<PointLatLng> points = GetRoutePoints(MakeRoutingUrl(start, end, walkingMode ? TravelTypeFoot : TravelTypeMotorCar));
70
         MapRoute route = points != null ? new MapRoute(points, walkingMode ? WalkingStr : DrivingStr) : null;
71
         return route;
72
      }
73
 
74
      /// <summary>
75
      /// NotImplemented
76
      /// </summary>
77
      /// <param name="start"></param>
78
      /// <param name="end"></param>
79
      /// <param name="avoidHighways"></param>
80
      /// <param name="walkingMode"></param>
81
      /// <param name="Zoom"></param>
82
      /// <returns></returns>
83
      public MapRoute GetRoute(string start, string end, bool avoidHighways, bool walkingMode, int Zoom)
84
      {
85
         throw new NotImplementedException("use GetRoute(PointLatLng start, PointLatLng end...");
86
      }
87
 
88
      #region -- internals --
89
      string MakeRoutingUrl(PointLatLng start, PointLatLng end, string travelType)
90
      {
91
         return string.Format(CultureInfo.InvariantCulture, RoutingUrlFormat, start.Lat, start.Lng, end.Lat, end.Lng, travelType);
92
      }
93
 
94
      List<PointLatLng> GetRoutePoints(string url)
95
      {
96
         List<PointLatLng> points = null;
97
         try
98
         {
99
            string route = GMaps.Instance.UseRouteCache ? Cache.Instance.GetContent(url, CacheType.RouteCache) : string.Empty;
100
            if(string.IsNullOrEmpty(route))
101
            {
102
               route = GetContentUsingHttp(url);
103
               if(!string.IsNullOrEmpty(route))
104
               {
105
                  if(GMaps.Instance.UseRouteCache)
106
                  {
107
                     Cache.Instance.SaveContent(url, CacheType.RouteCache, route);
108
                  }
109
               }
110
            }
111
 
112
            if(!string.IsNullOrEmpty(route))
113
            {
114
               XmlDocument xmldoc = new XmlDocument();
115
               xmldoc.LoadXml(route);
116
               System.Xml.XmlNamespaceManager xmlnsManager = new System.Xml.XmlNamespaceManager(xmldoc.NameTable);
117
               xmlnsManager.AddNamespace("sm", "http://earth.google.com/kml/2.0");
118
 
119
               ///Folder/Placemark/LineString/coordinates
120
               var coordNode = xmldoc.SelectSingleNode("/sm:kml/sm:Document/sm:Folder/sm:Placemark/sm:LineString/sm:coordinates", xmlnsManager);
121
 
122
               string[] coordinates = coordNode.InnerText.Split('\n');
123
 
124
               if(coordinates.Length > 0)
125
               {
126
                  points = new List<PointLatLng>();
127
 
128
                  foreach(string coordinate in coordinates)
129
                  {
130
                     if(coordinate != string.Empty)
131
                     {
132
                        string[] XY = coordinate.Split(',');
133
                        if(XY.Length == 2)
134
                        {
135
                           double lat = double.Parse(XY[1], CultureInfo.InvariantCulture);
136
                           double lng = double.Parse(XY[0], CultureInfo.InvariantCulture);
137
                           points.Add(new PointLatLng(lat, lng));
138
                        }
139
                     }
140
                  }
141
               }
142
            }
143
         }
144
         catch(Exception ex)
145
         {
146
            Debug.WriteLine("GetRoutePoints: " + ex);
147
         }
148
 
149
         return points;
150
      }
151
 
152
      static readonly string RoutingUrlFormat = "http://www.yournavigation.org/api/1.0/gosmore.php?format=kml&flat={0}&flon={1}&tlat={2}&tlon={3}&v={4}&fast=1&layer=mapnik";
153
      static readonly string TravelTypeFoot = "foot";
154
      static readonly string TravelTypeMotorCar = "motorcar";
155
 
156
      static readonly string WalkingStr = "Walking";
157
      static readonly string DrivingStr = "Driving";
158
      #endregion
159
 
160
      #endregion
161
 
162
      #region GeocodingProvider Members
163
 
164
      public GeoCoderStatusCode GetPoints(string keywords, out List<PointLatLng> pointList)
165
      {
166
         // http://nominatim.openstreetmap.org/search?q=lithuania,vilnius&format=xml
167
 
168
         #region -- response --
169
         //<searchresults timestamp="Wed, 01 Feb 12 09:46:00 -0500" attribution="Data Copyright OpenStreetMap Contributors, Some Rights Reserved. CC-BY-SA 2.0." querystring="lithuania,vilnius" polygon="false" exclude_place_ids="29446018,53849547,8831058,29614806" more_url="http://open.mapquestapi.com/nominatim/v1/search?format=xml&exclude_place_ids=29446018,53849547,8831058,29614806&accept-language=en&q=lithuania%2Cvilnius">
170
         //<place place_id="29446018" osm_type="way" osm_id="24598347" place_rank="30" boundingbox="54.6868133544922,54.6879043579102,25.2885360717773,25.2898139953613" lat="54.6873633486028" lon="25.289199818878" display_name="National Museum of Lithuania, 1, Arsenalo g., Senamiesčio seniūnija, YAHOO-HIRES-20080313, Vilnius County, Šalčininkų rajonas, Vilniaus apskritis, 01513, Lithuania" class="tourism" type="museum" icon="http://open.mapquestapi.com/nominatim/v1/images/mapicons/tourist_museum.p.20.png"/>
171
         //<place place_id="53849547" osm_type="way" osm_id="55469274" place_rank="30" boundingbox="54.6896553039551,54.690486907959,25.2675743103027,25.2692089080811" lat="54.6900227236882" lon="25.2683589759401" display_name="Ministry of Foreign Affairs of the Republic of Lithuania, 2, J. Tumo Vaižganto g., Naujamiesčio seniūnija, Vilnius, Vilnius County, Vilniaus m. savivaldybė, Vilniaus apskritis, LT-01104, Lithuania" class="amenity" type="public_building"/>
172
         //<place place_id="8831058" osm_type="node" osm_id="836234960" place_rank="30" boundingbox="54.6670935059,54.6870973206,25.2638857269,25.2838876343" lat="54.677095" lon="25.2738876" display_name="Railway Museum of Lithuania, 15, Mindaugo g., Senamiesčio seniūnija, Vilnius, Vilnius County, Vilniaus m. savivaldybė, Vilniaus apskritis, 03215, Lithuania" class="tourism" type="museum" icon="http://open.mapquestapi.com/nominatim/v1/images/mapicons/tourist_museum.p.20.png"/>
173
         //<place place_id="29614806" osm_type="way" osm_id="24845629" place_rank="30" boundingbox="54.6904983520508,54.6920852661133,25.2606296539307,25.2628803253174" lat="54.6913385159005" lon="25.2617684209873" display_name="Seimas (Parliament) of the Republic of Lithuania, 53, Gedimino pr., Naujamiesčio seniūnija, Vilnius, Vilnius County, Vilniaus m. savivaldybė, Vilniaus apskritis, LT-01111, Lithuania" class="amenity" type="public_building"/>
174
         //</searchresults> 
175
         #endregion
176
 
177
         return GetLatLngFromGeocoderUrl(MakeGeocoderUrl(keywords), out pointList);
178
      }
179
 
180
      public PointLatLng? GetPoint(string keywords, out GeoCoderStatusCode status)
181
      {
182
         List<PointLatLng> pointList;
183
         status = GetPoints(keywords, out pointList);
184
         return pointList != null && pointList.Count > 0 ? pointList[0] : (PointLatLng?) null;
185
      }
186
 
187
      public GeoCoderStatusCode GetPoints(Placemark placemark, out List<PointLatLng> pointList)
188
      {
189
         // http://nominatim.openstreetmap.org/search?street=&city=vilnius&county=&state=&country=lithuania&postalcode=&format=xml
190
 
191
         #region -- response --
192
         //<searchresults timestamp="Thu, 29 Nov 12 08:38:23 +0000" attribution="Data © OpenStreetMap contributors, ODbL 1.0. http://www.openstreetmap.org/copyright" querystring="vilnius, lithuania" polygon="false" exclude_place_ids="98093941" more_url="http://nominatim.openstreetmap.org/search?format=xml&exclude_place_ids=98093941&accept-language=de-de,de;q=0.8,en-us;q=0.5,en;q=0.3&q=vilnius%2C+lithuania">
193
         //<place place_id="98093941" osm_type="relation" osm_id="1529146" place_rank="16" boundingbox="54.5693359375,54.8323097229004,25.0250644683838,25.4815216064453" lat="54.6843135" lon="25.2853984" display_name="Vilnius, Vilniaus m. savivaldybė, Distrikt Vilnius, Litauen" class="boundary" type="administrative" icon="http://nominatim.openstreetmap.org/images/mapicons/poi_boundary_administrative.p.20.png"/>
194
         //</searchresults> 
195
         #endregion
196
 
197
         return GetLatLngFromGeocoderUrl(MakeDetailedGeocoderUrl(placemark), out pointList);
198
      }
199
 
200
      public PointLatLng? GetPoint(Placemark placemark, out GeoCoderStatusCode status)
201
      {
202
         List<PointLatLng> pointList;
203
         status = GetPoints(placemark, out pointList);
204
         return pointList != null && pointList.Count > 0 ? pointList[0] : (PointLatLng?) null;
205
      }
206
 
207
      public GeoCoderStatusCode GetPlacemarks(PointLatLng location, out List<Placemark> placemarkList)
208
      {
209
         throw new NotImplementedException("use GetPlacemark");
210
      }
211
 
212
      public Placemark? GetPlacemark(PointLatLng location, out GeoCoderStatusCode status)
213
      {
214
         //http://nominatim.openstreetmap.org/reverse?format=xml&lat=52.5487429714954&lon=-1.81602098644987&zoom=18&addressdetails=1
215
 
216
         #region -- response --
217
         /*
218
         <reversegeocode timestamp="Wed, 01 Feb 12 09:51:11 -0500" attribution="Data Copyright OpenStreetMap Contributors, Some Rights Reserved. CC-BY-SA 2.0." querystring="format=xml&lat=52.5487429714954&lon=-1.81602098644987&zoom=18&addressdetails=1">
219
         <result place_id="2061235282" osm_type="way" osm_id="90394420" lat="52.5487800131654" lon="-1.81626922291265">
220
         137, Pilkington Avenue, Castle Vale, City of Birmingham, West Midlands, England, B72 1LH, United Kingdom
221
         </result>
222
         <addressparts>
223
         <house_number>
224
         137
225
         </house_number>
226
         <road>
227
         Pilkington Avenue
228
         </road>
229
         <suburb>
230
         Castle Vale
231
         </suburb>
232
         <city>
233
         City of Birmingham
234
         </city>
235
         <county>
236
         West Midlands
237
         </county>
238
         <state_district>
239
         West Midlands
240
         </state_district>
241
         <state>
242
         England
243
         </state>
244
         <postcode>
245
         B72 1LH
246
         </postcode>
247
         <country>
248
         United Kingdom
249
         </country>
250
         <country_code>
251
         gb
252
         </country_code>
253
         </addressparts>
254
         </reversegeocode>
255
         */
256
 
257
         #endregion
258
 
259
         return GetPlacemarkFromReverseGeocoderUrl(MakeReverseGeocoderUrl(location), out status);
260
      }
261
 
262
      #region -- internals --
263
 
264
      string MakeGeocoderUrl(string keywords)
265
      {
266
         return string.Format(GeocoderUrlFormat, keywords.Replace(' ', '+'));
267
      }
268
 
269
      string MakeDetailedGeocoderUrl(Placemark placemark)
270
      {
271
         var street = String.Join(" ", new[] { placemark.HouseNo, placemark.ThoroughfareName }).Trim();
272
         return string.Format(GeocoderDetailedUrlFormat,
273
                              street.Replace(' ', '+'),
274
                              placemark.LocalityName.Replace(' ', '+'),
275
                              placemark.SubAdministrativeAreaName.Replace(' ', '+'),
276
                              placemark.AdministrativeAreaName.Replace(' ', '+'),
277
                              placemark.CountryName.Replace(' ', '+'),
278
                              placemark.PostalCodeNumber.Replace(' ', '+'));
279
      }
280
 
281
      string MakeReverseGeocoderUrl(PointLatLng pt)
282
      {
283
         return string.Format(CultureInfo.InvariantCulture, ReverseGeocoderUrlFormat, pt.Lat, pt.Lng);
284
      }
285
 
286
      GeoCoderStatusCode GetLatLngFromGeocoderUrl(string url, out List<PointLatLng> pointList)
287
      {
288
         var status = GeoCoderStatusCode.Unknow;
289
         pointList = null;
290
 
291
         try
292
         {
293
            string geo = GMaps.Instance.UseGeocoderCache ? Cache.Instance.GetContent(url, CacheType.GeocoderCache) : string.Empty;
294
 
295
            bool cache = false;
296
 
297
            if(string.IsNullOrEmpty(geo))
298
            {
299
               geo = GetContentUsingHttp(url);
300
 
301
               if(!string.IsNullOrEmpty(geo))
302
               {
303
                  cache = true;
304
               }
305
            }
306
 
307
            if(!string.IsNullOrEmpty(geo))
308
            {
309
               if(geo.StartsWith("<?xml") && geo.Contains("<place"))
310
               {
311
                  if(cache && GMaps.Instance.UseGeocoderCache)
312
                  {
313
                     Cache.Instance.SaveContent(url, CacheType.GeocoderCache, geo);
314
                  }
315
 
316
                  XmlDocument doc = new XmlDocument();
317
                  doc.LoadXml(geo);
318
                  {
319
                     XmlNodeList l = doc.SelectNodes("/searchresults/place");
320
                     if(l != null)
321
                     {
322
                        pointList = new List<PointLatLng>();
323
 
324
                        foreach(XmlNode n in l)
325
                        {
326
                           var nn = n.Attributes["place_rank"];
327
 
328
                           int rank = 0;
329
#if !PocketPC
330
                           if (nn != null && Int32.TryParse(nn.Value, out rank))
331
                           {
332
#else
333
                           if(nn != null && !string.IsNullOrEmpty(nn.Value))
334
                           {
335
                              rank = int.Parse(nn.Value, NumberStyles.Integer, CultureInfo.InvariantCulture);
336
#endif
337
                              if(rank < MinExpectedRank)
338
                                 continue;
339
                           }
340
 
341
                           nn = n.Attributes["lat"];
342
                           if(nn != null)
343
                           {
344
                              double lat = double.Parse(nn.Value, CultureInfo.InvariantCulture);
345
 
346
                              nn = n.Attributes["lon"];
347
                              if(nn != null)
348
                              {
349
                                 double lng = double.Parse(nn.Value, CultureInfo.InvariantCulture);
350
                                 pointList.Add(new PointLatLng(lat, lng));
351
                              }
352
                           }
353
                        }
354
 
355
                        status = GeoCoderStatusCode.G_GEO_SUCCESS;
356
                     }
357
                  }
358
               }
359
            }
360
         }
361
         catch(Exception ex)
362
         {
363
            status = GeoCoderStatusCode.ExceptionInCode;
364
            Debug.WriteLine("GetLatLngFromGeocoderUrl: " + ex);
365
         }
366
 
367
         return status;
368
      }
369
 
370
      Placemark? GetPlacemarkFromReverseGeocoderUrl(string url, out GeoCoderStatusCode status)
371
      {
372
         status = GeoCoderStatusCode.Unknow;
373
         Placemark? ret = null;
374
 
375
         try
376
         {
377
            string geo = GMaps.Instance.UsePlacemarkCache ? Cache.Instance.GetContent(url, CacheType.PlacemarkCache) : string.Empty;
378
 
379
            bool cache = false;
380
 
381
            if(string.IsNullOrEmpty(geo))
382
            {
383
               geo = GetContentUsingHttp(url);
384
 
385
               if(!string.IsNullOrEmpty(geo))
386
               {
387
                  cache = true;
388
               }
389
            }
390
 
391
            if(!string.IsNullOrEmpty(geo))
392
            {
393
               if(geo.StartsWith("<?xml") && geo.Contains("<result"))
394
               {
395
                  if(cache && GMaps.Instance.UsePlacemarkCache)
396
                  {
397
                     Cache.Instance.SaveContent(url, CacheType.PlacemarkCache, geo);
398
                  }
399
 
400
                  XmlDocument doc = new XmlDocument();
401
                  doc.LoadXml(geo);
402
                  {
403
                     XmlNode r = doc.SelectSingleNode("/reversegeocode/result");
404
                     if(r != null)
405
                     {
406
                        var p = new Placemark(r.InnerText);
407
 
408
                        XmlNode ad = doc.SelectSingleNode("/reversegeocode/addressparts");
409
                        if(ad != null)
410
                        {
411
                           var vl = ad.SelectSingleNode("country");
412
                           if(vl != null)
413
                           {
414
                              p.CountryName = vl.InnerText;
415
                           }
416
 
417
                           vl = ad.SelectSingleNode("country_code");
418
                           if(vl != null)
419
                           {
420
                              p.CountryNameCode = vl.InnerText;
421
                           }
422
 
423
                           vl = ad.SelectSingleNode("postcode");
424
                           if(vl != null)
425
                           {
426
                              p.PostalCodeNumber = vl.InnerText;
427
                           }
428
 
429
                           vl = ad.SelectSingleNode("state");
430
                           if(vl != null)
431
                           {
432
                              p.AdministrativeAreaName = vl.InnerText;
433
                           }
434
 
435
                           vl = ad.SelectSingleNode("region");
436
                           if(vl != null)
437
                           {
438
                              p.SubAdministrativeAreaName = vl.InnerText;
439
                           }
440
 
441
                           vl = ad.SelectSingleNode("suburb");
442
                           if(vl != null)
443
                           {
444
                              p.LocalityName = vl.InnerText;
445
                           }
446
 
447
                           vl = ad.SelectSingleNode("road");
448
                           if(vl != null)
449
                           {
450
                              p.ThoroughfareName = vl.InnerText;
451
                           }
452
                        }
453
 
454
                        ret = p;
455
 
456
                        status = GeoCoderStatusCode.G_GEO_SUCCESS;
457
                     }
458
                  }
459
               }
460
            }
461
         }
462
         catch(Exception ex)
463
         {
464
            ret = null;
465
            status = GeoCoderStatusCode.ExceptionInCode;
466
            Debug.WriteLine("GetPlacemarkFromReverseGeocoderUrl: " + ex);
467
         }
468
 
469
         return ret;
470
      }
471
 
472
      static readonly string ReverseGeocoderUrlFormat = "http://nominatim.openstreetmap.org/reverse?format=xml&lat={0}&lon={1}&zoom=18&addressdetails=1";
473
      static readonly string GeocoderUrlFormat = "http://nominatim.openstreetmap.org/search?q={0}&format=xml";
474
      static readonly string GeocoderDetailedUrlFormat = "http://nominatim.openstreetmap.org/search?street={0}&city={1}&county={2}&state={3}&country={4}&postalcode={5}&format=xml";
475
 
476
      #endregion
477
 
478
      #endregion
479
   }
480
 
481
   /// <summary>
482
   /// OpenStreetMap provider - http://www.openstreetmap.org/
483
   /// </summary>
484
   public class OpenStreetMapProvider : OpenStreetMapProviderBase
485
   {
486
      public static readonly OpenStreetMapProvider Instance;
487
 
488
      OpenStreetMapProvider()
489
      {
490
      }
491
 
492
      static OpenStreetMapProvider()
493
      {
494
         Instance = new OpenStreetMapProvider();
495
      }
496
 
497
      #region GMapProvider Members
498
 
499
      readonly Guid id = new Guid("0521335C-92EC-47A8-98A5-6FD333DDA9C0");
500
      public override Guid Id
501
      {
502
         get
503
         {
504
            return id;
505
         }
506
      }
507
 
508
      readonly string name = "OpenStreetMap";
509
      public override string Name
510
      {
511
         get
512
         {
513
            return name;
514
         }
515
      }
516
 
517
      GMapProvider[] overlays;
518
      public override GMapProvider[] Overlays
519
      {
520
         get
521
         {
522
            if(overlays == null)
523
            {
524
               overlays = new GMapProvider[] { this };
525
            }
526
            return overlays;
527
         }
528
      }
529
 
530
      public override PureImage GetTileImage(GPoint pos, int zoom)
531
      {
532
         string url = MakeTileImageUrl(pos, zoom, string.Empty);
533
 
534
         return GetTileImageUsingHttp(url);
535
      }
536
 
537
      #endregion
538
 
539
      string MakeTileImageUrl(GPoint pos, int zoom, string language)
540
      {
541
         char letter = ServerLetters[GetServerNum(pos, 3)];
542
         return string.Format(UrlFormat, letter, zoom, pos.X, pos.Y);
543
      }
544
 
545
      static readonly string UrlFormat = "http://{0}.tile.openstreetmap.org/{1}/{2}/{3}.png";
546
   }
547
}