From 2d5d1f4a293b50c689fcec8f1606e0f58f588522 Mon Sep 17 00:00:00 2001 From: Dennis Luxen Date: Fri, 22 Jul 2011 17:12:47 +0000 Subject: [PATCH] ViaRoute Javascript --- Docs/WebFrontend/MouseClick.js | 115 +++++++++++ Docs/WebFrontend/ViaRoute.js | 340 +++++++++++++++++++++++++++++++++ Docs/WebFrontend/index.html | 6 +- 3 files changed, 458 insertions(+), 3 deletions(-) create mode 100644 Docs/WebFrontend/MouseClick.js create mode 100644 Docs/WebFrontend/ViaRoute.js diff --git a/Docs/WebFrontend/MouseClick.js b/Docs/WebFrontend/MouseClick.js new file mode 100644 index 000000000..855d32fe9 --- /dev/null +++ b/Docs/WebFrontend/MouseClick.js @@ -0,0 +1,115 @@ +var selectedFeature = null; +var popupCloseTimer = null; +var popupToRemove = null; + +function rightClick(e) { + console.log("right click1"); + if(null == selectedFeature) + return; + //alert('rightclick at '+e.xy.x+','+e.xy.y); + console.log("right click2"); +} + +function dblClick(e) { + //alert('dblclick at '+e.xy.x+','+e.xy.y); +} + +function dblRightClick(e) { + //alert('dblrightclick at '+e.xy.x+','+e.xy.y); +} + +function leftClick(e) { + //set start and target via clicks + var lonlat = map.getLonLatFromViewPortPx(e.xy); + var markername = ""; + +/* //routing shall not be done by left clicks + * if (e.ctrlKey || e.altKey) { + markername = "end"; + isEndPointSet = true; + } else if(e.shiftKey) { + markername = "start"; + isStartPointSet = true; + } + for(var i= 0; i', + null, + false, + destroyPopup ); + feature.popup.backgroundColor = 'transparent'; + feature.popup.fixedRelativePosition = true; + feature.popup.relativePosition = "tr"; + map.addPopup(feature.popup, true); +} + +function destroyPopup(feature) { + if(feature.popup) { + popupToRemove = feature.popup; + popupCloseTimer = setTimeout("removePopup()",2000); + } +} + +function removePopup() { + if(null == popupToRemove) + return; + + map.removePopup(popupToRemove); + popupToRemove = null; + popupCloseTimer = null; +} + +function removeViaPoint(index) { + for(var i = 0; i < map.popups.length; i++) { + map.removePopup(map.popups[i]); + } + viaPointsVector.splice(index, 1); + reroute(); +} diff --git a/Docs/WebFrontend/ViaRoute.js b/Docs/WebFrontend/ViaRoute.js new file mode 100644 index 000000000..8a2b09861 --- /dev/null +++ b/Docs/WebFrontend/ViaRoute.js @@ -0,0 +1,340 @@ +/* + * 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; + var newURL = HOST_ROUTING_URL + "&start="+from.lat + ',' + from.lon + '&dest=' + to.lat + ',' + to.lon; + newURL += '&geomformat=cmp'; + for(var i = 0; i < viaPointsVector.length; i++) { + if(i == nearestSegmentIndex) { //insert new via node here + newURL += '&via=' + via.lat + ',' + via.lon; + viaNodeInserted = true; + } + if(skipViaPointsIndex == i) + continue; + newURL += '&via=' + viaPointsVector[i][0] + ',' + viaPointsVector[i][1]; + } + if(false == viaNodeInserted) { + newURL += '&via=' + via.lat + ',' + via.lon; + } + 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 ) + } +} diff --git a/Docs/WebFrontend/index.html b/Docs/WebFrontend/index.html index 1d699d08c..4f7606158 100644 --- a/Docs/WebFrontend/index.html +++ b/Docs/WebFrontend/index.html @@ -34,7 +34,7 @@ -
+