Filtering of geometry details by zoom level

This commit is contained in:
Dennis Luxen 2011-05-10 10:24:13 +00:00
parent 5642dc00e1
commit 9de3a5a586
5 changed files with 177 additions and 96 deletions

View File

@ -28,6 +28,7 @@ or see http://www.gnu.org/licenses/agpl.txt.
#include "../typedefs.h" #include "../typedefs.h"
#include "../DataStructures/ExtractorStructs.h" #include "../DataStructures/ExtractorStructs.h"
#include "../DataStructures/HashTable.h"
#include "../Util/StrIngUtil.h" #include "../Util/StrIngUtil.h"
template<class SearchEngineT> template<class SearchEngineT>
@ -37,6 +38,7 @@ public:
//Maybe someone can explain the pure virtual destructor thing to me (dennis) //Maybe someone can explain the pure virtual destructor thing to me (dennis)
virtual ~BaseDescriptor() { } virtual ~BaseDescriptor() { }
virtual void Run(http::Reply& reply, std::vector< _PathData > * path, PhantomNodes * phantomNodes, SearchEngineT * sEngine, unsigned distance) = 0; virtual void Run(http::Reply& reply, std::vector< _PathData > * path, PhantomNodes * phantomNodes, SearchEngineT * sEngine, unsigned distance) = 0;
virtual void SetZoom(const unsigned short z) = 0;
}; };

View File

