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 "../DataStructures/ExtractorStructs.h"
#include "../DataStructures/HashTable.h"
#include "../Util/StrIngUtil.h"
template<class SearchEngineT>
@ -37,6 +38,7 @@ public:
//Maybe someone can explain the pure virtual destructor thing to me (dennis)
virtual ~BaseDescriptor() { }
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_
#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>
class JSONDescriptor : public BaseDescriptor<SearchEngineT> {
private:
short zoom;
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) {
string tmp;
string routeGeometryString;
@ -40,19 +51,22 @@ public:
unsigned durationOfInstruction = 0;
double lastAngle = 0.;
reply.content += ("{\n");
reply.content += (" \"version\":0.3,\n");
unsigned painted = 0;
unsigned omitted = 0;
reply.content += ("{");
reply.content += ("\"version\":0.3,");
if(distance != UINT_MAX) {
reply.content += (" \"status\":0,\n");
reply.content += (" \"status_message\":");
reply.content += "\"Found route between points\",\n";
reply.content += ("\"status\":0,");
reply.content += ("\"status_message\":");
reply.content += "\"Found route between points\",";
unsigned streetID = sEngine->GetNameIDForOriginDestinationNodeID(phantomNodes->startNode1, phantomNodes->startNode2);
startPointName = sEngine->GetNameForNameID(streetID);
startPointName = sEngine->GetEscapedNameForNameID(streetID);
streetID = sEngine->GetNameIDForOriginDestinationNodeID(phantomNodes->targetNode1, phantomNodes->targetNode2);
endPointName = sEngine->GetNameForNameID(streetID);
endPointName = sEngine->GetEscapedNameForNameID(streetID);
routeInstructionString += " [\"Head ";
routeInstructionString += "[\"Head ";
_Coordinate tmpCoord;
if(path->size() > 0)
sEngine->getNodeInfo(path->begin()->node, tmpCoord);
@ -93,12 +107,12 @@ public:
//put start coord to linestring;
convertLatLon(phantomNodes->startCoord.lat, tmp);
routeGeometryString += " [";
routeGeometryString += "[";
routeGeometryString += tmp;
routeGeometryString += ", ";
convertLatLon(phantomNodes->startCoord.lon, tmp);
routeGeometryString += tmp;
routeGeometryString += "],\n";
routeGeometryString += "],";
position++;
_Coordinate previous(phantomNodes->startCoord.lat, phantomNodes->startCoord.lon);
@ -132,16 +146,21 @@ public:
durationOfInstruction += sEngine->GetWeightForOriginDestinationNodeID(it->node, (it+1)->node);
}
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);
routeGeometryString += " [";
routeGeometryString += "[";
routeGeometryString += tmp;
routeGeometryString += ", ";
convertLatLon(current.lon, tmp);
routeGeometryString += tmp;
routeGeometryString += "],\n";
routeGeometryString += "],";
position++;
startOfSegment = current;
} else {
omitted++;
}
if(nextID == nameID) {
tempDist += ApproximateDistance(previous.lat, previous.lon, current.lat, current.lon);
@ -152,7 +171,7 @@ public:
routeInstructionString += ",leave motorway and ";
routeInstructionString += " on ";
if(nameID != 0)
routeInstructionString += sEngine->GetNameForNameID(nameID);
routeInstructionString += sEngine->GetEscapedNameForNameID(nameID);
routeInstructionString += "\",";
distanceOfInstruction += ApproximateDistance(previous.lat, previous.lon, current.lat, current.lon)+tempDist;
entireDistance += distanceOfInstruction;
@ -178,13 +197,13 @@ public:
numberString.str("");
numberString << fixed << setprecision(2) << lastAngle;
routeInstructionString += numberString.str();
routeInstructionString += "],\n";
routeInstructionString += "],";
string lat; string lon;
convertLatLon(lastPlace.lon, lon);
convertLatLon(lastPlace.lat, lat);
lastPlace = current;
routeInstructionString += " [\"";
routeInstructionString += "[\"";
if(angle > 160 && angle < 200) {
routeInstructionString += /* " (" << angle << ")*/"Continue";
@ -214,7 +233,7 @@ public:
type = sEngine->GetTypeOfEdgeForOriginDestinationNodeID(phantomNodes->targetNode1, phantomNodes->targetNode2);
durationOfInstruction += sEngine->GetWeightForOriginDestinationNodeID(phantomNodes->targetNode1, phantomNodes->targetNode2);
routeInstructionString += " at ";
routeInstructionString += sEngine->GetNameForNameID(nameID);
routeInstructionString += sEngine->GetEscapedNameForNameID(nameID);
routeInstructionString += "\",";
distanceOfInstruction = ApproximateDistance(previous.lat, previous.lon, phantomNodes->targetCoord.lat, phantomNodes->targetCoord.lon) + tempDist;
entireDistance += distanceOfInstruction;
@ -239,58 +258,58 @@ public:
numberString.str("");
numberString << fixed << setprecision(2) << lastAngle;
routeInstructionString += numberString.str();
routeInstructionString += "]\n";
routeInstructionString += "]";
string lat; string lon;
//put targetCoord to linestring
convertLatLon(phantomNodes->targetCoord.lat, tmp);
routeGeometryString += " [";
routeGeometryString += "[";
routeGeometryString += tmp;
routeGeometryString += ", ";
convertLatLon(phantomNodes->targetCoord.lon, tmp);
routeGeometryString += tmp;
routeGeometryString += "]\n";
routeGeometryString += "]";
position++;
//give complete distance in meters;
ostringstream s;
s << 10*(round(entireDistance/10.));
routeSummaryString += " \"total_distance\":";
routeSummaryString += "\"total_distance\":";
routeSummaryString += s.str();
routeSummaryString += ",\n \"total_time\":";
routeSummaryString += ",\"total_time\":";
//give travel time in minutes
int travelTime = distance;
s.str("");
s << travelTime;
routeSummaryString += s.str();
routeSummaryString += ",\n \"start_point\":\"";
routeSummaryString += ",\"start_point\":\"";
routeSummaryString += startPointName;
routeSummaryString += "\",\n \"end_point\":\"";
routeSummaryString += "\",\"end_point\":\"";
routeSummaryString += endPointName;
routeSummaryString += "\"\n";
routeSummaryString += "\"";
} else {
reply.content += (" \"status\":207,\n");
reply.content += (" \"status_message\":");
reply.content += "\"Cannot find route between points\",\n";
routeSummaryString += " \"total_distance\":0";
routeSummaryString += ",\n \"total_time\":0";
routeSummaryString += ",\n \"start_point\":\"";
routeSummaryString += "\",\n \"end_point\":\"";
routeSummaryString += "\"\n";
reply.content += ("\"status\":207,");
reply.content += ("\"status_message\":");
reply.content += "\"Cannot find route between points\",";
routeSummaryString += "\"total_distance\":0";
routeSummaryString += ",\"total_time\":0";
routeSummaryString += ",\"start_point\":\"";
routeSummaryString += "\",\"end_point\":\"";
routeSummaryString += "\"";
}
reply.content += " \"route_summary\": {\n";
reply.content += "\"route_summary\": {";
reply.content += routeSummaryString;
reply.content += " },\n";
reply.content += " \"route_geometry\": [\n";
reply.content += "},";
reply.content += "\"route_geometry\": [";
reply.content += routeGeometryString;
reply.content += " ],\n";
reply.content += " \"route_instructions\": [\n";
reply.content += "],";
reply.content += "\"route_instructions\": [";
reply.content += routeInstructionString;
reply.content += " ],\n";
reply.content += " \"transactionId\": \"OSRM Routing Engine JSON Descriptor (beta)\"\n";
reply.content += "],";
reply.content += "\"transactionId\": \"OSRM Routing Engine JSON Descriptor (beta)\"";
reply.content += "}";
//std::cout << "zoom: " << zoom << ", threshold: " << areaThresholds[zoom] << ", painted: " << painted << ", omitted: " << omitted << std::endl;
}
private:
};
#endif /* JSONDESCRIPTOR_H_ */

