├── .cproject
├── .project
├── LICENSE
├── README.md
├── app.cpp
├── graph.h
├── graphics_item.h
├── helper_functions.cpp
├── helper_functions.h
├── main_window.cpp
├── main_window.h
├── main_window_moc.cpp
├── mp.jar
├── number_type.h
├── resources
├── app.ico
├── fitview.png
├── hexcycle.png
├── hexgrid.png
├── open.png
├── play.png
├── sg.png
└── solution.png
├── roadmap-generator-vc10
├── make-moc.vcxproj
├── make-moc.vcxproj.filters
├── make-moc.vcxproj.user
├── roadmap-generator-vc10.sln
├── roadmap-generator-vc10.suo
├── roadmap-generator-vc10.vcxproj
├── roadmap-generator-vc10.vcxproj.filters
└── roadmap-generator-vc10.vcxproj.user
├── roadmap.cpp
├── roadmap.h
├── shortest_path
└── README
├── test-envs
├── cross.txt
├── empty.txt
├── regular.txt
├── tirangles.txt
└── vertical.txt
├── types.h
└── vc10
└── main_window_moc.cpp
/.cproject:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
38 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
63 |
64 |
67 |
68 |
69 |
70 |
71 |
72 |
77 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 |
110 |
111 |
114 |
122 |
123 |
124 |
125 |
126 |
127 |
128 |
129 |
130 |
131 |
132 |
133 |
134 |
140 |
141 |
142 |
143 |
144 |
145 |
146 |
147 |
148 |
149 |
150 |
151 |
152 |
153 |
154 |
155 |
156 |
157 |
158 |
159 |
160 |
161 |
162 |
163 |
164 |
165 |
166 |
167 |
168 |
169 |
170 |
171 |
172 |
173 |
174 |
175 |
176 |
177 |
178 |
179 |
180 |
181 |
182 |
183 |
184 |
185 |
186 |
187 |
--------------------------------------------------------------------------------
/.project:
--------------------------------------------------------------------------------
1 |
2 |
3 | optimal-mrpp-continuous
4 |
5 |
6 |
7 |
8 |
9 | org.eclipse.cdt.managedbuilder.core.genmakebuilder
10 | clean,full,incremental,
11 |
12 |
13 |
14 |
15 | org.eclipse.cdt.managedbuilder.core.ScannerConfigBuilder
16 | full,incremental,
17 |
18 |
19 |
20 |
21 |
22 | org.eclipse.cdt.core.cnature
23 | org.eclipse.cdt.core.ccnature
24 | org.eclipse.cdt.managedbuilder.core.managedBuildNature
25 | org.eclipse.cdt.managedbuilder.core.ScannerConfigNature
26 |
27 |
28 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | All components of this library are licensed under the BSD 3-Clause
2 | License.
3 |
4 | Copyright (c) 2015-, Rutgers Algorithmic Robotics and Control Group
5 | (https://arc.cs.rutgers.edu). All rights reserved.
6 |
7 | Redistribution and use in source and binary forms, with or without
8 | modification, are permitted provided that the following conditions are
9 | met:
10 |
11 | * Redistributions of source code must retain the above copyright notice,
12 | this list of conditions and the following disclaimer.
13 |
14 | * Redistributions in binary form must reproduce the above copyright
15 | notice, this list of conditions and the following disclaimer in the
16 | documentation and/or other materials provided with the distribution.
17 |
18 | * Neither the name of the copyright holder nor the names of its
19 | contributors may be used to endorse or promote products derived from
20 | this software without specific prior written permission.
21 |
22 |
23 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
24 | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
25 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
26 | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
27 | HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
28 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
29 | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
30 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
31 | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
32 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
33 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
34 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | ###Optimal Multi-Robot Path Planning in 2D Continuous Domain
2 |
3 |
4 | 
5 |
6 |
7 | Cross platform C++ source code used in the following work
8 |
9 | J. Yu and D. Rus. An Effective Algorithmic Framework for Near Optimal Multi-Robot Path Planning. The 2015 International Symposium on Robotics Research (ISRR 2015).
10 |
11 | ###Requires
12 |
13 | Boost (1.55.0 used): http://www.boost.org/
14 | Compile shared library for your platform.
15 |
16 | CGAL (4.3 used): http://www.cgal.org/
17 | Use CMAKE to generate and compile for your platform.
18 |
19 | Gurobi (6.5+): http://www.gurobi.com/
20 | Install and make gurobi.jar (as well as mp.jar) available to the executable.
21 |
22 | LibQGLViewer (2.6): http://libqglviewer.com/
23 | Obtain the distribution and made available for CGAL to use.
24 |
25 | Qt (4.8.2 used): https://www.qt.io/
26 | Install and make moc.exe available to run on command line.
27 |
28 | Visilibity: http://visilibity.org/
29 | See README under shortest_path folder for instructions on this library.
30 |
31 |
--------------------------------------------------------------------------------
/app.cpp:
--------------------------------------------------------------------------------
1 | /*
2 | * Main app class
3 | *
4 | * Created on: Jan 30, 2015
5 | * Author: Jingjin Yu
6 | */
7 |
8 | #include "helper_functions.h"
9 | #include "main_window.h"
10 |
11 | // Qt headers
12 | #include
13 | #include
14 | #include
15 | #include
16 | #include
17 |
18 | // GraphicsView items and event filters (input classes)
19 | #include
20 | #include
21 | #include
22 | #include
23 |
24 | // Base window class
25 | #include
26 | #include
27 |
28 |
29 | int main(int argc, char* argv[]){
30 | QApplication a(argc, argv, true, 0);
31 | MainWindow mainWindow(&a, (argc > 1 ? QString(argv[1]) : QString("F:\\temp\\mr")), "Multi-Robot Path Planning", "./resources/app.ico", false);
32 | mainWindow.show();
33 |
34 |
35 | return a.exec();
36 | }
37 |
--------------------------------------------------------------------------------
/graph.h:
--------------------------------------------------------------------------------
1 | /*
2 | * A basic adjacency list based simple, undirected graph in which each vertex is indexed
3 | * with an integer ID.
4 | *
5 | * Created on: Jan 30, 2015
6 | * Author: Jingjin Yu
7 | */
8 |
9 | #ifndef _O_GRAPH_H_
10 | #define _O_GRAPH_H_
11 |
12 | #include "types.h"
13 |
14 | #include
15 | #include
16 | #include
17 | #include
18 |
19 | class Graph{
20 | private:
21 | std::set vSet;
22 | std::map > adjSetMap;
23 | std::set > edgeSet;
24 | std::set emptySet;
25 |
26 | public:
27 | // =====================================================================================
28 | // Core methods
29 | // =====================================================================================
30 |
31 | Graph(){}
32 |
33 | void clear(){
34 | vSet.clear();
35 | adjSetMap.clear();
36 | edgeSet.clear();
37 | emptySet.clear();
38 | }
39 |
40 | bool hasVertex(int v){
41 | return (vSet.find(v) != vSet.end());
42 | }
43 |
44 | std::set &getVertexSet(){return vSet;}
45 |
46 | void removeVertex(int v){
47 | // Delete all edges from the vertex
48 | std::set nbrSet = getNeighborSet(v);
49 | for(std::set::iterator vit = nbrSet.begin(); vit != nbrSet.end(); vit++){
50 | removeEdge(v, *vit);
51 | }
52 |
53 | // Erase the vertex itself
54 | vSet.erase(v);
55 | }
56 |
57 | void addEdge(int v1, int v2){
58 | // Need to add vertex?
59 | if(vSet.find(v1) == vSet.end()){vSet.insert(v1);adjSetMap[v1] = std::set();}
60 | if(vSet.find(v2) == vSet.end()){vSet.insert(v2);adjSetMap[v2] = std::set();}
61 | // Adding edges as needed
62 | adjSetMap[v1].insert(v2);
63 | adjSetMap[v2].insert(v1);
64 | edgeSet.insert(std::pair(v1 < v2? v1 : v2, v1 < v2? v2 : v1));
65 | }
66 |
67 | std::set > &getEdgeSet(){return edgeSet;}
68 |
69 | void removeEdge(int v1, int v2){
70 | // Check that we have the vertices
71 | if(vSet.find(v1) == vSet.end() || vSet.find(v2) == vSet.end()) return;
72 |
73 | // Remove edges as needed
74 | adjSetMap[v1].erase(v2);
75 | adjSetMap[v2].erase(v1);
76 | edgeSet.erase(std::pair(v1 < v2? v1 : v2, v1 < v2? v2 : v1));
77 |
78 | // Remove v1, v2 as needed
79 | if(adjSetMap[v1].size() == 0){vSet.erase(v1); adjSetMap.erase(v1);}
80 | if(adjSetMap[v2].size() == 0){vSet.erase(v2); adjSetMap.erase(v2);}
81 | }
82 |
83 | bool hasEdge(int v1, int v2){
84 | // Check we have vertex
85 | if(vSet.find(v1)!=vSet.end()){
86 | return (adjSetMap[v1].find(v2) != adjSetMap[v1].end());
87 | }
88 | return false;
89 | }
90 |
91 | std::set& getNeighborSet(int v){
92 | if(vSet.find(v)!=vSet.end()){
93 | return adjSetMap[v];
94 | }
95 | return emptySet;
96 | }
97 |
98 |
99 |
100 | // =====================================================================================
101 | // Auxiliary methods
102 | // =====================================================================================
103 |
104 | // If the graph is a cycle, this function returns the vertices of the cycle
105 | // ordered sequentially
106 | void getCycleVertexVector(std::vector& vVec){
107 | if(vSet.size() == 0) return;
108 | std::set processedVertexSet;
109 | // Start from a vertex and retrive other vertices in order. We assume that
110 | // the cycle is big enough
111 | int vStart = *(vSet.begin());
112 | vVec.push_back(vStart);
113 | processedVertexSet.insert(vStart);
114 | int vNext = *(getNeighborSet(vStart).begin());
115 | while(vSet.size() > vVec.size()){
116 | vVec.push_back(vNext);
117 | processedVertexSet.insert(vNext);
118 | std::set::iterator vit = getNeighborSet(vNext).begin();
119 | vNext = *vit++;
120 | if(processedVertexSet.find(vNext) != processedVertexSet.end()){
121 | vNext = *vit;
122 | }
123 | }
124 | }
125 |
126 |
127 | };
128 |
129 | #endif //_O_GRAPH_H_
130 |
--------------------------------------------------------------------------------
/graphics_item.h:
--------------------------------------------------------------------------------
1 | /*
2 | * A GraphicsItem derived class to enable the filling of the inside of a polygonal region.
3 | * Qt GraphicsItem class does not do filling by default (at least as of 4.8.5).
4 | *
5 | * Created on: Jan 30, 2015
6 | * Author: Jingjin Yu
7 | */
8 |
9 | #ifndef _O_ADV_GRAPHICS_ITEM_H_
10 | #define _O_ADV_GRAPHICS_ITEM_H_
11 |
12 | #include "types.h"
13 | #include "roadmap.h"
14 |
15 | #include
16 | #include
17 |
18 | #include
19 | #include
20 | #include
21 |
22 | template
23 | class AdvancedGraphicsItem: public CGAL::Qt::PolygonGraphicsItem {
24 | public:
25 | bool m_bShowVertices; // Draw vertices?
26 | bool m_bShowEdge; // Draw edges?
27 | bool m_bFill; // Fill the polygon?
28 |
29 | QPen m_vertexPen; // Vertex pen
30 | QPen m_edgePen; // Edge pen
31 | QBrush m_fillBrush; // Fill brush
32 |
33 | // Need this constructor to take a T* pointer
34 | AdvancedGraphicsItem(T* p);
35 |
36 | // We need to overwrite paint method to do custom rendering such as filling the area. This
37 | // is not provided by default by QGraphicsItem in any other way.
38 | void paint( QPainter * painter, const QStyleOptionGraphicsItem * option, QWidget * widget);
39 | };
40 |
41 | template AdvancedGraphicsItem
42 | ::AdvancedGraphicsItem(T* p): CGAL::Qt::PolygonGraphicsItem(p),
43 | m_bShowVertices(false),m_bShowEdge(true), m_bFill(true),
44 | m_vertexPen(QPen(Qt::red, 0.025, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin)),
45 | m_edgePen(QPen(Qt::red, 0.025, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin)),
46 | m_fillBrush(QColor(Qt::gray)){}
47 |
48 |
49 | // We need to overwrite paint method to do custom rendering such as filling the area. This
50 | // is not provided by default by QGraphicsItem in any other way.
51 | template void AdvancedGraphicsItem
52 | ::paint( QPainter * painter, const QStyleOptionGraphicsItem * option, QWidget * widget){
53 |
54 | // Paint the edges
55 | if(m_bShowEdge){
56 | painter->setPen(m_edgePen);
57 | CGAL::Qt::PolygonGraphicsItem::painterostream = CGAL::Qt::PainterOstream(painter);
58 | if(CGAL::Qt::PolygonGraphicsItem::drawEdges()) {
59 | for(typename T::Edge_const_iterator eit = CGAL::Qt::PolygonGraphicsItem::poly->edges_begin();
60 | eit != CGAL::Qt::PolygonGraphicsItem::poly->edges_end();
61 | ++eit){
62 | CGAL::Qt::PolygonGraphicsItem::painterostream << *eit;
63 | }
64 | }
65 | }
66 |
67 | // Paint vertices if needed and obtain the fill area
68 | if(m_bShowVertices || m_bFill){
69 | CGAL::Qt::Converter convert;
70 | painter->setPen(m_vertexPen);
71 | QMatrix matrix = painter->matrix();
72 | painter->resetMatrix();
73 | QPainterPath path;
74 | for(typename T::Vertex_iterator it = CGAL::Qt::PolygonGraphicsItem::poly->vertices_begin();
75 | it != CGAL::Qt::PolygonGraphicsItem::poly->vertices_end();
76 | it++){
77 | QPointF point = matrix.map(convert(*it));
78 | // Draw vertices here as needed
79 | if(m_bShowVertices){
80 | painter->drawPoint(point);
81 | }
82 | if(it == CGAL::Qt::PolygonGraphicsItem::poly->vertices_begin()){
83 | path.moveTo(point.rx(), point.ry());
84 | }
85 | else{
86 | path.lineTo(point.rx(), point.ry());
87 | }
88 | }
89 | path.closeSubpath();
90 | // Fill the area if needed
91 | if(m_bFill){
92 | painter->fillPath(path, QBrush(m_fillBrush));
93 | }
94 | }
95 | }
96 |
97 | #endif /* _O_ADV_GRAPHICS_ITEM_H_ */
98 |
--------------------------------------------------------------------------------
/helper_functions.cpp:
--------------------------------------------------------------------------------
1 | /*
2 | * Helper function implementations
3 | *
4 | * Created on: Jan 30, 2015
5 | * Author: Jingjin Yu
6 | */
7 | #include "helper_functions.h"
8 |
9 | void populateApproximateDisc(Polygon_2 &poly, Point_2 ¢er, double radius, int segments){
10 | for(int i = 0; i < segments; i ++){
11 | poly.push_back (Point_2 ( center.x() + radius*cos(i*PI*2/segments), center.y() + radius*sin(i*PI*2/segments)));
12 | }
13 | }
14 |
15 | Polygon_2 growPolygonByRadius(Polygon_2 &poly, double radius, int segments){
16 | // Get the disk for computing Minkowski sum
17 | Polygon_2 disc;
18 | Point_2 p(0, 0);
19 | populateApproximateDisc(disc, p, radius, segments);
20 |
21 | // Do computation
22 | if(!poly.is_clockwise_oriented()){
23 | poly.reverse_orientation();
24 | }
25 | return minkowski_sum_2 (poly, disc).outer_boundary();
26 | }
27 |
28 | double getPathLength(std::list path){
29 | double length = 0;
30 | std::list::iterator vit = path.begin();
31 | CGAL::Cartesian_converter K_ICK_converter;
32 | if(vit != path.end()){
33 | ICPoint_2 p = K_ICK_converter(*vit);
34 | vit++;
35 | for(; vit != path.end(); vit++){
36 | ICPoint_2 p2 = K_ICK_converter(*vit);
37 | length += sqrt((p2.x() - p.x())*(p2.x() - p.x()) + (p2.y() - p.y())*(p2.y() - p.y()));
38 | p = p2;
39 | }
40 | }
41 | return length;
42 | }
43 |
44 | double getDistance(Point_2& p1x, Point_2& p2x){
45 | static CGAL::Cartesian_converter K_ICK_converter;
46 | ICPoint_2 p1 = K_ICK_converter(p1x);
47 | ICPoint_2 p2 = K_ICK_converter(p2x);
48 | return sqrt((p2.x() - p1.x())*(p2.x() - p1.x()) + (p2.y() - p1.y())*(p2.y() - p1.y()));
49 | }
50 |
51 | double getDistance(Point_2& p, double x, double y){
52 | static CGAL::Cartesian_converter K_ICK_converter;
53 | ICPoint_2 pp = K_ICK_converter(p);
54 | return sqrt((pp.x() - x)*(pp.x() - x) + (pp.y() - y)*(pp.y() - y));
55 | }
56 |
57 | void getAllPairsShortestPath (Graph* pGraph, map > &dist){
58 | int V = pGraph->getVertexSet().size();
59 |
60 | /* dist[][] will be the output matrix that will finally have the shortest
61 | distances between every pair of vertices */
62 | int i, j, k;
63 |
64 | /* Initialize the solution matrix same as input graph matrix. Or
65 | we can say the initial values of shortest distances are based
66 | on shortest paths considering no intermediate vertex. */
67 | for (i = 0; i < V; i++)
68 | {
69 | for (j = 0; j < V; j++){
70 | dist[i][j] = (pGraph->hasEdge(i, j) ? 1 : (i == j?0:100000000));
71 | }
72 | }
73 |
74 | /* Add all vertices one by one to the set of intermediate vertices.
75 | ---> Before start of a iteration, we have shortest distances between all
76 | pairs of vertices such that the shortest distances consider only the
77 | vertices in set {0, 1, 2, .. k-1} as intermediate vertices.
78 | ----> After the end of a iteration, vertex no. k is added to the set of
79 | intermediate vertices and the set becomes {0, 1, 2, .. k} */
80 | for (k = 0; k < V; k++)
81 | {
82 | // Pick all vertices as source one by one
83 | for (i = 0; i < V; i++)
84 | {
85 | // Pick all vertices as destination for the
86 | // above picked source
87 | for (j = 0; j < V; j++)
88 | {
89 | // If vertex k is on the shortest path from
90 | // i to j, then update the value of dist[i][j]
91 | if (dist[i][k] + dist[k][j] < dist[i][j])
92 | dist[i][j] = dist[i][k] + dist[k][j];
93 | }
94 | }
95 | }
96 | }
97 |
98 | void converFromCGALtoVisilibity(ECPolygon_2 &poly, Polygon &visiPoly, bool ccw){
99 | // Reverse orientation as needed
100 | if((poly.is_counterclockwise_oriented() && ccw == false) ||
101 | (!poly.is_counterclockwise_oriented() && ccw)){
102 | poly.reverse_orientation();
103 | }
104 |
105 | // Get the vertices and convert
106 | static CGAL::Cartesian_converter EK_ICK_converter;
107 | vector vp;
108 | for(ECPolygon_2::Vertex_iterator vi = poly.vertices_begin(); vi != poly.vertices_end(); vi++){
109 | ICPoint_2 p = EK_ICK_converter(*vi);
110 | vp.push_back(Point(p.x(), p.y()));
111 | }
112 |
113 | visiPoly.set_vertices(vp);
114 | }
115 |
116 | bool boundaryInterset(ECPolygon_2 &poly1, ECPolygon_2 &poly2){
117 | // Check edge by edge
118 | for(int i = 0; i < poly1.size(); i++){
119 | ECSegment_2 seg1 = poly1.edge(i);
120 | for(int j = 0; j < poly2.size(); j ++){
121 | ECSegment_2 seg2 = poly2.edge(j);
122 | if(CGAL::do_intersect(seg1, seg2)){return true;}
123 | }
124 | }
125 | return false;
126 | }
127 |
128 | ECPoint_2 convertToExactPoint(Point_2 &p){
129 | static CGAL::Cartesian_converter K_ICK_converter;
130 | ICPoint_2 pp = K_ICK_converter(p);
131 | return ECPoint_2(pp.x(), pp.y());
132 | }
133 |
134 |
135 | ECPolygon_2 convertToExactPolygon(Polygon_2 &poly){
136 | ECPolygon_2 ecPoly;
137 | for(Polygon_2::Vertex_iterator vi = poly.vertices_begin(); vi != poly.vertices_end(); vi ++){
138 | static CGAL::Cartesian_converter K_ICK_converter;
139 | ICPoint_2 pp = K_ICK_converter(*vi);
140 | ecPoly.push_back(ECPoint_2(pp.x(), pp.y()));
141 | }
142 | return ecPoly;
143 | }
144 |
--------------------------------------------------------------------------------
/helper_functions.h:
--------------------------------------------------------------------------------
1 | /*
2 | * Some helper functions for geometric computing
3 | *
4 | * Created on: Jan 30, 2015
5 | * Author: Jingjin Yu
6 | */
7 |
8 | #ifndef _O_CGAL_HELPER_H_
9 | #define _O_CGAL_HELPER_H_
10 |
11 | #include "types.h"
12 | #include "graph.h"
13 | #include "shortest_path/visilibity.hpp"
14 | #include