From ec0108553f690366c6d87f0dbe99bdeaa9074d3f Mon Sep 17 00:00:00 2001 From: Dennis Luxen Date: Mon, 26 Jul 2010 08:17:52 +0000 Subject: [PATCH] removed libkdtree++ dependency. --- Contractor/GraphLoader.h | 7 +- Contractor/SearchEngine.h | 23 +-- DataStructures/NodeCoords.h | 14 +- DataStructures/NodeInformationHelpDesk.h | 95 +++++----- DataStructures/StaticKDTree.h | 212 +++++++++++++++++++++++ Docs/3rdparty.txt | 2 +- Docs/Todo.txt | 2 - HttpServer/request_handler.h | 9 +- 8 files changed, 283 insertions(+), 81 deletions(-) create mode 100644 DataStructures/StaticKDTree.h diff --git a/Contractor/GraphLoader.h b/Contractor/GraphLoader.h index bc3e0188d..5e9ab28b2 100644 --- a/Contractor/GraphLoader.h +++ b/Contractor/GraphLoader.h @@ -78,7 +78,12 @@ inline NodeID readOSMRGraphFromStream(istream &in, vector& edgeList, vect // translate the external NodeIDs to internal IDs ExternalNodeMap::iterator intNodeID = ext2IntNodeMap.find(source); - if( intNodeID == ext2IntNodeMap.end()) { cerr << "unresolved source NodeID: " << source << endl; exit(0); } + if( intNodeID == ext2IntNodeMap.end()) + { + cerr << "after " << edgeList.size() << " edges" << endl; + cerr << "->" << source << "," << target << "," << length << "," << dir << "," << weight << endl; + cerr << "unresolved source NodeID: " << source << endl; exit(0); + } source = intNodeID->second; intNodeID = ext2IntNodeMap.find(target); if(intNodeID == ext2IntNodeMap.end()) { cerr << "unresolved target NodeID : " << target << endl; exit(0); } diff --git a/Contractor/SearchEngine.h b/Contractor/SearchEngine.h index 4359d5ade..2342d20b0 100644 --- a/Contractor/SearchEngine.h +++ b/Contractor/SearchEngine.h @@ -39,23 +39,23 @@ class SearchEngine { private: const GraphT * _graph; public: - SearchEngine(GraphT * g, KDTST * k) : _graph(g), kdtree(k) {} + SearchEngine(GraphT * g, KDTST * k) : _graph(g), nodeHelpDesk(k) {} ~SearchEngine() {} - const NodeInfo& getNodeInfo(NodeID id) const + const void getNodeInfo(NodeID id, NodeInfo * info) const { - return kdtree->getExternalNodeInfo(id); + nodeHelpDesk->getExternalNodeInfo(id, info); } unsigned int numberOfNodes() const { - return kdtree->getNumberOfNodes(); + return nodeHelpDesk->getNumberOfNodes(); } unsigned int ComputeRoute(NodeID start, NodeID target, vector * path) { - _Heap * _forwardHeap = new _Heap(kdtree->getNumberOfNodes()); - _Heap * _backwardHeap = new _Heap(kdtree->getNumberOfNodes()); + _Heap * _forwardHeap = new _Heap(nodeHelpDesk->getNumberOfNodes()); + _Heap * _backwardHeap = new _Heap(nodeHelpDesk->getNumberOfNodes()); NodeID middle = ( NodeID ) 0; unsigned int _upperbound = std::numeric_limits::max(); _forwardHeap->Insert(start, 0, start); @@ -93,16 +93,10 @@ public: packedPath.push_back( pathNode ); } - // for(deque::size_type i = 0; i < packedPath.size()-1; i++) - // { - // cout << packedPath[i] << endl; - // } - // push start node explicitely path->push_back(packedPath[0]); for(deque::size_type i = 0; i < packedPath.size()-1; i++) { - // path->push_back(*it); _UnpackEdge(packedPath[i], packedPath[i+1], path); } @@ -115,10 +109,10 @@ public: unsigned int findNearestNodeForLatLon(const int lat, const int lon, NodeCoords * data) const { - return kdtree->findNearestNodeIDForLatLon( lat, lon, data); + return nodeHelpDesk->findNearestNodeIDForLatLon( lat, lon, data); } private: - KDTST * kdtree; + KDTST * nodeHelpDesk; void _RoutingStep(_Heap * _forwardHeap, _Heap *_backwardHeap, const bool& forwardDirection, NodeID * middle, unsigned int * _upperbound) { @@ -190,7 +184,6 @@ private: } } - assert(smallestWeight != SPECIAL_EDGEID); const EdgeData ed = _graph->GetEdgeData(smallestEdge); diff --git a/DataStructures/NodeCoords.h b/DataStructures/NodeCoords.h index dc2396b61..7032eabe6 100644 --- a/DataStructures/NodeCoords.h +++ b/DataStructures/NodeCoords.h @@ -39,21 +39,21 @@ struct NodeCoords { static NodeCoords min_value() { - return NodeCoords(0,0,numeric_limits::min()); + return NodeCoords(-90*100000,-180*100000,numeric_limits::min()); } static NodeCoords max_value() { - return NodeCoords(numeric_limits::max(), numeric_limits::max(), numeric_limits::max()); + return NodeCoords(90*100000, 180*100000, numeric_limits::max()); } value_type operator[](size_t n) const { switch(n) { - case 0: + case 1: return lat; break; - case 1: + case 0: return lon; break; default: @@ -63,10 +63,4 @@ struct NodeCoords { } } }; - -template -bool operator < (const NodeCoords & a, const NodeCoords & b) -{ - return a.id < b.id; -} #endif //_NODE_COORDS_H diff --git a/DataStructures/NodeInformationHelpDesk.h b/DataStructures/NodeInformationHelpDesk.h index 32e7fec54..3c4bd7f11 100644 --- a/DataStructures/NodeInformationHelpDesk.h +++ b/DataStructures/NodeInformationHelpDesk.h @@ -16,7 +16,7 @@ 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. -*/ + */ #ifndef NODEINFORMATIONHELPDESK_H_ #define NODEINFORMATIONHELPDESK_H_ @@ -37,88 +37,87 @@ or see http://www.gnu.org/licenses/agpl.txt. #include #include "../typedefs.h" +#include "StaticKDTree.h" -#include - -typedef KDTree::KDTree<2, NodeInfo > KDTreeType; +typedef KDTree::StaticKDTree<2, int, NodeID> KDTreeType; class NodeInformationHelpDesk{ public: - ~NodeInformationHelpDesk(); - NodeInformationHelpDesk() { int2ExtNodeMap = new vector();} - KDTreeType * initKDTree(ifstream& input); + NodeInformationHelpDesk() { int2ExtNodeMap = new vector();} + KDTreeType * initKDTree(ifstream& input); - NodeID getExternalNodeID(const NodeID node); - const NodeInfo& getExternalNodeInfo(const NodeID node) const; - int getLatitudeOfNode(const NodeID node) const; - int getLongitudeOfNode(const NodeID node) const; + NodeID getExternalNodeID(const NodeID node); + void getExternalNodeInfo(const NodeID node, NodeInfo * info) const; + int getLatitudeOfNode(const NodeID node) const; + int getLongitudeOfNode(const NodeID node) const; - NodeID getNumberOfNodes() const { return int2ExtNodeMap->size(); } + NodeID getNumberOfNodes() const { return int2ExtNodeMap->size(); } - inline NodeID findNearestNodeIDForLatLon(const int lat, const int lon, NodeCoords * data) const - { - - NodeInfo nearestNeighbor = *(kdtree->find_nearest(NodeInfo(lat, lon, 0)).first); - data->id = nearestNeighbor.id; - data->lat = nearestNeighbor.lat; - data->lon = nearestNeighbor.lon; - return data->id; - } + inline NodeID findNearestNodeIDForLatLon(const int lat, const int lon, NodeCoords * data) const + { + KDTreeType::InputPoint i; + KDTreeType::InputPoint o; + i.coordinates[0] = lat; + i.coordinates[1] = lon; + kdtree->NearestNeighbor(&o, i); + data->id = o.data; + data->lat = o.coordinates[0]; + data->lon = o.coordinates[1]; + return data->id; + } private: - vector * int2ExtNodeMap; - KDTreeType * kdtree; + vector * int2ExtNodeMap; + KDTreeType * kdtree; }; ////////////////// //implementation// ////////////////// -NodeInformationHelpDesk::~NodeInformationHelpDesk(){ - // delete graph; - // delete calc; - // delete c; -} - /* @brief: initialize kd-tree and internal->external node id map * */ KDTreeType * NodeInformationHelpDesk::initKDTree(ifstream& in) { - kdtree = new KDTreeType(); - NodeID id = 0; - while(!in.eof()) - { - NodeInfo b; - in.read((char *)&b, sizeof(b)); - b.id = id; - KDTreeType::iterator kdit = kdtree->insert(b); - int2ExtNodeMap->push_back(kdit); - id++; - } - in.close(); -// kdtree->optimise(); - return kdtree; + NodeID id = 0; + while(!in.eof()) + { + NodeInfo b; + in.read((char *)&b, sizeof(b)); + b.id = id; + KDTreeType::InputPoint p; + p.coordinates[0] = b.lat; + p.coordinates[1] = b.lon; + p.data = id; + int2ExtNodeMap->push_back(p); + id++; + } + in.close(); + kdtree = new KDTreeType(int2ExtNodeMap); + return kdtree; } NodeID NodeInformationHelpDesk::getExternalNodeID(const NodeID node) { - return int2ExtNodeMap->at(node)->id; + return int2ExtNodeMap->at(node).data; } -const NodeInfo& NodeInformationHelpDesk::getExternalNodeInfo(const NodeID node) const +void NodeInformationHelpDesk::getExternalNodeInfo(const NodeID node, NodeInfo * info) const { - return *(int2ExtNodeMap->at(node) ); + info->id = int2ExtNodeMap->at(node).data; + info->lat = int2ExtNodeMap->at(node).coordinates[0]; + info->lon = int2ExtNodeMap->at(node).coordinates[1]; } int NodeInformationHelpDesk::getLatitudeOfNode(const NodeID node) const { - return int2ExtNodeMap->at(node)->lat; + return int2ExtNodeMap->at(node).coordinates[0]; } int NodeInformationHelpDesk::getLongitudeOfNode(const NodeID node) const { - return int2ExtNodeMap->at(node)->lon; + return int2ExtNodeMap->at(node).coordinates[1]; } #endif /*NODEINFORMATIONHELPDESK_H_*/ diff --git a/DataStructures/StaticKDTree.h b/DataStructures/StaticKDTree.h new file mode 100644 index 000000000..f9444d48f --- /dev/null +++ b/DataStructures/StaticKDTree.h @@ -0,0 +1,212 @@ +/* + open source routing machine + Copyright (C) Dennis Luxen, others 2010 + +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. + +KD Tree coded by Christian Vetter, Monav Project + + */ +#ifndef STATICKDTREE_H_INCLUDED +#define STATICKDTREE_H_INCLUDED + +#include +#ifdef _GLIBCXX_PARALLEL +#include +#else +#include +#endif +#include +#include + +namespace KDTree { + +template< unsigned k, typename T > +class BoundingBox { +public: + BoundingBox() { + for ( unsigned dim = 0; dim < k; ++dim ) { + min[dim] = std::numeric_limits< T >::min(); + max[dim] = std::numeric_limits< T >::max(); + } + } + + T min[k]; + T max[k]; +}; + +struct NoData {}; + +template< unsigned k, typename T > +class EuclidianMetric { +public: + double operator() ( const T left[k], const T right[k] ) { + double result = 0; + for ( unsigned i = 0; i < k; ++i ) { + double temp = (double)left[i] - (double)right[i]; + result += temp * temp; + } + return result; + } + + double operator() ( const BoundingBox< k, T > &box, const T point[k] ) { + T nearest[k]; + for ( unsigned dim = 0; dim < k; ++dim ) { + if ( point[dim] < box.min[dim] ) + nearest[dim] = box.min[dim]; + else if ( point[dim] > box.max[dim] ) + nearest[dim] = box.max[dim]; + else + nearest[dim] = point[dim]; + } + return operator() ( point, nearest ); + } +}; + +template < unsigned k, typename T, typename Data = NoData, typename Metric = EuclidianMetric< k, T > > +class StaticKDTree { +public: + + struct InputPoint { + T coordinates[k]; + Data data; + }; + + StaticKDTree( std::vector< InputPoint > * points ){ + assert( k > 0 ); + assert ( points->size() > 0 ); + size = points->size(); + kdtree = new InputPoint[size]; + for ( Iterator i = 0; i != size; ++i ) { + kdtree[i] = points->at(i); + for ( unsigned dim = 0; dim < k; ++dim ) { + if ( kdtree[i].coordinates[dim] < boundingBox.min[dim] ) + boundingBox.min[dim] = kdtree[i].coordinates[dim]; + if ( kdtree[i].coordinates[dim] > boundingBox.max[dim] ) + boundingBox.max[dim] = kdtree[i].coordinates[dim]; + } + } + std::stack< Tree > s; + s.push ( Tree ( 0, size, 0 ) ); + while ( !s.empty() ) { + Tree tree = s.top(); + s.pop(); + + if ( tree.left == tree.right ) + continue; + + Iterator middle = tree.left + ( tree.right - tree.left ) / 2; +#ifdef _GLIBCXX_PARALLEL + __gnu_parallel::nth_element( kdtree + tree.left, kdtree + middle, kdtree + tree.right, Less( tree.dimension ) ); + #else + std::nth_element( kdtree + tree.left, kdtree + middle, kdtree + tree.right, Less( tree.dimension ) ); +#endif + s.push( Tree( tree.left, middle, ( tree.dimension + 1 ) % k ) ); + s.push( Tree( middle + 1, tree.right, ( tree.dimension + 1 ) % k ) ); + } + } + + ~StaticKDTree(){ + delete[] kdtree; + } + + bool NearestNeighbor( InputPoint* result, const InputPoint& point, double radius = std::numeric_limits< T >::max() ) { + Metric distance; + bool found = false; + double nearestDistance = radius; + std::stack< NNTree > s; + s.push ( NNTree ( 0, size, 0, boundingBox ) ); + while ( !s.empty() ) { + NNTree tree = s.top(); + s.pop(); + + if ( distance( tree.box, point.coordinates ) >= nearestDistance ) + continue; + + if ( tree.left == tree.right ) + continue; + + Iterator middle = tree.left + ( tree.right - tree.left ) / 2; + + double newDistance = distance( kdtree[middle].coordinates, point.coordinates ); + if ( newDistance < nearestDistance ) { + nearestDistance = newDistance; + *result = kdtree[middle]; + found = true; + } + + Less comperator( tree.dimension ); + if ( !comperator( point, kdtree[middle] ) ) { + NNTree first( middle + 1, tree.right, ( tree.dimension + 1 ) % k, tree.box ); + NNTree second( tree.left, middle, ( tree.dimension + 1 ) % k, tree.box ); + first.box.min[tree.dimension] = kdtree[middle].coordinates[tree.dimension]; + second.box.max[tree.dimension] = kdtree[middle].coordinates[tree.dimension]; + s.push( second ); + s.push( first ); + } + else { + NNTree first( middle + 1, tree.right, ( tree.dimension + 1 ) % k, tree.box ); + NNTree second( tree.left, middle, ( tree.dimension + 1 ) % k, tree.box ); + first.box.min[tree.dimension] = kdtree[middle].coordinates[tree.dimension]; + second.box.max[tree.dimension] = kdtree[middle].coordinates[tree.dimension]; + s.push( first ); + s.push( second ); + } + } + + return found; + } + +private: + typedef unsigned Iterator; + struct Tree { + Iterator left; + Iterator right; + unsigned dimension; + Tree() {} + Tree( Iterator l, Iterator r, unsigned d ): left( l ), right( r ), dimension( d ) {} + }; + struct NNTree { + Iterator left; + Iterator right; + unsigned dimension; + BoundingBox< k, T > box; + NNTree() {} + NNTree( Iterator l, Iterator r, unsigned d, const BoundingBox< k, T >& b ): left( l ), right( r ), dimension( d ), box ( b ) {} + }; + class Less { + public: + Less( unsigned d ) { + dimension = d; + assert( dimension < k ); + } + + bool operator() ( const InputPoint& left, const InputPoint& right ) { + assert( dimension < k ); + return left.coordinates[dimension] < right.coordinates[dimension]; + } + private: + unsigned dimension; + }; + + BoundingBox< k, T > boundingBox; + InputPoint* kdtree; + Iterator size; +}; + +} + +#endif // STATICKDTREE_H_INCLUDED diff --git a/Docs/3rdparty.txt b/Docs/3rdparty.txt index 4130a6c30..593889d4b 100644 --- a/Docs/3rdparty.txt +++ b/Docs/3rdparty.txt @@ -1,6 +1,6 @@ Third Party Libraries: +Scons 1.3+ Boost 1.37+ -kdtree++ 0.7+ (0.62 does not work with g++ 4.0+) sparsehash 1.4+ stxxl 1.2.1+ \ No newline at end of file diff --git a/Docs/Todo.txt b/Docs/Todo.txt index 287cf6c10..1feabcf5e 100644 --- a/Docs/Todo.txt +++ b/Docs/Todo.txt @@ -5,6 +5,4 @@ Start/Endpoints of queries can only start on nodes only. Instead of selecting th The server part is mostly adapted from the boost http examples. It should be replaced with a self-written front-end -The KD-Tree uses a lot of RAM. An own implementation might be better. - Use Boost to compress all in-/output streams to the file system diff --git a/HttpServer/request_handler.h b/HttpServer/request_handler.h index 8ce254614..a7c905f43 100644 --- a/HttpServer/request_handler.h +++ b/HttpServer/request_handler.h @@ -126,14 +126,16 @@ public: rep.content.append("\n"); if(distance != std::numeric_limits::max()) { //A route has been found + NodeInfo * info = new NodeInfo(); for(vector::iterator it = path->begin(); it != path->end(); it++) { - NodeInfo info = sEngine-> getNodeInfo(*it); + sEngine-> getNodeInfo(*it, info); stringstream nodeout; nodeout << std::setprecision(10); - nodeout << info.lon/100000. << "," << info.lat/100000. << " " << endl; + nodeout << info->lon/100000. << "," << info->lat/100000. << " " << endl; rep.content.append(nodeout.str()); } + delete info; } rep.content.append(""); rep.content.append(""); @@ -164,7 +166,6 @@ private: //SearchEngine object that is queried SearchEngine * sEngine; }; - -} // namespace ROUTER +} #endif // HTTP_ROUTER_REQUEST_HANDLER_HPP