View File

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

View File

@ -25,73 +25,125 @@ or see http://www.gnu.org/licenses/agpl.txt.
#include "BasePlugin.h"
#include "RouteParameters.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.
*/
class NearestPlugin : public BasePlugin {
public:
NearestPlugin(std::string ramIndexPath, std::string fileIndexPath, std::string nodesPath) {
nodeHelpDesk = new NodeInformationHelpDesk(ramIndexPath.c_str(), fileIndexPath.c_str());
ifstream nodesInStream(nodesPath.c_str(), ios::binary);
nodeHelpDesk->initNNGrid(nodesInStream);
}
~NearestPlugin() {
delete nodeHelpDesk;
}
std::string GetDescriptor() { return std::string("nearest"); }
std::string GetVersionString() { return std::string("0.3 (DL)"); }
void HandleRequest(RouteParameters routeParameters, http::Reply& reply) {
//check number of parameters
if(routeParameters.parameters.size() != 2) {
reply = http::Reply::stockReply(http::Reply::badRequest);
return;
}
NearestPlugin(std::string ramIndexPath, std::string fileIndexPath, std::string nodesPath) {
nodeHelpDesk = new NodeInformationHelpDesk(ramIndexPath.c_str(), fileIndexPath.c_str());
ifstream nodesInStream(nodesPath.c_str(), ios::binary);
nodeHelpDesk->initNNGrid(nodesInStream);
descriptorTable.Set("", 0); //default descriptor
descriptorTable.Set("kml", 0);
descriptorTable.Set("json", 1);
}
~NearestPlugin() {
delete nodeHelpDesk;
}
std::string GetDescriptor() { return std::string("nearest"); }
std::string GetVersionString() { return std::string("0.3 (DL)"); }
void HandleRequest(RouteParameters routeParameters, http::Reply& reply) {
//check number of parameters
if(routeParameters.parameters.size() != 2) {
reply = http::Reply::stockReply(http::Reply::badRequest);
return;
}
int lat = static_cast<int>(100000.*atof(routeParameters.parameters[0].c_str()));
int lon = static_cast<int>(100000.*atof(routeParameters.parameters[1].c_str()));
int lat = static_cast<int>(100000.*atof(routeParameters.parameters[0].c_str()));
int lon = static_cast<int>(100000.*atof(routeParameters.parameters[1].c_str()));
if(lat>90*100000 || lat <-90*100000 || lon>180*100000 || lon <-180*100000) {
reply = http::Reply::stockReply(http::Reply::badRequest);
return;
}
//query to helpdesk
_Coordinate result;
nodeHelpDesk->FindNearestPointOnEdge(_Coordinate(lat, lon), result);
if(lat>90*100000 || lat <-90*100000 || lon>180*100000 || lon <-180*100000) {
reply = http::Reply::stockReply(http::Reply::badRequest);
return;
}
//query to helpdesk
_Coordinate 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
//Write to stream
reply.status = http::Reply::ok;
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("<Placemark>");
JSONParameter = routeParameters.options.Find("jsonp");
if("" != JSONParameter) {
reply.content += JSONParameter;
reply.content += "(\n";
}
std::stringstream out1;
out1 << setprecision(10);
out1 << "<name>Nearest Place in map to " << lat/100000. << "," << lon/100000. << "</name>";
reply.content.append(out1.str());
reply.content.append("<Point>");
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());
std::stringstream out2;
out2 << setprecision(10);
out2 << "<coordinates>" << result.lon / 100000. << "," << result.lat / 100000. << "</coordinates>";
reply.content.append(out2.str());
reply.content.append("</Point>");
reply.content.append("</Placemark>");
reply.content.append("</kml>");
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\"";
}
reply.headers.resize(3);
reply.headers[0].name = "Content-Length";
reply.headers[0].value = boost::lexical_cast<std::string>(reply.content.size());
reply.headers[1].name = "Content-Type";
reply.headers[1].value = "application/vnd.google-earth.kml+xml";
reply.headers[2].name = "Content-Disposition";
reply.headers[2].value = "attachment; filename=\"placemark.kml\"";
return;
}
break;
default:
reply.status = http::Reply::ok;
//Write to stream
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("<Placemark>");
out1 << setprecision(10);
out1 << "<name>Nearest Place in map to " << lat/100000. << "," << lon/100000. << "</name>";
reply.content.append(out1.str());
reply.content.append("<Point>");
out2 << setprecision(10);
out2 << "<coordinates>" << result.lon / 100000. << "," << result.lat / 100000. << "</coordinates>";
reply.content.append(out2.str());
reply.content.append("</Point>");
reply.content.append("</Placemark>");
reply.content.append("</kml>");
reply.headers.resize(3);
reply.headers[0].name = "Content-Length";
reply.headers[0].value = boost::lexical_cast<std::string>(reply.content.size());
reply.headers[1].name = "Content-Type";
reply.headers[1].value = "application/vnd.google-earth.kml+xml";
reply.headers[2].name = "Content-Disposition";
reply.headers[2].value = "attachment; filename=\"placemark.kml\"";
break;
}
}
private:
NodeInformationHelpDesk * nodeHelpDesk;
NodeInformationHelpDesk * nodeHelpDesk;
HashTable<std::string, unsigned> descriptorTable;
};
#endif /* NearestPlugin_H_ */

View File

@ -21,6 +21,7 @@ or see http://www.gnu.org/licenses/agpl.txt.
#ifndef ROUTEPLUGIN_H_
#define ROUTEPLUGIN_H_
#include <cstdlib>
#include <fstream>
#include <sstream>
#include <string>
@ -127,6 +128,12 @@ public:
}
unsigned descriptorType = descriptorTable[routeParameters.options.Find("output")];
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
switch(descriptorType){
case 0:
@ -148,7 +155,7 @@ public:
desc = new KMLDescriptor<SearchEngine<EdgeData, StaticGraph<EdgeData> >, false >();
break;
}
desc->SetZoom(zoom);
desc->Run(reply, path, phantomNodes, sEngine, distance);
if("" != JSONParameter) {
reply.content += ")\n";
@ -175,7 +182,7 @@ public:
reply.headers[2].value = "attachment; filename=\"route.js\"";
} else {
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].value = "attachment; filename=\"route.json\"";
}