1 /*PGR-GNU*****************************************************************
2 *
3 Copyright (c) 2015 Celia Virginia Vergara Castillo
4 vicky_vergara@hotmail.com
5 ------
6
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2 of the License, or
10 (at your option) any later version.
11
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with this program; if not, write to the Free Software
19 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
20
21 ********************************************************************PGR-GNU*/
22
23 /*! @file */
24
25 #ifndef INCLUDE_CPP_COMMON_PGR_BASE_GRAPH_HPP_
26 #define INCLUDE_CPP_COMMON_PGR_BASE_GRAPH_HPP_
27 #pragma once
28
29 #include <boost/graph/iteration_macros.hpp>
30 #include <boost/config.hpp>
31 #include <boost/graph/adjacency_list.hpp>
32 #include <boost/graph/graph_utility.hpp>
33
34 #include <deque>
35 #include <vector>
36 #include <set>
37 #include <map>
38 #include <limits>
39
40 #include "c_types/graph_enum.h"
41
42 #include "cpp_common/basic_vertex.h"
43 #include "cpp_common/xy_vertex.h"
44 #include "cpp_common/basic_edge.h"
45
46 #include "cpp_common/pgr_assert.h"
47
48 namespace pgrouting {
49
50 /*! @brief boost::graph simplified to pgRouting needs
51 This class gives the handling basics of a boost::graph of kind G
52 where G:
53 can be an undirected graph or a directed graph.
54 Requiremets:
55 ============
56 A vertex class T_V
57 ------------------
58 Current Available vertex classes:
59 - Basic_vertex
60 - XY_vertex
61 An edge class T_E
62 -----------------
63 Current Available edge classes:
64 - Basic_edge
65 extract_vertices function
66 -------------------------
67 Data obtained from postgresql is stored in
68 A C array of pgr_edge_t type.
69 ~~~~{.c}
70 std::vector< T_V >
71 extract_vertices(pgr_edge_t *, size_t)
72 ~~~~
73 Data obtained from postgresql is stored in
74 o a vector container.
75 ~~~~{.c}
76 std::vector< T_V >
77 extract_vertices(std::vector< pgr_edge_t >)
78 ~~~~
79 Boost Graph
80 -------------
81 The code is prepared to be used for:
82 - boost::adjacency_list graph type
83 - boost::undirectedS when the graph is UNDIRECTED
84 - boost::bidirectionalS when the graph is DIRECTED
85 ~~~~{.c}
86 boost::adjacency_list
87 < boost::vecS, // not tested with other values
88 boost::vecS, // not tested with other values
89 boost::undirectedS, // USinG UNDIRECTED
90 Basic_vertex, // the vertex class
91 Basic_edge > // the edge class
92 ~~~~
93 Example Usage:
94 =============
95 For this example we will use:
96 - Basic_vertex
97 - Basic_edge
98 - pgr_edge_t
99 Create Graph type
100 -----------------
101 ~~~~{.c}
102 typedef typename
103 graph::Pgr_base_graph <
104 boost::adjacency_list <
105 boost::vecS,
106 boost::vecS,
107 boost::bidirectionalS,
108 Basic_vertex,
109 Basic_edge >,
110 Basic_vertex,
111 Basic_edge >
112 DirectedGraph;
113 ~~~~
114 Initializing the graph
115 ------------------------------
116 Graph initialization is for seting the Vertices of the graph.
117 //TODO discuss if also the edges
118 Vector of unique vertices of the graph
119 ~~~~{.c}
120 size_t total_edges;
121 pgr_edge_t *my_edges = NULL;
122 pgr_get_edges(edges_sql, &my_edges, &total_tuples);
123 std::vector< Basic_Vertex > vertices(pgrouting::extract_vertices(my_edges));
124 ~~~~
125 There are several ways to initialize the graph
126 ~~~~{.c}
127 // 1. Initializes an empty graph
128 pgrouting::DirectedGraph digraph(gType);
129 // 2. Initializes a graph based on the vertices
130 pgrouting::DirectedGraph digraph(
131 verices,
132 gType);
133 vertices.clear();
134 3. Initializes a graph based on the extracted vertices
135 pgrouting::DirectedGraph digraph(
136 pgrouting::extract_vertices(my_edges, total_edges);
137 gType);
138 4. Initializes a graph based on the extracted vertices
139 pgrouting::DirectedGraph digraph(
140 pgrouting::extract_vertices(my_edges);
141 gType);
142 ~~~~
143 1. Initializes an empty graph
144 - vertices vector size is 0
145 2. Initializes a graph based on the vertices:
146 - vertices vector size is vertices.size()
147 - the vertices are inserted
148 - vertices container can be clared to free memory
149 3. Initializes a graph based on the vertices extracted
150 - from edges stored on a C array
151 - the vertices are inserted
152 4. Initializes a graph based on the vertices extracted
153 - from edges stored on a vector
154 - the vertices are inserted
155 Fill the graph
156 ---------------------
157 After initializing the graph with the vertices, the edges can be added.
158 ~~~~{.c}
159 // inserting edges from a C array
160 digraph.insert_edges(my_edges, total_edges);
161 // adding more edges to the graph from a vector container
162 digraph.insert_edges(new_edges);
163 ~~~~
164 */
165
166 namespace graph {
167 template <class G, typename Vertex, typename Edge>
168 class Pgr_base_graph;
169
170 } // namespace graph
171
172
173 /** @name Graph types
174 Type | pgRouting
175 :---------: | :---------------------
176 UndirectedGraph | Basic undirected graph
177 DirectedGraph | Basic directed graph
178 xyUndirectedGraph | X & Y values stored on the vertex
179 xyDirectedGraph | X & Y values stored on the vertex
180 */
181 //@{
182 typedef graph::Pgr_base_graph <
183 boost::adjacency_list < boost::vecS, boost::vecS,
184 boost::undirectedS,
185 Basic_vertex, Basic_edge >,
186 Basic_vertex, Basic_edge > UndirectedGraph;
187
188 typedef graph::Pgr_base_graph <
189 boost::adjacency_list < boost::vecS, boost::vecS,
190 boost::bidirectionalS,
191 Basic_vertex, Basic_edge >,
192 Basic_vertex, Basic_edge > DirectedGraph;
193
194 typedef graph::Pgr_base_graph <
195 boost::adjacency_list < boost::listS, boost::vecS,
196 boost::undirectedS,
197 XY_vertex, Basic_edge >,
198 XY_vertex, Basic_edge > xyUndirectedGraph;
199
200 typedef graph::Pgr_base_graph <
201 boost::adjacency_list < boost::listS, boost::vecS,
202 boost::bidirectionalS,
203 XY_vertex, Basic_edge >,
204 XY_vertex, Basic_edge > xyDirectedGraph;
205
206 //@}
207
208
209 namespace graph {
210
211 template <typename G, typename T_V, typename T_E>
212 class Pgr_base_graph {
213 public:
214 /** @name Graph related types
215 Type | boost meaning | pgRouting meaning
216 :---------: | :-------------------- | :----------------------
217 G | boost::adjacency_list | Graph
218 V | vertex_descriptor | Think of it as local ID of a vertex
219 E | edge_descriptor | Think of it as local ID of an edge
220 V_i | vertex_iterator | To cycle the vertices of the Graph
221 E_i | edge_iterator | To cycle the edges of the Graph
222 EO_i | out_edge_iterator | To cycle the out going edges of a vertex
223 EI_i | in_edge_iterator | To cycle the in coming edges of a vertex (only in bidirectional graphs)
224 */
225 //@{
226 typedef G B_G;
227 typedef T_E G_T_E;
228 typedef T_V G_T_V;
229 typedef typename boost::graph_traits < G >::vertex_descriptor V;
230 typedef typename boost::graph_traits < G >::edge_descriptor E;
231 typedef typename boost::graph_traits < G >::vertex_iterator V_i;
232 typedef typename boost::graph_traits < G >::edge_iterator E_i;
233 typedef typename boost::graph_traits < G >::out_edge_iterator EO_i;
234 typedef typename boost::graph_traits < G >::in_edge_iterator EI_i;
235
236 typedef typename boost::graph_traits < G >::vertices_size_type
237 vertices_size_type;
238 typedef typename boost::graph_traits < G >::edges_size_type
239 edges_size_type;
240 typedef typename boost::graph_traits < G >::degree_size_type
241 degree_size_type;
242
243 //@}
244
245 /** @name Id handling related types
246 Type | Meaning | pgRouting Meaning
247 :---------: | :------------- | :----------------------
248 id_to_V | maps id -> V | given an id store the V
249 LI | Left Iterator | iterates over id_to_V
250 */
251 //@{
252
253 typedef typename std::map< int64_t, V > id_to_V;
254 typedef typename id_to_V::const_iterator LI;
255
256 //@}
257
258 //! @name The Graph
259 //@{
260 G graph; //!< The graph
261 graphType m_gType; //!< type (DIRECTED or UNDIRECTED)
262 //@}
263
264 //! @name Id mapping handling
265 //@{
266
267 id_to_V vertices_map; //!< id -> graph id
268
269 typename boost::property_map<G, boost::vertex_index_t>::type vertIndex;
270
271 typedef std::map<V, size_t> IndexMap;
272 IndexMap mapIndex;
273 boost::associative_property_map<IndexMap> propmapIndex;
274
275 //@}
276
277 //! @name Graph Modification
278 //@{
279 //! Used for storing the removed_edges
280
281 std::deque< T_E > removed_edges;
282
283 //@}
284
285
286
287 //! @name The Graph
288 //@{
289 //! @brief Constructor
290 /*!
291 - Prepares the graph to be of type gtype
292 - inserts the vertices
293 - The vertices must be checked (if necessary) before calling the constructor
294 */
295 Pgr_base_graph< G , T_V, T_E >(
296 const std::vector< T_V > &vertices, graphType gtype)
297 : graph(vertices.size()),
298 #if 0
299 m_num_vertices(vertices.size()),
300 #endif
301 m_gType(gtype),
302 vertIndex(boost::get(boost::vertex_index, graph)),
303 propmapIndex(mapIndex) {
304 // add_vertices(vertices);
305 // This code does not work with contraction
306 #if 0
307 pgassert(pgrouting::check_vertices(vertices) == 0);
308 #endif
309 size_t i = 0;
310 for (auto vi = boost::vertices(graph).first;
311 vi != boost::vertices(graph).second; ++vi) {
312 vertices_map[vertices[i].id] = (*vi);
313 graph[(*vi)].cp_members(vertices[i]);
314 // put(propmapIndex, *vi, num_vertices());
315 pgassert(vertIndex[*vi] == i);
316 ++i;
317 }
318
319 std::ostringstream log;
320 for (auto iter = vertices_map.begin();
321 iter != vertices_map.end();
322 iter++) {
323 log << "Key: "
324 << iter->first <<"\tValue:" << iter->second << "\n";
325 }
326 for (const auto vertex : vertices) {
327 pgassert(has_vertex(vertex.id));
328 }
329 // pgassert(mapIndex.size() == vertices.size());
330 }
331
332 /*!
333 Prepares the _graph_ to be of type gtype with 0 vertices
334 */
335 explicit Pgr_base_graph< G , T_V, T_E >(graphType gtype)
336 : graph(0),
337 #if 0
338 m_num_vertices(0),
339 #endif
340 m_gType(gtype),
341 vertIndex(boost::get(boost::vertex_index, graph)),
342 propmapIndex(mapIndex) {
343 }
344
345
346 //! @name Insert edges
347 //@{
348 /*! @brief Inserts *count* edges of type *T* into the graph
349 *
350 * Converts the edges to a std::vector<T> & calls the overloaded
351 * twin function.
352 *
353 * @param edges
354 * @param count
355 */
356 template < typename T >
insert_edges(const T * edges,size_t count)357 void insert_edges(const T *edges, size_t count) {
358 insert_edges(std::vector < T >(edges, edges + count));
359 }
360
361 template < typename T >
insert_edges_neg(const T * edges,size_t count)362 void insert_edges_neg(const T *edges, size_t count) {
363 insert_edges(std::vector < T >(edges, edges + count), false);
364 }
365
366 template < typename T>
insert_edges(T * edges,size_t count,bool)367 void insert_edges(T *edges, size_t count, bool) {
368 for (size_t i = 0; i < count; ++i) {
369 pgassert(has_vertex(edges[i].source));
370 pgassert(has_vertex(edges[i].target));
371 graph_add_edge_no_create_vertex(edges[i]);
372 }
373 }
374
375 template < typename T >
insert_negative_edges(const T * edges,int64_t count)376 void insert_negative_edges(const T *edges, int64_t count) {
377 insert_negative_edges(std::vector < T >(edges, edges + count));
378 }
379
380 /*! @brief Inserts *count* edges of type *pgr_edge_t* into the graph
381 The set of edges should not have an illegal vertex defined
382 When the graph is empty calls:
383 - @b extract_vertices
384 and throws an exception if there are illegal vertices.
385 When developing:
386 - if an illegal vertex is found an exception is thrown
387 - That means that the set of vertices should be checked in the
388 code that is being developed
389 No edge is inserted when there is an error on the vertices
390 @param edges
391 @param normal
392 */
393 template <typename T>
394 void
insert_edges(const std::vector<T> & edges,bool normal=true)395 insert_edges(const std::vector<T> &edges, bool normal = true) {
396 #if 0
397 // This code does not work with contraction
398 if (num_vertices() == 0) {
399 auto vertices = pgrouting::extract_vertices(edges);
400 pgassert(pgrouting::check_vertices(vertices) == 0);
401 add_vertices(vertices);
402 }
403 #endif
404 for (const auto edge : edges) {
405 graph_add_edge(edge, normal);
406 }
407 }
408
409 template <typename T>
insert_min_edges_no_parallel(const T * edges,size_t count)410 void insert_min_edges_no_parallel(const T *edges, size_t count) {
411 insert_edges(std::vector<T>(edges, edges + count));
412 }
413
414 template <typename T>
415 void
insert_min_edges_no_parallel(const std::vector<T> & edges)416 insert_min_edges_no_parallel(const std::vector<T> &edges) {
417 for (const auto edge : edges) {
418 graph_add_min_edge_no_parallel(edge);
419 }
420 }
421
422 template < typename T >
insert_negative_edges(const std::vector<T> & edges,bool normal=true)423 void insert_negative_edges(
424 const std::vector<T> &edges,
425 bool normal = true) {
426 for (const auto edge : edges) {
427 graph_add_neg_edge(edge, normal);
428 }
429 }
430 //@}
431
432 private:
433 /*! @brief adds the vertices into the graph
434 *
435 * PRECONDITIONS:
436 * - The graph has not being initialized before
437 * - There are no dupicated vertices
438 *
439 * ~~~~~{.c}
440 * precondition(boost::num_vertices(graph) == 0);
441 * for (vertex : vertices)
442 * precondition(!has_vertex(vertex.id));
443 * ~~~~~
444 *
445 *
446 * POSTCONDITIONS:
447 * ~~~~~{.c}
448 * postcondition(boost::num_vertices(graph) == vertices.size());
449 * for (vertex : vertices)
450 * postcondition(has_vertex(vertex.id));
451 * ~~~~~
452 *
453 * Example use:
454 *
455 * ~~~~~{.c}
456 * pgrouting::DirectedGraph digraph(gType);
457 * auto vertices(pgrouting::extract_vertices(data_edges, total_edges));
458 * digraph.add_vertices(vertices);
459 * ~~~~~
460 *
461 */
add_vertices(std::vector<T_V> vertices)462 void add_vertices(
463 std::vector< T_V > vertices) {
464 pgassert(num_vertices() == 0);
465 for (const auto vertex : vertices) {
466 pgassert(!has_vertex(vertex.id));
467
468 auto v = add_vertex(graph);
469 vertices_map[vertex.id] = v;
470 graph[v].cp_members(vertex);
471 // put(propmapIndex, v, num_vertices());
472
473 pgassert(has_vertex(vertex.id));
474 }
475 // pgassert(mapIndex.size() == vertices.size());
476 pgassert(num_vertices() == vertices.size());
477 }
478
479
480 public:
481 //! @name boost wrappers with original id
482 //@{
483 //! @brief get the out-degree of a vertex
484
485 /*!
486 @returns 0: The out degree of a vertex that its not in the graph
487 @param [in] vertex_id original vertex id
488 */
out_degree(int64_t vertex_id) const489 degree_size_type out_degree(int64_t vertex_id) const {
490 if (!has_vertex(vertex_id)) {
491 return 0;
492 }
493 auto v = get_V(vertex_id);
494 auto d = out_degree(v);
495 return d;
496 }
in_degree(int64_t vertex_id) const497 degree_size_type in_degree(int64_t vertex_id) const {
498 if (!has_vertex(vertex_id)) {
499 return 0;
500 }
501 return is_directed()?
502 in_degree(get_V(vertex_id))
503 : out_degree(get_V(vertex_id));
504 }
505
506
507 /*! @brief get the vertex descriptor of the vertex
508 When the vertex does not exist
509 - creates a new vetex
510 @return V: The vertex descriptor of the vertex
511 */
get_V(const T_V & vertex)512 V get_V(const T_V &vertex) {
513 auto vm_s(vertices_map.find(vertex.id));
514 if (vm_s == vertices_map.end()) {
515 auto v = add_vertex(graph);
516 graph[v].cp_members(vertex);
517 vertices_map[vertex.id] = v;
518 put(propmapIndex, v, num_vertices());
519 return v;
520 }
521 return vm_s->second;
522 }
523
524 /*! @brief get the vertex descriptor of the vid
525 Call has_vertex(vid) before calling this function
526 @return V: The vertex descriptor of the vertex
527 */
get_V(int64_t vid) const528 V get_V(int64_t vid) const {
529 pgassert(has_vertex(vid));
530 return vertices_map.find(vid)->second;
531 }
532
533 //! @brief True when vid is in the graph
has_vertex(int64_t vid) const534 bool has_vertex(int64_t vid) const {
535 return vertices_map.find(vid) != vertices_map.end();
536 }
537
538
539
540 //! @name to be or not to be
541 //@{
542
is_directed() const543 bool is_directed() const {return m_gType == DIRECTED;}
is_undirected() const544 bool is_undirected() const {return m_gType == UNDIRECTED;}
is_source(V v_idx,E e_idx) const545 bool is_source(V v_idx, E e_idx) const {return v_idx == source(e_idx);}
is_target(V v_idx,E e_idx) const546 bool is_target(V v_idx, E e_idx) const {return v_idx == target(e_idx);}
547
548 //@}
549
550 //! @name boost wrappers with V
551 //@{
552
553
operator [](E e_idx)554 T_E& operator[](E e_idx) {return graph[e_idx];}
operator [](E e_idx) const555 const T_E& operator[](E e_idx) const {return graph[e_idx];}
556
operator [](V v_idx)557 T_V& operator[](V v_idx) {return graph[v_idx];}
operator [](V v_idx) const558 const T_V& operator[](V v_idx) const {return graph[v_idx];}
559
source(E e_idx) const560 V source(E e_idx) const {return boost::source(e_idx, graph);}
target(E e_idx) const561 V target(E e_idx) const {return boost::target(e_idx, graph);}
adjacent(V v_idx,E e_idx) const562 V adjacent(V v_idx, E e_idx) const {
563 pgassert(is_source(v_idx, e_idx) || is_target(v_idx, e_idx));
564 return is_source(v_idx, e_idx)?
565 target(e_idx) :
566 source(e_idx);
567 }
568
569
570 /*! @brief in degree of a vertex
571 *
572 * - when its undirected there is no "concept" of in degree
573 * - out degree is returned
574 * - on directed in degree of vertex is returned
575 */
in_degree(V & v) const576 degree_size_type in_degree(V &v) const {
577 return is_directed()?
578 boost::in_degree(v, graph) :
579 boost::out_degree(v, graph);
580 }
581
582 /*! @brief out degree of a vertex
583 *
584 * regardles of undirected or directed graph
585 * - out degree is returned
586 */
out_degree(V & v) const587 degree_size_type out_degree(V &v) const {
588 return boost::out_degree(v, graph);
589 }
590
591 //@}
592
593
594 //! @name edge disconection/reconnection
595 //@{
596 //! @brief Disconnects all edges from p_from to p_to
597 /*!
598 - No edge is disconnected if the vertices id's do not exist in the graph
599 - All removed edges are stored for future reinsertion
600 - All parallel edges are disconnected (automatically by boost)
601 ![disconnect_edge(2,3) on an UNDIRECTED graph](disconnectEdgeUndirected.png)
602 ![disconnect_edge(2,3) on a DIRECTED graph](disconnectEdgeDirected.png)
603 @param [in] p_from original vertex id of the starting point of the edge
604 @param [in] p_to original vertex id of the ending point of the edge
605 */
606 void disconnect_edge(int64_t p_from, int64_t p_to);
607
608
609 //! @brief Disconnects the outgoing edges of a vertex
610 /*!
611 - No edge is disconnected if it doesn't exist in the graph
612 - Removed edges are stored for future reinsertion
613 - all outgoing edges with the edge_id are removed if they exist
614 @param [in] vertex_id original vertex
615 @param [in] edge_id original edge_id
616 */
617 void disconnect_out_going_edge(int64_t vertex_id, int64_t edge_id);
618
619
620
621
622 //! @brief Disconnects all incoming and outgoing edges from the vertex
623 /*!
624 boost::graph doesn't recommend th to insert/remove vertices, so a vertex removal is
625 simulated by disconnecting the vertex from the graph
626 - No edge is disconnected if the vertices id's do not exist in the graph
627 - All removed edges are stored for future reinsertion
628 - All parallel edges are disconnected (automatically by boost)
629 ![disconnect_vertex(2) on an UNDIRECTED graph](disconnectVertexUndirected.png)
630 ![disconnect_vertex(2) on a DIRECTED graph](disconnectVertexDirected.png)
631 @param [in] p_vertex original vertex id of the starting point of the edge
632 */
633 void disconnect_vertex(int64_t p_vertex);
634 void disconnect_vertex(V vertex);
635
636
637 //! @brief Reconnects all edges that were removed
638 void restore_graph();
639
640 //@}
641
642 //! @name only for stand by program
643 //@{
644
operator <<(std::ostream & log,const Pgr_base_graph<G,T_V,T_E> & g)645 friend std::ostream& operator<<(
646 std::ostream &log, const Pgr_base_graph< G, T_V, T_E > &g) {
647 typename Pgr_base_graph< G, T_V, T_E >::EO_i out, out_end;
648
649 for (auto vi = vertices(g.graph).first;
650 vi != vertices(g.graph).second; ++vi) {
651 if ((*vi) >= g.num_vertices()) break;
652 log << (*vi) << ": " << " out_edges_of(" << g.graph[(*vi)] << "):";
653 for (boost::tie(out, out_end) = out_edges(*vi, g.graph);
654 out != out_end; ++out) {
655 log << ' '
656 << g.graph[*out].id << "=("
657 << g[g.source(*out)].id << ", "
658 << g[g.target(*out)].id << ") = "
659 << g.graph[*out].cost <<"\t";
660 }
661 log << std::endl;
662 }
663 return log;
664 }
665
666 //@}
667
668
669 int64_t get_edge_id(V from, V to, double &distance) const;
670
get_edge(V from,V to,double & distance) const671 E get_edge(
672 V from,
673 V to,
674 double &distance) const {
675 E e;
676 EO_i out_i, out_end;
677 V v_source, v_target;
678 double minCost = (std::numeric_limits<double>::max)();
679 E minEdge;
680 bool valid = false;
681 for (boost::tie(out_i, out_end) = boost::out_edges(from, graph);
682 out_i != out_end; ++out_i) {
683 e = *out_i;
684 if (!valid) {
685 minEdge = e;
686 valid = true;
687 }
688 v_target = target(e);
689 v_source = source(e);
690 if ((from == v_source) && (to == v_target)
691 && (distance == graph[e].cost)) {
692 return e;
693 }
694 if ((from == v_source) && (to == v_target)
695 && (minCost > graph[e].cost)) {
696 minCost = graph[e].cost;
697 minEdge = e;
698 }
699 }
700 return minEdge;
701 }
702
num_vertices() const703 size_t num_vertices() const { return boost::num_vertices(graph);}
num_edges() const704 size_t num_edges() const { return boost::num_edges(graph);}
705
706
707 void graph_add_edge(const T_E &edge);
708
709 template < typename T >
710 void graph_add_edge(const T &edge, bool normal = true);
711
712 template < typename T >
713 void graph_add_min_edge_no_parallel(const T &edge);
714
715 template < typename T >
716 void graph_add_neg_edge(const T &edge, bool normal = true);
717 /**
718 * Use this function when the vertices are already inserted in the graph
719 */
720 template < typename T>
graph_add_edge_no_create_vertex(const T & edge)721 void graph_add_edge_no_create_vertex(const T &edge) {
722 bool inserted;
723 E e;
724 if ((edge.cost < 0) && (edge.reverse_cost < 0))
725 return;
726
727 #if 0
728 std::ostringstream log;
729 for (auto iter = vertices_map.begin();
730 iter != vertices_map.end();
731 iter++) {
732 log << "Key: " << iter->first <<"\tValue:" << iter->second << "\n";
733 }
734 pgassertwm(has_vertex(edge.source), log.str().c_str());
735 pgassert(has_vertex(edge.target));
736 #endif
737
738 auto vm_s = get_V(edge.source);
739 auto vm_t = get_V(edge.target);
740
741
742 if (edge.cost >= 0) {
743 boost::tie(e, inserted) =
744 boost::add_edge(vm_s, vm_t, graph);
745 graph[e].cost = edge.cost;
746 graph[e].id = edge.id;
747 }
748
749
750 if (edge.reverse_cost >= 0 && (is_directed()
751 || (is_undirected() && edge.cost != edge.reverse_cost))) {
752 boost::tie(e, inserted) =
753 boost::add_edge(vm_t, vm_s, graph);
754 graph[e].cost = edge.reverse_cost;
755 graph[e].id = edge.id;
756 }
757 }
758 };
759
760
761
762
763 template < class G, typename T_V, typename T_E >
764 void
disconnect_edge(int64_t p_from,int64_t p_to)765 Pgr_base_graph< G, T_V, T_E >::disconnect_edge(int64_t p_from, int64_t p_to) {
766 T_E d_edge;
767
768 // nothing to do, the vertex doesn't exist
769 if (!has_vertex(p_from) || !has_vertex(p_to)) return;
770
771 EO_i out, out_end;
772 V g_from(get_V(p_from));
773 V g_to(get_V(p_to));
774
775 // store the edges that are going to be removed
776 for (boost::tie(out, out_end) = out_edges(g_from, graph);
777 out != out_end; ++out) {
778 if (target(*out) == g_to) {
779 d_edge.id = graph[*out].id;
780 d_edge.source = graph[source(*out)].id;
781 d_edge.target = graph[target(*out)].id;
782 d_edge.cost = graph[*out].cost;
783 removed_edges.push_back(d_edge);
784 }
785 }
786 // the actual removal
787 boost::remove_edge(g_from, g_to, graph);
788 }
789
790
791
792 template < class G, typename T_V, typename T_E >
793 void
disconnect_out_going_edge(int64_t vertex_id,int64_t edge_id)794 Pgr_base_graph< G, T_V, T_E >::disconnect_out_going_edge(
795 int64_t vertex_id, int64_t edge_id) {
796 T_E d_edge;
797
798 // nothing to do, the vertex doesn't exist
799 if (!has_vertex(vertex_id)) return;
800 auto v_from(get_V(vertex_id));
801
802 EO_i out, out_end;
803 bool change = true;
804 // store the edge that are going to be removed
805 while (change) {
806 change = false;
807 for (boost::tie(out, out_end) = out_edges(v_from, graph);
808 out != out_end; ++out) {
809 if (graph[*out].id == edge_id) {
810 d_edge.id = graph[*out].id;
811 d_edge.source = graph[source(*out)].id;
812 d_edge.target = graph[target(*out)].id;
813 d_edge.cost = graph[*out].cost;
814 removed_edges.push_back(d_edge);
815 boost::remove_edge((*out), graph);
816 change = true;
817 break;
818 }
819 }
820 }
821 }
822
823
824 template < class G, typename T_V, typename T_E >
825 void
disconnect_vertex(int64_t vertex)826 Pgr_base_graph< G, T_V, T_E >::disconnect_vertex(int64_t vertex) {
827 if (!has_vertex(vertex)) return;
828 disconnect_vertex(get_V(vertex));
829 }
830
831 template < class G, typename T_V, typename T_E >
832 void
disconnect_vertex(V vertex)833 Pgr_base_graph< G, T_V, T_E >::disconnect_vertex(V vertex) {
834 T_E d_edge;
835
836 EO_i out, out_end;
837 // store the edges that are going to be removed
838 for (boost::tie(out, out_end) = out_edges(vertex, graph);
839 out != out_end; ++out) {
840 d_edge.id = graph[*out].id;
841 d_edge.source = graph[source(*out)].id;
842 d_edge.target = graph[target(*out)].id;
843 d_edge.cost = graph[*out].cost;
844 removed_edges.push_back(d_edge);
845 }
846
847 // special case
848 if (m_gType == DIRECTED) {
849 EI_i in, in_end;
850 for (boost::tie(in, in_end) = in_edges(vertex, graph);
851 in != in_end; ++in) {
852 d_edge.id = graph[*in].id;
853 d_edge.source = graph[source(*in)].id;
854 d_edge.target = graph[target(*in)].id;
855 d_edge.cost = graph[*in].cost;
856 removed_edges.push_back(d_edge);
857 }
858 }
859
860 // delete incoming and outgoing edges from the vertex
861 boost::clear_vertex(vertex, graph);
862 }
863
864 template < class G, typename T_V, typename T_E >
865 void
restore_graph()866 Pgr_base_graph< G, T_V, T_E >::restore_graph() {
867 while (removed_edges.size() != 0) {
868 graph_add_edge(removed_edges[0]);
869 removed_edges.pop_front();
870 }
871 }
872
873
874
875
876 template < class G, typename T_V, typename T_E >
877 int64_t
get_edge_id(V from,V to,double & distance) const878 Pgr_base_graph< G, T_V, T_E >::get_edge_id(
879 V from,
880 V to,
881 double &distance) const {
882 E e;
883 EO_i out_i, out_end;
884 V v_source, v_target;
885 double minCost = (std::numeric_limits<double>::max)();
886 int64_t minEdge = -1;
887 for (boost::tie(out_i, out_end) = boost::out_edges(from, graph);
888 out_i != out_end; ++out_i) {
889 e = *out_i;
890 v_target = target(e);
891 v_source = source(e);
892 if ((from == v_source) && (to == v_target)
893 && (distance == graph[e].cost))
894 return graph[e].id;
895 if ((from == v_source) && (to == v_target)
896 && (minCost > graph[e].cost)) {
897 minCost = graph[e].cost;
898 minEdge = graph[e].id;
899 }
900 }
901 distance = minEdge == -1? 0: minCost;
902 return minEdge;
903 }
904
905
906 template < class G, typename T_V, typename T_E >
907 void
graph_add_edge(const T_E & edge)908 Pgr_base_graph< G, T_V, T_E >::graph_add_edge(const T_E &edge ) {
909 typename Pgr_base_graph< G, T_V, T_E >::LI vm_s, vm_t;
910 typename Pgr_base_graph< G, T_V, T_E >::E e;
911
912 vm_s = vertices_map.find(edge.source);
913 if (vm_s == vertices_map.end()) {
914 vertices_map[edge.source]= num_vertices();
915 vm_s = vertices_map.find(edge.source);
916 }
917
918 vm_t = vertices_map.find(edge.target);
919 if (vm_t == vertices_map.end()) {
920 vertices_map[edge.target]= num_vertices();
921 vm_t = vertices_map.find(edge.target);
922 }
923
924 if (edge.cost >= 0) {
925 bool inserted;
926 boost::tie(e, inserted) =
927 boost::add_edge(vm_s->second, vm_t->second, graph);
928 graph[e].cp_members(edge);
929 }
930 }
931
932
933 template < class G, typename T_V, typename T_E >
934 template < typename T>
935 void
graph_add_edge(const T & edge,bool normal)936 Pgr_base_graph< G, T_V, T_E >::graph_add_edge(const T &edge, bool normal) {
937 bool inserted;
938 typename Pgr_base_graph< G, T_V, T_E >::E e;
939 if ((edge.cost < 0) && (edge.reverse_cost < 0))
940 return;
941
942 /*
943 * true: for source
944 * false: for target
945 */
946 auto vm_s = get_V(T_V(edge, true));
947 auto vm_t = get_V(T_V(edge, false));
948
949 pgassert(vertices_map.find(edge.source) != vertices_map.end());
950 pgassert(vertices_map.find(edge.target) != vertices_map.end());
951 if (edge.cost >= 0) {
952 boost::tie(e, inserted) =
953 boost::add_edge(vm_s, vm_t, graph);
954 graph[e].cost = edge.cost;
955 graph[e].id = edge.id;
956 }
957
958 if (edge.reverse_cost >= 0
959 && (m_gType == DIRECTED
960 || (m_gType == UNDIRECTED && edge.cost != edge.reverse_cost))) {
961 boost::tie(e, inserted) =
962 boost::add_edge(vm_t, vm_s, graph);
963
964 graph[e].cost = edge.reverse_cost;
965 graph[e].id = normal? edge.id : -edge.id;
966 }
967 }
968
969 template < class G, typename T_V, typename T_E >
970 template < typename T>
971 void
graph_add_min_edge_no_parallel(const T & edge)972 Pgr_base_graph< G, T_V, T_E >::graph_add_min_edge_no_parallel(const T &edge) {
973 bool inserted;
974 typename Pgr_base_graph< G, T_V, T_E >::E e;
975 if ((edge.cost < 0) && (edge.reverse_cost < 0))
976 return;
977
978 /*
979 * true: for source
980 * false: for target
981 */
982 auto vm_s = get_V(T_V(edge, true));
983 auto vm_t = get_V(T_V(edge, false));
984
985 pgassert(vertices_map.find(edge.source) != vertices_map.end());
986 pgassert(vertices_map.find(edge.target) != vertices_map.end());
987 if (edge.cost >= 0) {
988 E e1;
989 bool found;
990 boost::tie(e1, found) = edge(vm_s, vm_t, graph);
991 if (found) {
992 if (edge.cost < graph[e1].cost) {
993 graph[e1].cost = edge.cost;
994 graph[e1].id = edge.id;
995 }
996 } else {
997 boost::tie(e, inserted) =
998 boost::add_edge(vm_s, vm_t, graph);
999 graph[e].cost = edge.cost;
1000 graph[e].id = edge.id;
1001 }
1002 }
1003
1004 if (edge.reverse_cost >= 0
1005 && (m_gType == DIRECTED
1006 || (m_gType == UNDIRECTED && edge.cost != edge.reverse_cost))) {
1007 E e1;
1008 bool found;
1009 boost::tie(e1, found) = edge(vm_t, vm_s, graph);
1010 if (found) {
1011 if (edge.reverse_cost < graph[e1].cost) {
1012 graph[e1].cost = edge.reverse_cost;
1013 graph[e1].id = edge.id;
1014 }
1015 } else {
1016 boost::tie(e, inserted) =
1017 boost::add_edge(vm_t, vm_s, graph);
1018
1019 graph[e].cost = edge.reverse_cost;
1020 graph[e].id = edge.id;
1021 }
1022 }
1023 }
1024
1025 #if 1
1026 /*
1027 Add edges with negative cost(either cost or reverse_cost or both)
1028 Reading them into graph as positive cost ( edge_cost = (-1)* edge_negative_cost) [L931 & L941]
1029 To Do: Read and apply edges with negative cost in function as it is
1030 */
1031
1032 template < class G, typename T_V, typename T_E >
1033 template < typename T>
1034 void
graph_add_neg_edge(const T & edge,bool normal)1035 Pgr_base_graph< G, T_V, T_E >::graph_add_neg_edge(const T &edge, bool normal) {
1036 bool inserted;
1037 typename Pgr_base_graph< G, T_V, T_E >::E e;
1038
1039 auto vm_s = get_V(T_V(edge, true));
1040 auto vm_t = get_V(T_V(edge, false));
1041
1042 pgassert(vertices_map.find(edge.source) != vertices_map.end());
1043 pgassert(vertices_map.find(edge.target) != vertices_map.end());
1044
1045 boost::tie(e, inserted) =
1046 boost::add_edge(vm_s, vm_t, graph);
1047 if (edge.cost < 0) {
1048 // reading negative edges as positive
1049 graph[e].cost = (-0.5)*edge.cost;
1050 } else {
1051 graph[e].cost = edge.cost;
1052 }
1053 graph[e].id = edge.id;
1054
1055 if (m_gType == DIRECTED
1056 || (m_gType == UNDIRECTED && edge.cost > edge.reverse_cost)) {
1057 boost::tie(e, inserted) =
1058 boost::add_edge(vm_t, vm_s, graph);
1059 if (edge.reverse_cost < 0) {
1060 // reading negative edges as positive
1061 graph[e].cost = (-0.5)*edge.reverse_cost;
1062 } else {
1063 graph[e].cost = edge.reverse_cost;
1064 }
1065
1066 graph[e].id = normal? edge.id : -edge.id;
1067 }
1068 }
1069 #endif
1070
1071 /****************** PRIVATE *******************/
1072
1073 } // namespace graph
1074 } // namespace pgrouting
1075 #endif // INCLUDE_CPP_COMMON_PGR_BASE_GRAPH_HPP_
1076