osrm-backend/Docs/WebFrontend/ViaRoute.js

342 lines
11 KiB
JavaScript
Raw Normal View History

2011-07-22 13:12:47 -04:00
/*
* Open Source Routing Machine (OSRM) - Web (GUI) Interface
* Copyright (C) Dennis Luxen, 2011
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU AFFERO General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* or see http://www.gnu.org/licenses/agpl.txt.
*/
/**
* Title: ViaRoute.js
* Description: JS file for routing with via points
*
* @author Dennis Luxen, luxen@kit.edu
* @version 0.1 June 2011
*
*/
//======================
// OBJECTS
//global timestamp to control frequency of mouse->route distance computations
var timestamp = (new Date()).getTime();
var ISCOMPUTINGDISTANCE = false;
var ISCALCULATINGVIA = false;
//var HASDELETEDTEMPORARYVIAROUTE = false;
var nearestPoint = new OpenLayers.Geometry.Point(1,1);
var nearestSegmentIndex = null;
var viaPointsVector = [];
var p0;
var temporaryViaStyle = {
fillColor: "#ffffff",
strokeColor: "#33ff33",
strokeOpacity: 0.6,
strokeWidth: 2,
pointRadius: 4,
pointerEvents: "visiblePainted"
};
var permanentViaStyle = {
fillColor: "#ffffff",
strokeColor: "#0033ff",
strokeOpacity: 0.6,
strokeWidth: 2,
pointRadius: 4,
pointerEvents: "visiblePainted"
};
//======================
//FUNCTIONS
function distanceBetweenPoint(x1, y1, x2, y2) {
var a = x1 - x2;
var b = y1 - y2;
return Math.sqrt(a*a + b*b);
}
/* Distance from a point to a line or segment.
x point's x coord
y point's y coord
x0 x coord of the line's A point
y0 y coord of the line's A point
x1 x coord of the line's B point
y1 y coord of the line's B point
o specifies if the distance should respect the limits of the segment
(overLine = true) or if it should consider the segment as an infinite
line (overLine = false), if false returns the distance from the point
to the line, otherwise the distance from the point to the segment
*/
function dotLineLength(x, y, x0, y0, x1, y1, o){
function lineLength(x, y, x0, y0){
return Math.sqrt((x -= x0) * x + (y -= y0) * y);
}
if(o && !(o = function(x, y, x0, y0, x1, y1){
if(!(x1 - x0)) return {x: x0, y: y};
else if(!(y1 - y0)) return {x: x, y: y0};
var left, tg = -1 / ((y1 - y0) / (x1 - x0));
return {x: left = (x1 * (x * tg - y + y0) + x0 * (x * - tg + y - y1)) / (tg * (x1 - x0) + y0 - y1), y: tg * left - tg * x + y};
}(x, y, x0, y0, x1, y1), o.x >= Math.min(x0, x1) && o.x <= Math.max(x0, x1) && o.y >= Math.min(y0, y1) && o.y <= Math.max(y0, y1))){
var l1 = lineLength(x, y, x0, y0), l2 = lineLength(x, y, x1, y1);
return l1 > l2 ? l2 : l1;
}
else {
var a = y0 - y1, b = x1 - x0, c = x0 * y1 - y0 * x1;
return Math.abs(a * x + b * y + c) / Math.sqrt(a * a + b * b);
}
};
function distanceToRoute(pixel) {
if(!isStartPointSet || !isEndPointSet){
return;
}
if(ISDRAGGING) {
return;
}
if(ISCOMPUTINGDISTANCE) {
return;
}
var tempTime = (new Date()).getTime()
if( tempTime - timestamp < 25) {
return;
}
timestamp = tempTime;
if(ISCALCULATING) {
var viaPointFeature = dragLayer.getFeatureBy("name", 'via');
if(viaPointFeature != null) {
dragLayer.removeFeatures(viaPointFeature);
viaPointFeature.destroy;
}
return;
}
if(pixel == null) {
pixel.x = window.event.clientX;
pixel.y = window.event.clientY;
}
var newLonLat = map.getLonLatFromPixel(pixel);
var minimumDist = 20*Math.pow(2,(19- this.map.getZoom()));
var minimumDistToVia = 20*Math.pow(2,(19- this.map.getZoom()));
var indexToInsertViaPoint = 0;
var startFeat = getMarkerByName('start');
var endFeat = getMarkerByName('end');
var from = new OpenLayers.LonLat(startFeat.geometry.x,startFeat.geometry.y).transform(EPSG_900913, EPSG_4326);
var to = new OpenLayers.LonLat(endFeat.geometry.x,endFeat.geometry.y).transform(EPSG_900913, EPSG_4326);
var mapExtent = map.getExtent();
for(var i = 0; i < allRoutePoints.length-1; i++) {
var p1 = allRoutePoints[i];
var p2 = allRoutePoints[i+1];
if(p1.x < mapExtent.left || p1.x > mapExtent.right || p1.y < mapExtent.bottom || p1.y > mapExtent.top) {
if(p2.x < mapExtent.left || p2.x > mapExtent.right || p2.y < mapExtent.bottom || p2.y > mapExtent.top) {
continue;
}
}
//check if previous segment is closest to via point
//if yes, then we have passed a via point.
if(viaPointsVector.length > indexToInsertViaPoint && p0) {
var viaPoint = new OpenLayers.LonLat(viaPointsVector[indexToInsertViaPoint][1],viaPointsVector[indexToInsertViaPoint][0]).transform(EPSG_4326, EPSG_900913);
var dist2 = dotLineLength(viaPoint.lon, viaPoint.lat, p1.x, p1.y, p0.x, p0.y, true)
if( 0 == dist2 ) {
indexToInsertViaPoint++;
}
var tmpDist = distanceBetweenPoint(viaPoint.lat, viaPoint.lon, newLonLat.lat, newLonLat.lon);
if(tmpDist < minimumDistToVia) {
minimumDistToVia = tmpDist;
}
}
//continue if point out of view
dist = dotLineLength(newLonLat.lon, newLonLat.lat, p1.x, p1.y, p2.x, p2.y, true);
if(dist <= minimumDist) {
nearestSegmentIndex = indexToInsertViaPoint;
minimumDist = dist;
var lonDiff = (p2.x - p1.x)
var m = (p2.y - p1.y) / lonDiff;
var b = p1.y - (m * p1.x);
var m2 = m*m;
var x = (m * newLonLat.lat + newLonLat.lon - m * b) / (m2 + 1);
var y = (m2 * newLonLat.lat + m * newLonLat.lon + b) / (m2 + 1);
var r = (x - p1.x) / lonDiff;
if ( r <= 1 && r >= 0 ) {
nearestPoint.x = x;
nearestPoint.y = y;
} else {
if( r < 0 ) {
nearestPoint.x = p1.x;
nearestPoint.y = p1.y;
} if ( r > 1 ) {
nearestPoint.x = p2.x;
nearestPoint.y = p2.y;
}
}
if(p2.x == p1.x) {
nearestPoint.x = p1.x;
nearestPoint.y = newLonLat.lat;
}
}
}
var zoomFactor = Math.pow(2,(19- this.map.getZoom()));
var viaPointFeature = dragLayer.getFeatureBy("name", 'via');
if(viaPointFeature != null) {
dragLayer.removeFeatures(viaPointFeature);
viaPointFeature.destroy;
}
//too close to start or destination?
if(Math.min(distanceBetweenPoint(startFeat.geometry.x, startFeat.geometry.y, newLonLat.lon, newLonLat.lat),
distanceBetweenPoint(endFeat.geometry.x, endFeat.geometry.y, newLonLat.lon, newLonLat.lat)) < 10*zoomFactor) {
ISCOMPUTINGDISTANCE = false;
return;
}
//Are we close to the route but sufficiently far away from any existing via point?
if(minimumDist < 10*zoomFactor && minimumDistToVia > 5*zoomFactor) {
viaPointFeature = new OpenLayers.Feature.Vector( OpenLayers.Geometry.Polygon.createRegularPolygon( nearestPoint, (1.5*zoomFactor), 15, 0 ), null, temporaryViaStyle );
viaPointFeature.name = "via";
dragLayer.addFeatures( viaPointFeature );
//console.log('nearestSegmentIndex: ' + nearestSegmentIndex);
}
ISCOMPUTINGDISTANCE = false;
p0 = p1;
}
function computeViaRoute(pixel, isTemporary, skipViaPointsIndex) {
if(ISCALCULATINGVIA && isTemporary)
return;
if( nearestSegmentIndex == null ) {
//console.log('nearestSegmentIndex: ' + nearestSegmentIndex);
return;
}
if(isTemporary == null) {
isTemporary = false;
}
//So, we jumped all fences
ISCALCULATINGVIA = true;
var startFeat = getMarkerByName('start');
var endFeat = getMarkerByName('end');
var from = new OpenLayers.LonLat(startFeat.geometry.x,startFeat.geometry.y).transform(EPSG_900913, EPSG_4326);
var to = new OpenLayers.LonLat(endFeat.geometry.x,endFeat.geometry.y).transform(EPSG_900913, EPSG_4326);
var coordinate = map.getLonLatFromPixel(pixel);
var via = coordinate.transform(EPSG_900913, EPSG_4326);
var viaNodeInserted = false;
2012-03-05 11:42:35 -05:00
var newURL = HOST_ROUTING_URL + "?loc="+from.lat + ',' + from.lon;
2011-07-22 13:12:47 -04:00
newURL += '&geomformat=cmp';
for(var i = 0; i < viaPointsVector.length; i++) {
if(i == nearestSegmentIndex) { //insert new via node here
2012-03-05 11:42:35 -05:00
newURL += '&loc=' + via.lat + ',' + via.lon;
2011-07-22 13:12:47 -04:00
viaNodeInserted = true;
}
if(skipViaPointsIndex == i)
continue;
2012-03-05 11:42:35 -05:00
newURL += '&loc=' + viaPointsVector[i][0] + ',' + viaPointsVector[i][1];
2011-07-22 13:12:47 -04:00
}
if(false == viaNodeInserted) {
2012-03-05 11:42:35 -05:00
newURL += '&loc=' + via.lat + ',' + via.lon;
2011-07-22 13:12:47 -04:00
}
2012-03-05 11:42:35 -05:00
newURL += '&loc=' + to.lat + ',' + to.lon;
2011-07-22 13:12:47 -04:00
newURL += '&output=json' + '&z=' + this.map.getZoom();
if(!isTemporary) {
newURL += '&instructions=true&jsonp=showResultsRoute';
} else {
newURL += '&instructions=false&jsonp=showResultsViaRoute';
}
//console.log(newURL);
var script = document.createElement('script');
script.id = 'JSONP';
script.type = 'application/javascript';
script.src = newURL;
document.body.appendChild(script);
}
function showResultsViaRoute(response) {
if (response) {
var viaRouteVector = [];
    // now with compression of the route geometry
       var geometry = decodeRouteGeometry(response.route_geometry, 5);
      var lengthOfArray = geometry.length;
       var points = [];
       points.length = lengthOfArray;
       //Create Route Layer for Display
       for (var i = 0; i < lengthOfArray; i++) {
           var point = new OpenLayers.Geometry.Point(geometry[i][1], geometry[i][0]).transform(EPSG_4326, EPSG_900913);
           allRoutePoints.push(point);
points.push(point);
           
if(i % 1024 == 0 && i>0 || i==lengthOfArray-1){
/* var feature1 = new OpenLayers.Feature.Vector(new OpenLayers.Geometry.LineString(points), null, {
strokeColor: "#006600",
strokeOpacity: 1,
strokeWidth: 9
});
*/
var feature = new OpenLayers.Feature.Vector(new OpenLayers.Geometry.LineString(points), null, {
strokeColor: "#aaffaa",
strokeOpacity: 0.8,
strokeWidth: 7
});
// viaRouteVector.push(feature1);
viaRouteVector.push(feature);
points = [];
points.push(point);
}
       }
vectorLayerViaRoute.removeFeatures(vectorLayerViaRoute.features);
for(var i = 0; i< viaRouteVector.length; i++) {
vectorLayerViaRoute.addFeatures(viaRouteVector[i]);
}
viaRouteVector.length = 0;
ISCALCULATINGVIA = false;
}
}
function paintViaPoints() {
//remove all previous via points
var featuresToRemove = [];
for(var i = 0; i < dragLayer.features.length; i++) {
if(dragLayer.features[i].name == "viapoint" || "via" == dragLayer.features[i].name ) {
featuresToRemove.push(dragLayer.features[i]);
}
}
dragLayer.removeFeatures(featuresToRemove);
featuresToRemove.length = 0;
//paint all via points
var zoomFactor = Math.pow(2,(19- this.map.getZoom()));
//console.log('painting ' + viaPointsVector.length + ' via points');
for(var i = 0; i < viaPointsVector.length; i++) {
//console.log(viaPointsVector[i]);
var viapoint = new OpenLayers.Geometry.Point(
viaPointsVector[i][1],
viaPointsVector[i][0]);
viapoint.transform(EPSG_4326, EPSG_900913);
var viaPointFeature = new OpenLayers.Feature.Vector( OpenLayers.Geometry.Polygon.createRegularPolygon( viapoint, (1.5*zoomFactor), 20, 0 ), null, permanentViaStyle );
viaPointFeature.name = "viapoint";
viaPointFeature.viaIndex = i;
dragLayer.addFeatures( viaPointFeature )
}
}