@ -23,9 +23,20 @@ or see http://www.gnu.org/licenses/agpl.txt.
#ifndef JSONDESCRIPTOR_H_ #ifndef JSONDESCRIPTOR_H_
#define JSONDESCRIPTOR_H_ #define JSONDESCRIPTOR_H_
static double areaThresholds[19] = { 5000, 5000, 5000, 5000, 5000, 2500, 2000, 1500, 800, 400, 250, 150, 100, 75, 25, 20, 10, 5 };
template<class SearchEngineT, bool SimplifyRoute = false> template<class SearchEngineT, bool SimplifyRoute = false>
class JSONDescriptor : public BaseDescriptor<SearchEngineT> { class JSONDescriptor : public BaseDescriptor<SearchEngineT> {
private:
short zoom;
public: public:
JSONDescriptor() : zoom(18) {}
void SetZoom(const unsigned short z) {
if(z > 18)
zoom = 18;
zoom = z;
}
void Run(http::Reply& reply, std::vector< _PathData > * path, PhantomNodes * phantomNodes, SearchEngineT * sEngine, unsigned distance) { void Run(http::Reply& reply, std::vector< _PathData > * path, PhantomNodes * phantomNodes, SearchEngineT * sEngine, unsigned distance) {
string tmp; string tmp;
string routeGeometryString; string routeGeometryString;
@ -40,19 +51,22 @@ public:
unsigned durationOfInstruction = 0; unsigned durationOfInstruction = 0;
double lastAngle = 0.; double lastAngle = 0.;
reply.content += ("{\n"); unsigned painted = 0;
reply.content += (" \"version\":0.3,\n"); unsigned omitted = 0;
reply.content += ("{");
reply.content += ("\"version\":0.3,");
if(distance != UINT_MAX) { if(distance != UINT_MAX) {
reply.content += (" \"status\":0,\n"); reply.content += ("\"status\":0,");
reply.content += (" \"status_message\":"); reply.content += ("\"status_message\":");
reply.content += "\"Found route between points\",\n"; reply.content += "\"Found route between points\",";
unsigned streetID = sEngine->GetNameIDForOriginDestinationNodeID(phantomNodes->startNode1, phantomNodes->startNode2); unsigned streetID = sEngine->GetNameIDForOriginDestinationNodeID(phantomNodes->startNode1, phantomNodes->startNode2);
startPointName = sEngine->GetNameForNameID(streetID); startPointName = sEngine->GetEscapedNameForNameID(streetID);
streetID = sEngine->GetNameIDForOriginDestinationNodeID(phantomNodes->targetNode1, phantomNodes->targetNode2); streetID = sEngine->GetNameIDForOriginDestinationNodeID(phantomNodes->targetNode1, phantomNodes->targetNode2);
endPointName = sEngine->GetNameForNameID(streetID); endPointName = sEngine->GetEscapedNameForNameID(streetID);
routeInstructionString += " [\"Head "; routeInstructionString += "[\"Head ";
_Coordinate tmpCoord; _Coordinate tmpCoord;
if(path->size() > 0) if(path->size() > 0)
sEngine->getNodeInfo(path->begin()->node, tmpCoord); sEngine->getNodeInfo(path->begin()->node, tmpCoord);
@ -93,12 +107,12 @@ public:
//put start coord to linestring; //put start coord to linestring;
convertLatLon(phantomNodes->startCoord.lat, tmp); convertLatLon(phantomNodes->startCoord.lat, tmp);
routeGeometryString += " ["; routeGeometryString += "[";
routeGeometryString += tmp; routeGeometryString += tmp;
routeGeometryString += ", "; routeGeometryString += ", ";
convertLatLon(phantomNodes->startCoord.lon, tmp); convertLatLon(phantomNodes->startCoord.lon, tmp);
routeGeometryString += tmp; routeGeometryString += tmp;
routeGeometryString += "],\n"; routeGeometryString += "],";
position++; position++;
_Coordinate previous(phantomNodes->startCoord.lat, phantomNodes->startCoord.lon); _Coordinate previous(phantomNodes->startCoord.lat, phantomNodes->startCoord.lon);
@ -132,16 +146,21 @@ public:
durationOfInstruction += sEngine->GetWeightForOriginDestinationNodeID(it->node, (it+1)->node); durationOfInstruction += sEngine->GetWeightForOriginDestinationNodeID(it->node, (it+1)->node);
} }
double angle = GetAngleBetweenTwoEdges(startOfSegment, current, next); double angle = GetAngleBetweenTwoEdges(startOfSegment, current, next);
if(178 > angle || 182 < angle || false == SimplifyRoute) { double area = fabs(0.5*( startOfSegment.lon*(current.lat - next.lat) + current.lon*(next.lat - startOfSegment.lat) + next.lon*(startOfSegment.lat - current.lat) ) );
// std::cout << "Area for: " << area << std::endl;
if(area > areaThresholds[zoom] || false == SimplifyRoute) {
painted++;
convertLatLon(current.lat, tmp); convertLatLon(current.lat, tmp);
routeGeometryString += " ["; routeGeometryString += "[";
routeGeometryString += tmp; routeGeometryString += tmp;
routeGeometryString += ", "; routeGeometryString += ", ";
convertLatLon(current.lon, tmp); convertLatLon(current.lon, tmp);
routeGeometryString += tmp; routeGeometryString += tmp;
routeGeometryString += "],\n"; routeGeometryString += "],";
position++; position++;
startOfSegment = current; startOfSegment = current;
} else {
omitted++;
} }
if(nextID == nameID) { if(nextID == nameID) {
tempDist += ApproximateDistance(previous.lat, previous.lon, current.lat, current.lon); tempDist += ApproximateDistance(previous.lat, previous.lon, current.lat, current.lon);
@ -152,7 +171,7 @@ public:
routeInstructionString += ",leave motorway and "; routeInstructionString += ",leave motorway and ";
routeInstructionString += " on "; routeInstructionString += " on ";
if(nameID != 0) if(nameID != 0)
routeInstructionString += sEngine->GetNameForNameID(nameID); routeInstructionString += sEngine->GetEscapedNameForNameID(nameID);
routeInstructionString += "\","; routeInstructionString += "\",";
distanceOfInstruction += ApproximateDistance(previous.lat, previous.lon, current.lat, current.lon)+tempDist; distanceOfInstruction += ApproximateDistance(previous.lat, previous.lon, current.lat, current.lon)+tempDist;
entireDistance += distanceOfInstruction; entireDistance += distanceOfInstruction;
@ -178,13 +197,13 @@ public:
numberString.str(""); numberString.str("");
numberString << fixed << setprecision(2) << lastAngle; numberString << fixed << setprecision(2) << lastAngle;
routeInstructionString += numberString.str(); routeInstructionString += numberString.str();
routeInstructionString += "],\n"; routeInstructionString += "],";
string lat; string lon; string lat; string lon;
convertLatLon(lastPlace.lon, lon); convertLatLon(lastPlace.lon, lon);
convertLatLon(lastPlace.lat, lat); convertLatLon(lastPlace.lat, lat);
lastPlace = current; lastPlace = current;
routeInstructionString += " [\""; routeInstructionString += "[\"";
if(angle > 160 && angle < 200) { if(angle > 160 && angle < 200) {
routeInstructionString += /* " (" << angle << ")*/"Continue"; routeInstructionString += /* " (" << angle << ")*/"Continue";
@ -214,7 +233,7 @@ public:
type = sEngine->GetTypeOfEdgeForOriginDestinationNodeID(phantomNodes->targetNode1, phantomNodes->targetNode2); type = sEngine->GetTypeOfEdgeForOriginDestinationNodeID(phantomNodes->targetNode1, phantomNodes->targetNode2);
durationOfInstruction += sEngine->GetWeightForOriginDestinationNodeID(phantomNodes->targetNode1, phantomNodes->targetNode2); durationOfInstruction += sEngine->GetWeightForOriginDestinationNodeID(phantomNodes->targetNode1, phantomNodes->targetNode2);
routeInstructionString += " at "; routeInstructionString += " at ";
routeInstructionString += sEngine->GetNameForNameID(nameID); routeInstructionString += sEngine->GetEscapedNameForNameID(nameID);
routeInstructionString += "\","; routeInstructionString += "\",";
distanceOfInstruction = ApproximateDistance(previous.lat, previous.lon, phantomNodes->targetCoord.lat, phantomNodes->targetCoord.lon) + tempDist; distanceOfInstruction = ApproximateDistance(previous.lat, previous.lon, phantomNodes->targetCoord.lat, phantomNodes->targetCoord.lon) + tempDist;
entireDistance += distanceOfInstruction; entireDistance += distanceOfInstruction;
@ -239,58 +258,58 @@ public:
numberString.str(""); numberString.str("");
numberString << fixed << setprecision(2) << lastAngle; numberString << fixed << setprecision(2) << lastAngle;
routeInstructionString += numberString.str(); routeInstructionString += numberString.str();
routeInstructionString += "]\n"; routeInstructionString += "]";
string lat; string lon; string lat; string lon;
//put targetCoord to linestring //put targetCoord to linestring
convertLatLon(phantomNodes->targetCoord.lat, tmp); convertLatLon(phantomNodes->targetCoord.lat, tmp);
routeGeometryString += " ["; routeGeometryString += "[";
routeGeometryString += tmp; routeGeometryString += tmp;
routeGeometryString += ", "; routeGeometryString += ", ";
convertLatLon(phantomNodes->targetCoord.lon, tmp); convertLatLon(phantomNodes->targetCoord.lon, tmp);
routeGeometryString += tmp; routeGeometryString += tmp;
routeGeometryString += "]\n"; routeGeometryString += "]";
position++; position++;
//give complete distance in meters; //give complete distance in meters;
ostringstream s; ostringstream s;
s << 10*(round(entireDistance/10.)); s << 10*(round(entireDistance/10.));
routeSummaryString += " \"total_distance\":"; routeSummaryString += "\"total_distance\":";
routeSummaryString += s.str(); routeSummaryString += s.str();
routeSummaryString += ",\n \"total_time\":"; routeSummaryString += ",\"total_time\":";
//give travel time in minutes //give travel time in minutes
int travelTime = distance; int travelTime = distance;
s.str(""); s.str("");
s << travelTime; s << travelTime;
routeSummaryString += s.str(); routeSummaryString += s.str();
routeSummaryString += ",\n \"start_point\":\""; routeSummaryString += ",\"start_point\":\"";
routeSummaryString += startPointName; routeSummaryString += startPointName;
routeSummaryString += "\",\n \"end_point\":\""; routeSummaryString += "\",\"end_point\":\"";
routeSummaryString += endPointName; routeSummaryString += endPointName;
routeSummaryString += "\"\n"; routeSummaryString += "\"";
} else { } else {
reply.content += (" \"status\":207,\n"); reply.content += ("\"status\":207,");
reply.content += (" \"status_message\":"); reply.content += ("\"status_message\":");
reply.content += "\"Cannot find route between points\",\n"; reply.content += "\"Cannot find route between points\",";
routeSummaryString += " \"total_distance\":0"; routeSummaryString += "\"total_distance\":0";
routeSummaryString += ",\n \"total_time\":0"; routeSummaryString += ",\"total_time\":0";
routeSummaryString += ",\n \"start_point\":\""; routeSummaryString += ",\"start_point\":\"";
routeSummaryString += "\",\n \"end_point\":\""; routeSummaryString += "\",\"end_point\":\"";
routeSummaryString += "\"\n"; routeSummaryString += "\"";
} }
reply.content += " \"route_summary\": {\n"; reply.content += "\"route_summary\": {";
reply.content += routeSummaryString; reply.content += routeSummaryString;
reply.content += " },\n"; reply.content += "},";
reply.content += " \"route_geometry\": [\n"; reply.content += "\"route_geometry\": [";
reply.content += routeGeometryString; reply.content += routeGeometryString;
reply.content += " ],\n"; reply.content += "],";
reply.content += " \"route_instructions\": [\n"; reply.content += "\"route_instructions\": [";
reply.content += routeInstructionString; reply.content += routeInstructionString;
reply.content += " ],\n"; reply.content += "],";
reply.content += " \"transactionId\": \"OSRM Routing Engine JSON Descriptor (beta)\"\n"; reply.content += "\"transactionId\": \"OSRM Routing Engine JSON Descriptor (beta)\"";
reply.content += "}"; reply.content += "}";
//std::cout << "zoom: " << zoom << ", threshold: " << areaThresholds[zoom] << ", painted: " << painted << ", omitted: " << omitted << std::endl;
} }
private:
}; };
#endif /* JSONDESCRIPTOR_H_ */ #endif /* JSONDESCRIPTOR_H_ */

View File

@ -24,6 +24,7 @@ or see http://www.gnu.org/licenses/agpl.txt.
template<class SearchEngineT, bool SimplifyRoute = false> template<class SearchEngineT, bool SimplifyRoute = false>
class KMLDescriptor : public BaseDescriptor<SearchEngineT>{ class KMLDescriptor : public BaseDescriptor<SearchEngineT>{
public: public:
void SetZoom(const unsigned short z) { }
void Run(http::Reply& reply, std::vector< _PathData > * path, PhantomNodes * phantomNodes, SearchEngineT * sEngine, unsigned distance) { void Run(http::Reply& reply, std::vector< _PathData > * path, PhantomNodes * phantomNodes, SearchEngineT * sEngine, unsigned distance) {
string tmp; string tmp;
string lineString; string lineString;

View File

@ -25,8 +25,9 @@ or see http://www.gnu.org/licenses/agpl.txt.
#include "BasePlugin.h" #include "BasePlugin.h"
#include "RouteParameters.h" #include "RouteParameters.h"
#include "../DataStructures/NodeInformationHelpDesk.h" #include "../DataStructures/NodeInformationHelpDesk.h"
#include "../DataStructures/HashTable.h"
#include "../Util/StrIngUtil.h"
/* /*
* This Plugin locates the nearest point on a street in the road network for a given coordinate. * This Plugin locates the nearest point on a street in the road network for a given coordinate.
@ -37,6 +38,9 @@ public:
nodeHelpDesk = new NodeInformationHelpDesk(ramIndexPath.c_str(), fileIndexPath.c_str()); nodeHelpDesk = new NodeInformationHelpDesk(ramIndexPath.c_str(), fileIndexPath.c_str());
ifstream nodesInStream(nodesPath.c_str(), ios::binary); ifstream nodesInStream(nodesPath.c_str(), ios::binary);
nodeHelpDesk->initNNGrid(nodesInStream); nodeHelpDesk->initNNGrid(nodesInStream);
descriptorTable.Set("", 0); //default descriptor
descriptorTable.Set("kml", 0);
descriptorTable.Set("json", 1);
} }
~NearestPlugin() { ~NearestPlugin() {
delete nodeHelpDesk; delete nodeHelpDesk;
@ -60,20 +64,66 @@ public:
//query to helpdesk //query to helpdesk
_Coordinate result; _Coordinate result;
nodeHelpDesk->FindNearestPointOnEdge(_Coordinate(lat, lon), result); nodeHelpDesk->FindNearestPointOnEdge(_Coordinate(lat, lon), result);
unsigned descriptorType = descriptorTable[routeParameters.options.Find("output")];
std::stringstream out1;
std::stringstream out2;
std::string tmp;
std::string JSONParameter;
switch(descriptorType){
case 1:
//json
JSONParameter = routeParameters.options.Find("jsonp");
if("" != JSONParameter) {
reply.content += JSONParameter;
reply.content += "(\n";
}
reply.status = http::Reply::ok;
reply.content += ("{");
reply.content += ("\"version\":0.3,");
reply.content += ("\"status\":0,");
reply.content += ("\"status_message\":");
out1 << setprecision(10);
out1 << "\"Nearest Place in map to " << lat/100000. << "," << lon/100000. << "\",";
reply.content.append(out1.str());
reply.content += ("\"coordinate\": ");
out2 << setprecision(10);
out2 << "[" << result.lat / 100000. << "," << result.lon / 100000. << "]";
reply.content.append(out2.str());
reply.content += ("}");
reply.headers.resize(3);
reply.headers[0].name = "Content-Length";
intToString(reply.content.size(), tmp);
reply.headers[0].value = tmp;if("" != JSONParameter) {
reply.content += ")\n";
reply.headers[1].name = "Content-Type";
reply.headers[1].value = "text/javascript";
reply.headers[2].name = "Content-Disposition";
reply.headers[2].value = "attachment; filename=\"location.js\"";
} else {
reply.headers[1].name = "Content-Type";
reply.headers[1].value = "application/x-javascript";
reply.headers[2].name = "Content-Disposition";
reply.headers[2].value = "attachment; filename=\"location.json\"";
}
break;
default:
reply.status = http::Reply::ok;
//Write to stream //Write to stream
reply.status = http::Reply::ok;
reply.content.append("<?xml version=\"1.0\" encoding=\"UTF-8\"?>"); reply.content.append("<?xml version=\"1.0\" encoding=\"UTF-8\"?>");
reply.content.append("<kml xmlns=\"http://www.opengis.net/kml/2.2\">"); reply.content.append("<kml xmlns=\"http://www.opengis.net/kml/2.2\">");
reply.content.append("<Placemark>"); reply.content.append("<Placemark>");
std::stringstream out1;
out1 << setprecision(10); out1 << setprecision(10);
out1 << "<name>Nearest Place in map to " << lat/100000. << "," << lon/100000. << "</name>"; out1 << "<name>Nearest Place in map to " << lat/100000. << "," << lon/100000. << "</name>";
reply.content.append(out1.str()); reply.content.append(out1.str());
reply.content.append("<Point>"); reply.content.append("<Point>");
std::stringstream out2;
out2 << setprecision(10); out2 << setprecision(10);
out2 << "<coordinates>" << result.lon / 100000. << "," << result.lat / 100000. << "</coordinates>"; out2 << "<coordinates>" << result.lon / 100000. << "," << result.lat / 100000. << "</coordinates>";
reply.content.append(out2.str()); reply.content.append(out2.str());
@ -88,10 +138,12 @@ public:
reply.headers[1].value = "application/vnd.google-earth.kml+xml"; reply.headers[1].value = "application/vnd.google-earth.kml+xml";
reply.headers[2].name = "Content-Disposition"; reply.headers[2].name = "Content-Disposition";
reply.headers[2].value = "attachment; filename=\"placemark.kml\""; reply.headers[2].value = "attachment; filename=\"placemark.kml\"";
return; break;
}
} }
private: private:
NodeInformationHelpDesk * nodeHelpDesk; NodeInformationHelpDesk * nodeHelpDesk;
HashTable<std::string, unsigned> descriptorTable;
}; };
#endif /* NearestPlugin_H_ */ #endif /* NearestPlugin_H_ */

View File

@ -21,6 +21,7 @@ or see http://www.gnu.org/licenses/agpl.txt.
#ifndef ROUTEPLUGIN_H_ #ifndef ROUTEPLUGIN_H_
#define ROUTEPLUGIN_H_ #define ROUTEPLUGIN_H_
#include <cstdlib>
#include <fstream> #include <fstream>
#include <sstream> #include <sstream>
#include <string> #include <string>
@ -127,6 +128,12 @@ public:
} }
unsigned descriptorType = descriptorTable[routeParameters.options.Find("output")]; unsigned descriptorType = descriptorTable[routeParameters.options.Find("output")];
const bool simplifiedRoute = (routeParameters.options.Find("simplified") == "yes"); const bool simplifiedRoute = (routeParameters.options.Find("simplified") == "yes");
unsigned short zoom;
if(routeParameters.options.Find("z") != ""){
zoom = atoi(routeParameters.options.Find("z").c_str());
if(18 < zoom)
zoom = 18;
}
//todo: put options in a seperate struct and pass it to the descriptor //todo: put options in a seperate struct and pass it to the descriptor
switch(descriptorType){ switch(descriptorType){
case 0: case 0:
@ -148,7 +155,7 @@ public:
desc = new KMLDescriptor<SearchEngine<EdgeData, StaticGraph<EdgeData> >, false >(); desc = new KMLDescriptor<SearchEngine<EdgeData, StaticGraph<EdgeData> >, false >();
break; break;
} }
desc->SetZoom(zoom);
desc->Run(reply, path, phantomNodes, sEngine, distance); desc->Run(reply, path, phantomNodes, sEngine, distance);
if("" != JSONParameter) { if("" != JSONParameter) {
reply.content += ")\n"; reply.content += ")\n";
@ -175,7 +182,7 @@ public:
reply.headers[2].value = "attachment; filename=\"route.js\""; reply.headers[2].value = "attachment; filename=\"route.js\"";
} else { } else {
reply.headers[1].name = "Content-Type"; reply.headers[1].name = "Content-Type";
reply.headers[1].value = "application/json"; reply.headers[1].value = "application/x-javascript";
reply.headers[2].name = "Content-Disposition"; reply.headers[2].name = "Content-Disposition";
reply.headers[2].value = "attachment; filename=\"route.json\""; reply.headers[2].value = "attachment; filename=\"route.json\"";
} }