2011-10-10 11:52:47 -04:00
/*
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.
*/
2011-11-09 10:12:05 -05:00
# include <algorithm>
# include <boost/foreach.hpp>
2012-02-28 10:25:01 -05:00
# include <boost/lexical_cast.hpp>
# include <boost/property_tree/ptree.hpp>
# include <boost/property_tree/ini_parser.hpp>
2011-11-09 10:12:05 -05:00
2011-11-26 10:42:15 -05:00
# include "../Util/OpenMPReplacement.h"
2011-10-10 11:52:47 -04:00
# include "EdgeBasedGraphFactory.h"
template < >
2012-03-05 03:36:20 -05:00
EdgeBasedGraphFactory : : EdgeBasedGraphFactory ( int nodes , std : : vector < NodeBasedEdge > & inputEdges , std : : vector < NodeID > & bn , std : : vector < NodeID > & tl , std : : vector < _Restriction > & irs , std : : vector < NodeInfo > & nI , boost : : property_tree : : ptree speedProfile , std : : string & srtm ) : inputNodeInfoList ( nI ) , numberOfTurnRestrictions ( irs . size ( ) ) , trafficSignalPenalty ( 0 ) {
2012-02-29 14:02:04 -05:00
BOOST_FOREACH ( _Restriction & restriction , irs ) {
std : : pair < NodeID , NodeID > restrictionSource = std : : make_pair ( restriction . fromNode , restriction . viaNode ) ;
unsigned index ;
RestrictionMap : : iterator restrIter = _restrictionMap . find ( restrictionSource ) ;
if ( restrIter = = _restrictionMap . end ( ) ) {
index = _restrictionBucketVector . size ( ) ;
_restrictionBucketVector . resize ( index + 1 ) ;
_restrictionMap [ restrictionSource ] = index ;
} else {
index = restrIter - > second ;
//Map already contains an is_only_*-restriction
if ( _restrictionBucketVector . at ( index ) . begin ( ) - > second )
continue ;
else if ( restriction . flags . isOnly ) {
//We are going to insert an is_only_*-restriction. There can be only one.
_restrictionBucketVector . at ( index ) . clear ( ) ;
}
}
_restrictionBucketVector . at ( index ) . push_back ( std : : make_pair ( restriction . toNode , restriction . flags . isOnly ) ) ;
}
2011-11-09 10:12:05 -05:00
2012-02-28 10:25:01 -05:00
std : : string usedSpeedProfile ( speedProfile . get_child ( " " ) . begin ( ) - > first ) ;
BOOST_FOREACH ( boost : : property_tree : : ptree : : value_type & v , speedProfile . get_child ( usedSpeedProfile ) ) {
if ( " trafficSignalPenalty " = = v . first ) {
std : : string value = v . second . get < std : : string > ( " " ) ;
try {
trafficSignalPenalty = 10 * boost : : lexical_cast < int > ( v . second . get < std : : string > ( " " ) ) ;
} catch ( boost : : bad_lexical_cast & ) {
trafficSignalPenalty = 0 ;
}
}
2012-03-20 07:35:52 -04:00
if ( " uturnPenalty " = = v . first ) {
std : : string value = v . second . get < std : : string > ( " " ) ;
try {
uturnPenalty = 10 * boost : : lexical_cast < int > ( v . second . get < std : : string > ( " " ) ) ;
} catch ( boost : : bad_lexical_cast & ) {
uturnPenalty = 0 ;
}
}
if ( " takeMinimumOfSpeeds " = = v . first ) {
std : : string value = v . second . get < std : : string > ( " " ) ;
takeMinimumOfSpeeds = ( v . second . get < std : : string > ( " " ) = = " yes " ) ;
}
2012-02-28 10:25:01 -05:00
}
2012-03-20 07:35:52 -04:00
// INFO("traffic signal penalty: " << trafficSignalPenalty << ", U-Turn penalty: " << uturnPenalty << ", takeMinimumOfSpeeds=" << (takeMinimumOfSpeeds ? "yes" : "no"));
2012-03-05 03:36:20 -05:00
2012-04-04 05:11:54 -04:00
BOOST_FOREACH ( NodeID id , bn ) {
_barrierNodes [ id ] = true ;
}
BOOST_FOREACH ( NodeID id , tl ) {
_trafficLights [ id ] = true ;
}
2011-11-09 10:12:05 -05:00
2012-03-01 09:59:46 -05:00
std : : vector < _NodeBasedEdge > edges ;
2012-04-04 05:11:54 -04:00
// edges.reserve( 2 * inputEdges.size() );
2012-03-08 05:35:40 -05:00
for ( std : : vector < NodeBasedEdge > : : const_iterator i = inputEdges . begin ( ) ; i ! = inputEdges . end ( ) ; + + i ) {
2011-10-10 11:52:47 -04:00
2012-03-08 05:35:40 -05:00
_NodeBasedEdge edge ;
if ( ! i - > isForward ( ) ) {
edge . source = i - > target ( ) ;
edge . target = i - > source ( ) ;
edge . data . backward = i - > isForward ( ) ;
edge . data . forward = i - > isBackward ( ) ;
} else {
edge . source = i - > source ( ) ;
edge . target = i - > target ( ) ;
edge . data . forward = i - > isForward ( ) ;
edge . data . backward = i - > isBackward ( ) ;
}
2011-11-09 10:12:05 -05:00
if ( edge . source = = edge . target )
continue ;
2011-10-10 11:52:47 -04:00
edge . data . distance = ( std : : max ) ( ( int ) i - > weight ( ) , 1 ) ;
assert ( edge . data . distance > 0 ) ;
edge . data . shortcut = false ;
2011-11-22 10:47:15 -05:00
edge . data . roundabout = i - > isRoundabout ( ) ;
2011-12-16 08:05:30 -05:00
edge . data . ignoreInGrid = i - > ignoreInGrid ( ) ;
2011-11-25 06:02:52 -05:00
edge . data . nameID = i - > name ( ) ;
2011-10-10 11:52:47 -04:00
edge . data . type = i - > type ( ) ;
2012-03-22 05:25:04 -04:00
edge . data . isAccessRestricted = i - > isAccessRestricted ( ) ;
2011-11-14 07:12:56 -05:00
edge . data . edgeBasedNodeID = edges . size ( ) ;
2011-10-10 11:52:47 -04:00
edges . push_back ( edge ) ;
2011-11-09 10:12:05 -05:00
if ( edge . data . backward ) {
2011-12-05 08:45:45 -05:00
std : : swap ( edge . source , edge . target ) ;
2011-11-09 10:12:05 -05:00
edge . data . forward = i - > isBackward ( ) ;
edge . data . backward = i - > isForward ( ) ;
2011-11-14 07:12:56 -05:00
edge . data . edgeBasedNodeID = edges . size ( ) ;
2011-11-09 10:12:05 -05:00
edges . push_back ( edge ) ;
}
2011-10-10 11:52:47 -04:00
}
2011-11-09 10:12:05 -05:00
2012-03-22 05:25:04 -04:00
std : : sort ( edges . begin ( ) , edges . end ( ) ) ;
2011-11-09 10:12:05 -05:00
_nodeBasedGraph . reset ( new _NodeBasedDynamicGraph ( nodes , edges ) ) ;
INFO ( " Converted " < < inputEdges . size ( ) < < " node-based edges into " < < _nodeBasedGraph - > GetNumberOfEdges ( ) < < " edge-based nodes. " ) ;
}
2012-04-25 11:11:14 -04:00
void EdgeBasedGraphFactory : : GetEdgeBasedEdges ( std : : deque < EdgeBasedEdge > & outputEdgeList ) {
2011-11-09 10:12:05 -05:00
2011-11-25 06:02:52 -05:00
GUARANTEE ( 0 = = outputEdgeList . size ( ) , " Vector passed to EdgeBasedGraphFactory::GetEdgeBasedEdges(..) is not empty " ) ;
2011-11-09 10:12:05 -05:00
GUARANTEE ( 0 ! = edgeBasedEdges . size ( ) , " No edges in edge based graph " ) ;
2011-11-25 06:02:52 -05:00
edgeBasedEdges . swap ( outputEdgeList ) ;
2011-11-09 10:12:05 -05:00
}
2011-11-14 07:12:56 -05:00
void EdgeBasedGraphFactory : : GetEdgeBasedNodes ( std : : vector < EdgeBasedNode > & nodes ) {
2011-12-13 04:12:41 -05:00
BOOST_FOREACH ( EdgeBasedNode & node , edgeBasedNodes ) {
2012-03-01 08:36:10 -05:00
assert ( node . lat1 ! = INT_MAX ) ; assert ( node . lon1 ! = INT_MAX ) ;
assert ( node . lat2 ! = INT_MAX ) ; assert ( node . lon2 ! = INT_MAX ) ;
2011-12-13 04:12:41 -05:00
}
2012-03-01 08:36:10 -05:00
nodes . swap ( edgeBasedNodes ) ;
2011-11-09 10:12:05 -05:00
}
2012-04-25 04:51:16 -04:00
void EdgeBasedGraphFactory : : GetOriginalEdgeData ( std : : vector < OriginalEdgeData > & oed ) {
oed . swap ( originalEdgeData ) ;
}
2012-02-29 14:02:04 -05:00
NodeID EdgeBasedGraphFactory : : CheckForEmanatingIsOnlyTurn ( const NodeID u , const NodeID v ) const {
std : : pair < NodeID , NodeID > restrictionSource = std : : make_pair ( u , v ) ;
RestrictionMap : : const_iterator restrIter = _restrictionMap . find ( restrictionSource ) ;
if ( restrIter ! = _restrictionMap . end ( ) ) {
unsigned index = restrIter - > second ;
2012-03-01 08:36:10 -05:00
BOOST_FOREACH ( RestrictionSource restrictionTarget , _restrictionBucketVector . at ( index ) ) {
2012-02-29 14:02:04 -05:00
if ( restrictionTarget . second ) {
return restrictionTarget . first ;
}
}
}
return UINT_MAX ;
}
bool EdgeBasedGraphFactory : : CheckIfTurnIsRestricted ( const NodeID u , const NodeID v , const NodeID w ) const {
//only add an edge if turn is not a U-turn except it is the end of dead-end street.
std : : pair < NodeID , NodeID > restrictionSource = std : : make_pair ( u , v ) ;
RestrictionMap : : const_iterator restrIter = _restrictionMap . find ( restrictionSource ) ;
if ( restrIter ! = _restrictionMap . end ( ) ) {
unsigned index = restrIter - > second ;
BOOST_FOREACH ( RestrictionTarget restrictionTarget , _restrictionBucketVector . at ( index ) ) {
2012-03-01 08:36:10 -05:00
if ( w = = restrictionTarget . first )
2012-02-29 14:02:04 -05:00
return true ;
}
}
return false ;
}
2012-03-01 13:41:06 -05:00
void EdgeBasedGraphFactory : : InsertEdgeBasedNode (
_NodeBasedDynamicGraph : : EdgeIterator e1 ,
_NodeBasedDynamicGraph : : NodeIterator u ,
_NodeBasedDynamicGraph : : NodeIterator v ) {
2012-03-05 08:34:38 -05:00
_NodeBasedDynamicGraph : : EdgeData & data = _nodeBasedGraph - > GetEdgeData ( e1 ) ;
2012-03-01 13:41:06 -05:00
EdgeBasedNode currentNode ;
2012-03-05 08:34:38 -05:00
currentNode . nameID = data . nameID ;
2012-03-01 13:41:06 -05:00
currentNode . lat1 = inputNodeInfoList [ u ] . lat ;
currentNode . lon1 = inputNodeInfoList [ u ] . lon ;
currentNode . lat2 = inputNodeInfoList [ v ] . lat ;
currentNode . lon2 = inputNodeInfoList [ v ] . lon ;
2012-03-05 08:34:38 -05:00
currentNode . id = data . edgeBasedNodeID ;
currentNode . ignoreInGrid = data . ignoreInGrid ;
currentNode . weight = data . distance ;
2012-03-01 13:41:06 -05:00
//currentNode.weight += ComputeHeightPenalty(u, v);
edgeBasedNodes . push_back ( currentNode ) ;
}
2011-11-09 10:12:05 -05:00
void EdgeBasedGraphFactory : : Run ( ) {
2012-04-04 05:11:54 -04:00
// edgeBasedNodes.reserve(_nodeBasedGraph->GetNumberOfEdges());
2011-11-09 10:12:05 -05:00
Percent p ( _nodeBasedGraph - > GetNumberOfNodes ( ) ) ;
2011-12-30 07:30:17 -05:00
int numberOfSkippedTurns ( 0 ) ;
2011-11-09 10:12:05 -05:00
int nodeBasedEdgeCounter ( 0 ) ;
2011-11-23 12:40:54 -05:00
2012-03-01 08:36:10 -05:00
//loop over all edges and generate new set of nodes.
2011-11-09 10:12:05 -05:00
for ( _NodeBasedDynamicGraph : : NodeIterator u = 0 ; u < _nodeBasedGraph - > GetNumberOfNodes ( ) ; + + u ) {
for ( _NodeBasedDynamicGraph : : EdgeIterator e1 = _nodeBasedGraph - > BeginEdges ( u ) ; e1 < _nodeBasedGraph - > EndEdges ( u ) ; + + e1 ) {
_NodeBasedDynamicGraph : : NodeIterator v = _nodeBasedGraph - > GetTarget ( e1 ) ;
2012-02-07 13:40:25 -05:00
2012-03-01 08:36:10 -05:00
if ( _nodeBasedGraph - > GetEdgeData ( e1 ) . type ! = SHRT_MAX ) {
2012-03-05 08:34:38 -05:00
assert ( e1 ! = UINT_MAX ) ;
assert ( u ! = UINT_MAX ) ;
assert ( v ! = UINT_MAX ) ;
2012-03-01 13:41:06 -05:00
InsertEdgeBasedNode ( e1 , u , v ) ;
2011-12-05 08:45:45 -05:00
}
2012-03-01 08:36:10 -05:00
}
}
2012-01-01 10:04:59 -05:00
2012-03-01 08:36:10 -05:00
//Loop over all turns and generate new set of edges.
//Three nested loop look super-linear, but we are dealing with a linear number of turns only.
for ( _NodeBasedDynamicGraph : : NodeIterator u = 0 ; u < _nodeBasedGraph - > GetNumberOfNodes ( ) ; + + u ) {
for ( _NodeBasedDynamicGraph : : EdgeIterator e1 = _nodeBasedGraph - > BeginEdges ( u ) ; e1 < _nodeBasedGraph - > EndEdges ( u ) ; + + e1 ) {
2012-03-07 08:08:46 -05:00
+ + nodeBasedEdgeCounter ;
2012-03-01 08:36:10 -05:00
_NodeBasedDynamicGraph : : NodeIterator v = _nodeBasedGraph - > GetTarget ( e1 ) ;
//EdgeWeight heightPenalty = ComputeHeightPenalty(u, v);
NodeID onlyToNode = CheckForEmanatingIsOnlyTurn ( u , v ) ;
2011-11-09 10:12:05 -05:00
for ( _NodeBasedDynamicGraph : : EdgeIterator e2 = _nodeBasedGraph - > BeginEdges ( v ) ; e2 < _nodeBasedGraph - > EndEdges ( v ) ; + + e2 ) {
_NodeBasedDynamicGraph : : NodeIterator w = _nodeBasedGraph - > GetTarget ( e2 ) ;
2012-02-07 13:40:25 -05:00
2012-03-01 08:36:10 -05:00
if ( onlyToNode ! = UINT_MAX & & w ! = onlyToNode ) { //We are at an only_-restriction but not at the right turn.
2012-02-29 14:02:04 -05:00
+ + numberOfSkippedTurns ;
2011-12-05 08:45:45 -05:00
continue ;
}
2012-03-01 08:36:10 -05:00
bool isBollardNode = ( _barrierNodes . find ( v ) ! = _barrierNodes . end ( ) ) ;
2012-03-01 13:41:06 -05:00
if ( ( ! isBollardNode & & ( u ! = w | | 1 = = _nodeBasedGraph - > GetOutDegree ( v ) ) ) | | ( ( u = = w ) & & isBollardNode ) ) { //only add an edge if turn is not a U-turn except it is the end of dead-end street.
2012-02-29 14:02:04 -05:00
if ( ! CheckIfTurnIsRestricted ( u , v , w ) | | ( onlyToNode ! = UINT_MAX & & w = = onlyToNode ) ) { //only add an edge if turn is not prohibited
2012-03-01 08:36:10 -05:00
const _NodeBasedDynamicGraph : : EdgeData edgeData1 = _nodeBasedGraph - > GetEdgeData ( e1 ) ;
const _NodeBasedDynamicGraph : : EdgeData edgeData2 = _nodeBasedGraph - > GetEdgeData ( e2 ) ;
assert ( edgeData1 . edgeBasedNodeID < _nodeBasedGraph - > GetNumberOfEdges ( ) ) ;
assert ( edgeData2 . edgeBasedNodeID < _nodeBasedGraph - > GetNumberOfEdges ( ) ) ;
unsigned distance = edgeData1 . distance ;
2012-02-28 10:25:01 -05:00
if ( _trafficLights . find ( v ) ! = _trafficLights . end ( ) ) {
distance + = trafficSignalPenalty ;
}
2012-03-01 08:36:10 -05:00
short turnInstruction = AnalyzeTurn ( u , v , w ) ;
2012-03-20 07:35:52 -04:00
if ( turnInstruction = = TurnInstructions . UTurn )
distance + = uturnPenalty ;
2012-03-22 05:25:04 -04:00
if ( ! edgeData1 . isAccessRestricted & & edgeData2 . isAccessRestricted ) {
distance + = TurnInstructions . AccessRestrictionPenaly ;
turnInstruction | = TurnInstructions . AccessRestrictionFlag ;
}
2012-03-20 07:35:52 -04:00
//distance += heightPenalty;
//distance += ComputeTurnPenalty(u, v, w);
2012-03-05 08:34:38 -05:00
assert ( edgeData1 . edgeBasedNodeID ! = edgeData2 . edgeBasedNodeID ) ;
2012-04-25 11:11:14 -04:00
// if(edgeBasedEdges.size() == edgeBasedEdges.capacity()-3)
// edgeBasedEdges.reserve(edgeBasedEdges.size()*1.1);
2012-04-25 10:35:13 -04:00
if ( originalEdgeData . size ( ) = = originalEdgeData . capacity ( ) - 3 )
originalEdgeData . reserve ( originalEdgeData . size ( ) * 1.1 ) ;
2012-04-25 04:51:16 -04:00
OriginalEdgeData oed ( v , edgeData2 . nameID , turnInstruction ) ;
EdgeBasedEdge newEdge ( edgeData1 . edgeBasedNodeID , edgeData2 . edgeBasedNodeID , edgeBasedEdges . size ( ) , distance , true , false ) ;
originalEdgeData . push_back ( oed ) ;
2011-11-09 10:12:05 -05:00
edgeBasedEdges . push_back ( newEdge ) ;
} else {
2011-12-30 07:30:17 -05:00
+ + numberOfSkippedTurns ;
2011-11-09 10:12:05 -05:00
}
}
2011-10-10 11:52:47 -04:00
}
}
2011-11-09 10:12:05 -05:00
p . printIncrement ( ) ;
2011-10-10 11:52:47 -04:00
}
2012-04-14 09:07:02 -04:00
INFO ( " Sorting edge-based Nodes " ) ;
2011-11-14 07:12:56 -05:00
std : : sort ( edgeBasedNodes . begin ( ) , edgeBasedNodes . end ( ) ) ;
2012-04-14 09:07:02 -04:00
INFO ( " Removing duplicate nodes (if any) " ) ;
2011-11-14 07:12:56 -05:00
edgeBasedNodes . erase ( std : : unique ( edgeBasedNodes . begin ( ) , edgeBasedNodes . end ( ) ) , edgeBasedNodes . end ( ) ) ;
2012-04-14 09:07:02 -04:00
INFO ( " Applying vector self-swap trick to free up memory " ) ;
edgeBasedNodes . swap ( edgeBasedNodes ) ;
2011-11-14 07:12:56 -05:00
INFO ( " Node-based graph contains " < < nodeBasedEdgeCounter < < " edges " ) ;
2011-11-09 10:12:05 -05:00
INFO ( " Edge-based graph contains " < < edgeBasedEdges . size ( ) < < " edges, blowup is " < < ( double ) edgeBasedEdges . size ( ) / ( double ) nodeBasedEdgeCounter ) ;
2012-02-29 14:02:04 -05:00
INFO ( " Edge-based graph skipped " < < numberOfSkippedTurns < < " turns, defined by " < < numberOfTurnRestrictions < < " restrictions. " ) ;
2011-11-14 07:12:56 -05:00
INFO ( " Generated " < < edgeBasedNodes . size ( ) < < " edge based nodes " ) ;
2011-11-09 10:12:05 -05:00
}
2011-11-17 12:04:49 -05:00
short EdgeBasedGraphFactory : : AnalyzeTurn ( const NodeID u , const NodeID v , const NodeID w ) const {
2012-02-29 14:02:04 -05:00
if ( u = = w ) {
return TurnInstructions . UTurn ;
}
2012-01-01 10:04:59 -05:00
2011-11-17 12:04:49 -05:00
_NodeBasedDynamicGraph : : EdgeIterator edge1 = _nodeBasedGraph - > FindEdge ( u , v ) ;
_NodeBasedDynamicGraph : : EdgeIterator edge2 = _nodeBasedGraph - > FindEdge ( v , w ) ;
2011-11-25 06:02:52 -05:00
_NodeBasedDynamicGraph : : EdgeData & data1 = _nodeBasedGraph - > GetEdgeData ( edge1 ) ;
_NodeBasedDynamicGraph : : EdgeData & data2 = _nodeBasedGraph - > GetEdgeData ( edge2 ) ;
2011-11-17 12:04:49 -05:00
2011-11-23 12:40:54 -05:00
//roundabouts need to be handled explicitely
if ( data1 . roundabout & & data2 . roundabout ) {
//Is a turn possible? If yes, we stay on the roundabout!
if ( 1 = = ( _nodeBasedGraph - > EndEdges ( v ) - _nodeBasedGraph - > BeginEdges ( v ) ) ) {
//No turn possible.
return TurnInstructions . NoTurn ;
} else {
return TurnInstructions . StayOnRoundAbout ;
}
}
//Does turn start or end on roundabout?
2011-11-22 10:47:15 -05:00
if ( data1 . roundabout | | data2 . roundabout ) {
//We are entering the roundabout
2011-11-23 12:40:54 -05:00
if ( ( ! data1 . roundabout ) & & data2 . roundabout )
2011-11-22 10:47:15 -05:00
return TurnInstructions . EnterRoundAbout ;
//We are leaving the roundabout
2012-03-08 05:35:40 -05:00
else if ( data1 . roundabout & & ( ! data2 . roundabout ) )
2011-11-22 10:47:15 -05:00
return TurnInstructions . LeaveRoundAbout ;
2011-11-17 12:04:49 -05:00
}
2011-11-22 10:47:15 -05:00
2011-11-23 12:40:54 -05:00
//If street names stay the same and if we are certain that it is not a roundabout, we skip it.
2012-02-08 12:31:37 -05:00
if ( ( data1 . nameID = = data2 . nameID ) & & ( 0 ! = data1 . nameID ) )
return TurnInstructions . NoTurn ;
2012-02-23 10:29:55 -05:00
if ( ( data1 . nameID = = data2 . nameID ) & & ( 0 = = data1 . nameID ) & & ( _nodeBasedGraph - > GetOutDegree ( v ) < = 2 ) )
2011-11-23 12:40:54 -05:00
return TurnInstructions . NoTurn ;
2012-02-08 12:31:37 -05:00
double angle = GetAngleBetweenTwoEdges ( inputNodeInfoList [ u ] , inputNodeInfoList [ v ] , inputNodeInfoList [ w ] ) ;
2011-11-22 10:47:15 -05:00
return TurnInstructions . GetTurnDirectionOfInstruction ( angle ) ;
2011-11-17 12:04:49 -05:00
}
2011-11-09 10:12:05 -05:00
unsigned EdgeBasedGraphFactory : : GetNumberOfNodes ( ) const {
2011-12-13 04:12:41 -05:00
return _nodeBasedGraph - > GetNumberOfEdges ( ) ;
2011-10-10 11:52:47 -04:00
}
2011-11-22 10:47:15 -05:00
/* Get angle of line segment (A,C)->(C,B), atan2 magic, formerly cosine theorem*/
template < class CoordinateT >
double EdgeBasedGraphFactory : : GetAngleBetweenTwoEdges ( const CoordinateT & A , const CoordinateT & C , const CoordinateT & B ) const {
const int v1x = A . lon - C . lon ;
const int v1y = A . lat - C . lat ;
const int v2x = B . lon - C . lon ;
const int v2y = B . lat - C . lat ;
double angle = ( atan2 ( ( double ) v2y , v2x ) - atan2 ( ( double ) v1y , v1x ) ) * 180 / M_PI ;
while ( angle < 0 )
angle + = 360 ;
return angle ;
}