1/*********************************************************************\ 2* * 3* epolys.js by Mike Williams * 4* updated to API v3 by Larry Ross * 5* * 6* A Google Maps API Extension * 7* * 8* Adds various Methods to google.maps.Polygon and google.maps.Polyline * 9* * 10* .Contains(latlng) returns true is the poly contains the specified * 11* GLatLng * 12* * 13* .Area() returns the approximate area of a poly that is * 14* not self-intersecting * 15* * 16* .Distance() returns the length of the poly path * 17* * 18* .Bounds() returns a GLatLngBounds that bounds the poly * 19* * 20* .GetPointAtDistance() returns a GLatLng at the specified distance * 21* along the path. * 22* The distance is specified in metres * 23* Reurns null if the path is shorter than that * 24* * 25* .GetPointsAtDistance() returns an array of GLatLngs at the * 26* specified interval along the path. * 27* The distance is specified in metres * 28* * 29* .GetIndexAtDistance() returns the vertex number at the specified * 30* distance along the path. * 31* The distance is specified in metres * 32* Returns null if the path is shorter than that * 33* * 34* .Bearing(v1?,v2?) returns the bearing between two vertices * 35* if v1 is null, returns bearing from first to last * 36* if v2 is null, returns bearing from v1 to next * 37* * 38* * 39*********************************************************************** 40* * 41* This Javascript is provided by Mike Williams * 42* Blackpool Community Church Javascript Team * 43* http://www.blackpoolchurch.org/ * 44* http://econym.org.uk/gmap/ * 45* * 46* This work is licenced under a Creative Commons Licence * 47* http://creativecommons.org/licenses/by/2.0/uk/ * 48* * 49*********************************************************************** 50* * 51* Version 1.1 6-Jun-2007 * 52* Version 1.2 1-Jul-2007 - fix: Bounds was omitting vertex zero * 53* add: Bearing * 54* Version 1.3 28-Nov-2008 add: GetPointsAtDistance() * 55* Version 1.4 12-Jan-2009 fix: GetPointsAtDistance() * 56* Version 3.0 11-Aug-2010 update to v3 * 57* * 58\*********************************************************************/ 59// === first support methods that don't (yet) exist in v3 60google.maps.LatLng.prototype.distanceFrom = function(newLatLng) { 61 var EarthRadiusMeters = 6378137.0; // meters 62 var lat1 = this.lat(); 63 var lon1 = this.lng(); 64 var lat2 = newLatLng.lat(); 65 var lon2 = newLatLng.lng(); 66 var dLat = (lat2-lat1) * Math.PI / 180; 67 var dLon = (lon2-lon1) * Math.PI / 180; 68 var a = Math.sin(dLat/2) * Math.sin(dLat/2) + 69 Math.cos(lat1 * Math.PI / 180 ) * Math.cos(lat2 * Math.PI / 180 ) * 70 Math.sin(dLon/2) * Math.sin(dLon/2); 71 var c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1-a)); 72 var d = EarthRadiusMeters * c; 73 return d; 74} 75 76google.maps.LatLng.prototype.latRadians = function() { 77 return this.lat() * Math.PI/180;
78} 79 80google.maps.LatLng.prototype.lngRadians = function() { 81 return this.lng() * Math.PI/180; 82} 83 84// === A method for testing if a point is inside a polygon 85// === Returns true if poly contains point 86// === Algorithm shamelessly stolen from http://alienryderflex.com/polygon/ 87google.maps.Polygon.prototype.Contains = function(point) { 88 var j=0; 89 var oddNodes = false; 90 var x = point.lng(); 91 var y = point.lat(); 92 for (var i=0; i < this.getPath().getLength(); i++) { 93 j++; 94 if (j == this.getPath().getLength()) {j = 0;} 95 if (((this.getPath().getAt(i).lat() < y) && (this.getPath().getAt(j).lat() >= y)) 96 || ((this.getPath().getAt(j).lat() < y) && (this.getPath().getAt(i).lat() >= y))) { 97 if ( this.getPath().getAt(i).lng() + (y - this.getPath().getAt(i).lat()) 98 / (this.getPath().getAt(j).lat()-this.getPath().getAt(i).lat()) 99 * (this.getPath().getAt(j).lng() - this.getPath().getAt(i).lng())<x ) { 100 oddNodes = !oddNodes 101 } 102 } 103 } 104 return oddNodes; 105} 106 107// === A method which returns the approximate area of a non-intersecting polygon in square metres === 108// === It doesn't fully account for spherical geometry, so will be inaccurate for large polygons === 109// === The polygon must not intersect itself === 110google.maps.Polygon.prototype.Area = function() { 111 var a = 0; 112 var j = 0; 113 var b = this.Bounds();
114 var x0 = b.getSouthWest().lng(); 115 var y0 = b.getSouthWest().lat(); 116 for (var i=0; i < this.getPath().getLength(); i++) { 117 j++; 118 if (j == this.getPath().getLength()) {j = 0;} 119 var x1 = this.getPath().getAt(i).distanceFrom(new google.maps.LatLng(this.getPath().getAt(i).lat(),x0)); 120 var x2 = this.getPath().getAt(j).distanceFrom(new google.maps.LatLng(this.getPath().getAt(j).lat(),x0)); 121 var y1 = this.getPath().getAt(i).distanceFrom(new google.maps.LatLng(y0,this.getPath().getAt(i).lng())); 122 var y2 = this.getPath().getAt(j).distanceFrom(new google.maps.LatLng(y0,this.getPath().getAt(j).lng())); 123 a += x1*y2 - x2*y1; 124 } 125 return Math.abs(a * 0.5); 126} 127 128// === A method which returns the length of a path in metres === 129google.maps.Polygon.prototype.Distance = function() { 130 var dist = 0; 131 for (var i=1; i < this.getPath().getLength(); i++) { 132 dist += this.getPath().getAt(i).distanceFrom(this.getPath().getAt(i-1)); 133 } 134 return dist; 135} 136 137// === A method which returns the bounds as a GLatLngBounds === 138google.maps.Polygon.prototype.Bounds = function() { 139 var bounds = new google.maps.LatLngBounds(); 140 for (var i=0; i < this.getPath().getLength(); i++) { 141 bounds.extend(this.getPath().getAt(i)); 142 } 143 return bounds; 144} 145 146// === A method which returns a GLatLng of a point a given distance along the path === 147// === Returns null if the path is shorter than the specified distance === 148google.maps.Polygon.prototype.GetPointAtDistance = function(metres) { 149 // some awkward special cases 150 if (metres == 0) return this.getPath().getAt(0); 151 if (metres < 0) return null; 152 if (this.getPath().getLength() < 2) return null; 153 var dist=0; 154 var olddist=0; 155 for (var i=1; (i < this.getPath().getLength() && dist < metres); i++) { 156 olddist = dist; 157 dist += this.getPath().getAt(i).distanceFrom(this.getPath().getAt(i-1)); 158 } 159 if (dist < metres) { 160 return null; 161 } 162 var p1= this.getPath().getAt(i-2); 163 var p2= this.getPath().getAt(i-1); 164 var m = (metres-olddist)/(dist-olddist); 165 return new google.maps.LatLng( p1.lat() + (p2.lat()-p1.lat())*m, p1.lng() + (p2.lng()-p1.lng())*m); 166} 167 168// === A method which returns an array of GLatLngs of points a given interval along the path === 169google.maps.Polygon.prototype.GetPointsAtDistance = function(metres) { 170 var next = metres; 171 var points = []; 172 // some awkward special cases 173 if (metres <= 0) return points; 174 var dist=0; 175 var olddist=0; 176 for (var i=1; (i < this.getPath().getLength()); i++) { 177 olddist = dist; 178 dist += this.getPath().getAt(i).distanceFrom(this.getPath().getAt(i-1)); 179 while (dist > next) { 180 var p1= this.getPath().getAt(i-1); 181 var p2= this.getPath().getAt(i); 182 var m = (next-olddist)/(dist-olddist); 183 points.push(new google.maps.LatLng( p1.lat() + (p2.lat()-p1.lat())*m, p1.lng() + (p2.lng()-p1.lng())*m)); 184 next += metres; 185 } 186 } 187 return points; 188} 189 190// === A method which returns the Vertex number at a given distance along the path === 191// === Returns null if the path is shorter than the specified distance === 192google.maps.Polygon.prototype.GetIndexAtDistance = function(metres) { 193 // some awkward special cases 194 if (metres == 0) return this.getPath().getAt(0); 195 if (metres < 0) return null; 196 var dist=0; 197 var olddist=0; 198 for (var i=1; (i < this.getPath().getLength() && dist < metres); i++) { 199 olddist = dist; 200 dist += this.getPath().getAt(i).distanceFrom(this.getPath().getAt(i-1)); 201 } 202 if (dist < metres) {return null;} 203 return i; 204} 205 206// === A function which returns the bearing between two vertices in decgrees from 0 to 360=== 207// === If v1 is null, it returns the bearing between the first and last vertex === 208// === If v1 is present but v2 is null, returns the bearing from v1 to the next vertex === 209// === If either vertex is out of range, returns void === 210google.maps.Polygon.prototype.Bearing = function(v1,v2) { 211 if (v1 == null) { 212 v1 = 0; 213 v2 = this.getPath().getLength()-1; 214 } else if (v2 == null) { 215 v2 = v1+1; 216 } 217 if ((v1 < 0) || (v1 >= this.getPath().getLength()) || (v2 < 0) || (v2 >= this.getPath().getLength())) { 218 return; 219 } 220 var from = this.getPath().getAt(v1); 221 var to = this.getPath().getAt(v2); 222 if (from.equals(to)) { 223 return 0; 224 } 225 var lat1 = from.latRadians(); 226 var lon1 = from.lngRadians(); 227 var lat2 = to.latRadians(); 228 var lon2 = to.lngRadians(); 229 var angle = - Math.atan2( Math.sin( lon1 - lon2 ) * Math.cos( lat2 ), Math.cos( lat1 ) * Math.sin( lat2 ) - Math.sin( lat1 ) * Math.cos( lat2 ) * Math.cos( lon1 - lon2 ) ); 230 if ( angle < 0.0 ) angle += Math.PI * 2.0; 231 angle = angle * 180.0 / Math.PI; 232 return parseFloat(angle.toFixed(1)); 233} 234 235// === Copy all the above functions to GPolyline === 236google.maps.Polyline.prototype.Contains = google.maps.Polygon.prototype.Contains; 237google.maps.Polyline.prototype.Area = google.maps.Polygon.prototype.Area; 238google.maps.Polyline.prototype.Distance = google.maps.Polygon.prototype.Distance; 239google.maps.Polyline.prototype.Bounds = google.maps.Polygon.prototype.Bounds; 240google.maps.Polyline.prototype.GetPointAtDistance = google.maps.Polygon.prototype.GetPointAtDistance; 241google.maps.Polyline.prototype.GetPointsAtDistance = google.maps.Polygon.prototype.GetPointsAtDistance; 242google.maps.Polyline.prototype.GetIndexAtDistance = google.maps.Polygon.prototype.GetIndexAtDistance; 243google.maps.Polyline.prototype.Bearing = google.maps.Polygon.prototype.Bearing; 244 245/* end epolys.js */ 246 247function CMMRM_RouteModel(data, waypointsString, locations, icon, polyline) { 248 this.polyline = polyline; 249 this.data = data; 250 this.waypointsString = (typeof waypointsString == 'string' ? waypointsString : ''); 251 this.waypointsCoords = []; 252 this.waypoints = []; 253 this.decodeWaypoints();
254 255 this.waypointsCoordsString = ''; 256 this.commaWaypoints(); 257 258 this.locations = []; 259 this.data.latlng = []; 260 this.data.latlngStr = ''; 261 this.data.latlngStrArr = []; 262 if(typeof this.data.path_waypoints !== 'undefined'){ 263 var datac; 264 // If Travel mode is "walking" 265 if ( typeof this.data.main_path_data !== 'undefined' && this.data.main_path_data.length > 0 ){ 266 try { 267 datac = JSON.parse(this.data.main_path_data); 268 for(var i = 0; i < datac.length; ++i){ 269 this.data.latlng.push(new google.maps.LatLng(datac[i]['lat'], datac[i]['lng'])); 270 } 271 } 272 catch(err) { 273 console.log('wrong JSON data') 274 } 275 // Else travel mode is "straight-line" 276 } else { 277 try { 278 datac = this.data.path_waypoints; 279 for(var i = 0; i < datac.length; ++i){ 280 this.data.latlng.push(new google.maps.LatLng(datac[i][0], datac[i][1])); 281 } 282 } 283 catch(err) { 284 console.log('wrong JSON data') 285 } 286 } 287 288 } 289 this.addLocations(locations); 290} 291 292CMMRM_RouteModel.prototype.addLocations = function(locations) { 293 if (typeof locations != 'undefined') { 294 for (var i=0; i<locations.length; i++) { 295 296 if (typeof this.polyline !== 'undefined' && this.polyline != '') { 297 var distance_ol = parseFloat(locations[i].distance * 1000); 298 var latng_ol = this.polyline.GetPointAtDistance(distance_ol); 299 locations[i].lat = latng_ol.lat(); 300 locations[i].lng = latng_ol.lng(); 301 } 302 303 this.addLocation(locations[i]); 304 } 305 } 306}; 307 308CMMRM_RouteModel.prototype.addLocation = function(locationData) { 309 var locationModel = new CMMRM_LocationModel(locationData, this); 310 var that = this; 311 this.locations.push(locationModel); 312 jQuery(this).trigger('RouteModel:addLocation', {locationData: locationData, locationModel: locationModel}); 313 jQuery(locationModel).bind('LocationModel:remove', function() { 314 that.removeLocationByModel(this); 315 }); 316 return locationModel; 317}; 318 319CMMRM_RouteModel.prototype.removeLocationByIndex = function(index) { 320 var removed = this.locations.splice(index, 1); 321 return (removed.length == 1); 322}; 323 324CMMRM_RouteModel.prototype.removeLocationByModel = function(obj) { 325 for (var i=0; i<this.locations.length; i++) { 326 if (this.locations[i] === obj) { 327 return this.removeLocationByIndex(i); 328 } 329 } 330 return false; 331}; 332 333CMMRM_RouteModel.prototype.addWaypoints = function(waypoints) { 334 var that = this; 335 for (var i=0; i<waypoints.length; i++) { 336 this.addWaypoint(waypoints[i]); 337 } 338 return this; 339}; 340 341CMMRM_RouteModel.prototype.removeWaypointByIndex = function(index) { 342 var removed = this.waypointsCoords.splice(index, 1); 343 return (removed.length == 1); 344}; 345 346CMMRM_RouteModel.prototype.removeWaypointByModel = function(obj) { 347 for (var i=0; i<this.waypoints.length; i++) { 348 if (this.waypoints[i] === obj) { 349 return this.removeWaypointByIndex(i); 350 } 351 } 352 return false; 353}; 354 355CMMRM_RouteModel.prototype.commaWaypoints = function() { 356 if (typeof this.waypointsString == 'string') { 357 this.waypointsCoordsString = this.waypointsString; 358 } else { 359 this.waypointsCoordsString = ''; 360 } 361 return this; 362}; 363 364CMMRM_RouteModel.prototype.decodeWaypoints = function() { 365 if (typeof this.waypointsString == 'string') { 366 this.waypointsCoords = google.maps.geometry.encoding.decodePath(this.waypointsString); 367 } else { 368 this.waypointsCoords = []; 369 } 370 return this; 371 //return this.addWaypoints(coords); 372}; 373 374CMMRM_RouteModel.prototype.addWaypoint = function(waypointData, index) { 375 if (Object.prototype.toString.call(waypointData) == '[object Array]') { 376 //waypointData = [waypointData.lat(), waypointData.lng()]; 377 waypointData = new google.maps.LatLng(waypointData[0], waypointData[1]); 378 } 379 380 if (typeof index == 'undefined') { 381 index = this.waypointsCoords.length; 382 this.waypointsCoords.push(waypointData); 383 } else { 384 this.waypointsCoords.splice(index, 0, waypointData); 385 } 386 387 jQuery(this).trigger('RouteModel:addWaypoint', {waypointData: waypointData}); 388 389 return this; 390}; 391 392CMMRM_RouteModel.prototype.getTravelMode = function() { 393 return this.data.travelMode; 394}; 395 396CMMRM_RouteModel.prototype.setTravelMode = function(mode) { 397 var old = this.data.travelMode; 398 this.data.travelMode = mode; 399 jQuery(this).trigger('RouteModel:setTravelMode', {old: old, travelMode: mode}); 400 return this; 401};
402 403CMMRM_RouteModel.prototype.getLocations = function() { 404 return this.locations; 405}; 406 407CMMRM_RouteModel.prototype.getWaypoints = function() { 408 return this.waypoints; 409}; 410 411CMMRM_RouteModel.prototype.getWaypointsString = function() { 412 return this.waypointsString; 413}; 414 415CMMRM_RouteModel.prototype.setWaypointsString = function(val) { 416 var old = this.waypointsString; 417 this.waypointsString = val; 418 jQuery(this).trigger('RouteModel:setWaypointsString', {old: old, waypointsString: val}); 419 return this; 420}; 421 422CMMRM_RouteModel.prototype.getWaypointsCoords = function() { 423 return this.waypointsCoords; 424}; 425 426CMMRM_RouteModel.prototype.getWaypointsGoogleLatLng = function() { 427 var coords = []; 428 for (var i=0; i<this.waypoints.length; i++) { 429 coords.push(this.waypoints[i].getGoogleLatLng()); 430 } 431 return coords; 432}; 433 434CMMRM_RouteModel.prototype.getWaypointsCoordsString = function() { 435 if(this.waypointsCoordsString != '') { 436 return this.waypointsCoordsString; 437 } else { 438 return this.data.overviewPath; 439 } 440}; 441 442CMMRM_RouteModel.prototype.getPolylineString = function() { 443 return this.data.overviewPath; 444}; 445 446CMMRM_RouteModel.prototype.setPolylineString = function(str) { 447 var old = this.data.overviewPath; 448 this.data.overviewPath = str; 449 jQuery(this).trigger('RouteModel:setPolylineString', {old: old, polylineString: str}); 450 return this; 451}; 452 453CMMRM_RouteModel.prototype.setLatLongList = function(str) { 454 this.data.latlng = str; 455 return this; 456}; 457 458CMMRM_RouteModel.prototype.getPolylineCoords = function() { 459 var str = this.getPolylineString(); 460 if (str) { 461 return google.maps.geometry.encoding.decodePath(str); 462 } else { 463 return []; 464 } 465}; 466 467CMMRM_RouteModel.prototype.getPathColor = function() { 468 return (this.data.pathColor ? this.data.pathColor : '#3377FF'); 469}; 470 471CMMRM_RouteModel.prototype.getSlopeDownwardColor = function() { 472 return (this.data.slopeDownwardColor ? this.data.slopeDownwardColor : '#3377FF'); 473}; 474 475CMMRM_RouteModel.prototype.getSlopeUpwardColor = function() { 476 return (this.data.slopeUpwardColor ? this.data.slopeUpwardColor : '#3377FF'); 477}; 478 479CMMRM_RouteModel.prototype.showDirectionalArrows = function() { 480 return this.data.showDirectionalArrows; 481}; 482 483CMMRM_RouteModel.prototype.getIcon = function() { 484 return null; 485}; 486 487CMMRM_RouteModel.prototype.getName = function() { 488 return this.data.name; 489}; 490 491CMMRM_RouteModel.prototype.getIcon = function() { 492 return this.data.icon; 493}; 494 495CMMRM_RouteModel.prototype.getLocationInfo = function() { 496 return this.data.infoContent; 497}; 498 499CMMRM_RouteModel.prototype.getBounds = function() { 500 var coords = []; 501 502 // Add waypoints 503 /* 504 var waypoints = this.getWaypoints(); 505 for (var i=0; i<waypoints.length; i++) { 506 coords.push(waypoints[i].getPosition()); 507 } 508 */ 509 510 // Add locations 511 var locations = this.getLocations(); 512 for (var i=0; i<locations.length; i++) { 513 coords.push(locations[i].getPosition()); 514 } 515 516 // Add polyline 517 var polyline = this.getPolylineCoords(); 518 for (var i=0; i<polyline.length; i++) { 519 coords.push(polyline[i]); 520 } 521 522 // Add default lat lng 523 var latLng = this.getGoogleLatLng(); 524 if (latLng) { 525 coords.push(latLng); 526 } 527 528 return coords; 529}; 530 531CMMRM_RouteModel.prototype.setRouteParam = function(name, val) { 532 var old = this.data[name]; 533 this.data[name] = val; 534 jQuery(this).trigger('RouteModel:setRouteParam', {name: name, old: old, value: val}); 535 return this; 536}; 537 538CMMRM_RouteModel.prototype.getRouteParam = function(name) { 539 return this.data[name]; 540}; 541 542CMMRM_RouteModel.prototype.updateWaypointsString = function() { 543 //var waypoints = this.getWaypointsCoords(); 544 if (google && google.maps && google.maps.geometry && google.maps.geometry.encoding) { 545 var coords = this.getWaypointsCoords(); 546 /* 547 for (var i=0; i<waypoints.length; i++) { 548 coords.push(new google.maps.LatLng(waypoints[i].getLat(), waypoints[i].getLng())); 549 } 550 */ 551 //console.log(coords); 552 var path = google.maps.geometry.encoding.encodePath(coords); 553 //console.log(path); 554 this.setWaypointsString(path); 555 } 556}; 557 558CMMRM_RouteModel.prototype.getGoogleLatLng = function() { 559 //console.log(this.data.lat, this.data.long); 560 if (this.data.lat && this.data.long) { 561 return new google.maps.LatLng(this.data.lat, this.data.long); 562 } 563}; 564 565CMMRM_RouteModel.prototype.getGoogleLatLngStr = function() { 566 //console.log(this.data.lat, this.data.long); 567 if (this.data.lat && this.data.long) { 568 return this.data.lat+"|"+this.data.long; 569 } 570}; 571 572CMMRM_RouteModel.prototype.showPathOutline = function() { 573 return this.data.showPathOutline; 574} 575 576CMMRM_RouteModel.prototype.isEmpty = function() { 577 return (this.locations.length == 0 && this.waypointsCoords.length == 0); 578}; 579 580CMMRM_RouteModel.prototype.isSlopesShowingEnabled = function() { 581 return this.data.isSlopesShowingEnabled; 582}; 583 584CMMRM_RouteModel.prototype.getSlopeMinValue = function() { 585 return this.data.slopeMinValue; 586}; 587 588CMMRM_RouteModel.prototype.getSlopeMinWidth = function() { 589 return this.data.slopeMinWidth; 590};
591 592CMMRM_RouteModel.prototype.getStartingPointCoords = function() { 593 return this.getGoogleLatLng(); 594 /* 595 var pathCoords = this.getWaypointsCoords(); 596 if ('path' == CMMRM_Map_Settings.startingPointMarker && pathCoords && pathCoords.length > 0) { 597 return pathCoords[0]; 598 } 599 var locations = this.getLocations(); 600 if (locations && locations.length > 0) { 601 return locations[0].getGoogleLatLng(); 602 } 603 */ 604};
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.