Commit 05952a79 authored by Valentin Platzgummer's avatar Valentin Platzgummer

123

parent b791a606
#include "OptimisationTools.h"
#include <QPointF>
namespace OptimisationTools {
namespace {
} // end anonymous namespace
/*!
* \fn bool dijkstraAlgorithm(int startIndex, int endIndex, const QList<T> elements, QList<T> &elementPath, double(*distance)(const T &t1, const T &t2))
* Calculates the shortest path between the elements stored in \a elements.
* The \l {Dijkstra Algorithm} is used to find the shorest path.
* Stores the result inside \a elementPath when sucessfull.
* The function handle \a distance is used to calculate the distance between two elements. The distance must be positive.
* Returns \c true if successful, \c false else.
*
* \sa QList
*/
template <class T>
bool dijkstraAlgorithm(const QList<T> &elements, int startIndex, int endIndex, QList<T> &elementPath, std::function<double(const T &, const T &)> distance); // don't seperate parameters with new lines or documentation will break
bool dijkstraAlgorithm(const int numElements, int startIndex, int endIndex, QVector<int> &elementPath, std::function<double (const int, const int)> distanceDij)
{
if ( numElements < 0
|| startIndex < 0
|| endIndex < 0
|| startIndex >= numElements
|| endIndex >= numElements) {
return false;
}
// Node struct
// predecessorIndex is the index of the predecessor node (nodeList[predecessorIndex])
// distance is the distance between the node and the start node
// node number is stored by the position in nodeList
struct Node{
int predecessorIndex = -1;
double distance = std::numeric_limits<qreal>::infinity();
};
// The list with all Nodes (elements)
QVector<Node> nodeList(numElements);
// This list will be initalized with (pointer to) all elements of nodeList.
// Elements will be successively remove during the execution of the Dijkstra Algorithm.
QVector<int> workingSet(numElements);
//append elements to node list
for (int i = 0; i < numElements; ++i) workingSet[i] = i;
nodeList[startIndex].distance = 0;
// qDebug() << "nodeList" ;
// for (auto node : nodeList) {
// qDebug() << "predecessor: " << node.predecessorIndex;
// qDebug() << "distance: " << node.distance;
// }
// qDebug() << "workingSet";
// for (auto node : workingSet) {
// qDebug() << "index: " << node;
// }
// Dijkstra Algorithm
// https://de.wikipedia.org/wiki/Dijkstra-Algorithmus
while (workingSet.size() > 0) {
// serach Node with minimal distance
double minDist = std::numeric_limits<qreal>::infinity();
int minDistIndex_WS = -1; // WS = workinSet
for (int i = 0; i < workingSet.size(); ++i) {
const int nodeIndex = workingSet.at(i);
const double dist = nodeList.at(nodeIndex).distance;
if (dist < minDist) {
minDist = dist;
minDistIndex_WS = i;
}
}
if (minDistIndex_WS == -1)
return false;
int indexU_NL = workingSet.takeAt(minDistIndex_WS); // NL = nodeList
if (indexU_NL == endIndex) // shortest path found
break;
const double distanceU = nodeList.at(indexU_NL).distance;
//update distance
for (int i = 0; i < workingSet.size(); ++i) {
int indexV_NL = workingSet[i]; // NL = nodeList
Node* v = &nodeList[indexV_NL];
double dist = distanceDij(indexU_NL, indexV_NL);
// is ther an alternative path which is shorter?
double alternative = distanceU + dist;
if (alternative < v->distance) {
v->distance = alternative;
v->predecessorIndex = indexU_NL;
}
}
qDebug() << "nodeList" ;
for (auto node : nodeList) {
qDebug() << "predecessor: " << node.predecessorIndex;
qDebug() << "distance: " << node.distance;
}
}
// end Djikstra Algorithm
// reverse assemble path
int e = endIndex;
while (1) {
if (e == -1) {
if (elementPath[0] == startIndex)// check if starting point was reached
break;
return false;
}
elementPath.prepend(e);
//Update Node
e = nodeList[e].predecessorIndex;
}
return true;
}
// don't seperate parameters with new lines or documentation will break
} // end OptimisationTools namespace
#pragma once
#include <QObject>
#include <QDebug>
#include <functional>
#include <QPointF>
#include <QVector>
namespace OptimisationTools {
/*!
* \fn bool dijkstraAlgorithm(int startIndex, int endIndex, const QList<T> elements, QList<T> &elementPath, double(*distance)(const T &t1, const T &t2))
* Calculates the shortest path between the elements stored in \a elements.
* The \l {Dijkstra Algorithm} is used to find the shorest path.
* Stores the result inside \a elementPath when sucessfull.
* The function handle \a distance is used to calculate the distance between two elements. The distance must be positive.
* Returns \c true if successful, \c false else.
*
* \sa QList
*/
template <class T>
bool dijkstraAlgorithm(const QList<T> &elements, int startIndex, int endIndex, QList<T> &elementPath, std::function<double(const T &, const T &)> distanceDij)
{
if ( elements.isEmpty() || startIndex < 0
|| startIndex >= elements.size() || endIndex < 0
|| endIndex >= elements.size()) {
return false;
}
//qWarning("optitools");
// Each element of type T gets stuff into a Node
/// @param distance is the distance between the Node and it's predecessor
struct Node{
T element;
double distance = std::numeric_limits<qreal>::infinity();
Node* predecessorNode = nullptr;
};
// The list with all Nodes (elements)
QList<Node> nodeList;
// This list will be initalized with (pointer to) all elements of nodeList.
// Elements will be successively remove during the execution of the Dijkstra Algorithm.
QList<Node*> workingSet;
//append elements to node list
for (int i = 0; i < elements.size(); i++) {
Node node;
node.element = elements[i];
nodeList.append(node);
workingSet.append(&nodeList[i]);
}
// double d1 = distanceDij(elements[0], elements[1]);
// double d2 = distanceDij(elements[0], elements[5]);
// double d3 = distanceDij(elements[5], elements[1]);
nodeList[startIndex].distance = 0;
// Dijkstra Algorithm
// https://de.wikipedia.org/wiki/Dijkstra-Algorithmus
while (workingSet.size() > 0) {
// serach Node with minimal distance
double minDist = std::numeric_limits<qreal>::infinity();
int minDistIndex = -1;
for (int i = 0; i < workingSet.size(); i++) {
Node* node = workingSet.value(i);
double dist = node->distance;
if (dist < minDist) {
minDist = dist;
minDistIndex = i;
}
}
if (minDistIndex == -1)
return false;
Node* u = workingSet.takeAt(minDistIndex);
if (u->element == elements[endIndex]) // shortest path found
break;
//update distance
for (int i = 0; i < workingSet.size(); i++) {
Node* v = workingSet[i];
double dist = distanceDij(u->element, v->element);
// is ther a alternative path which is shorter?
double alternative = u->distance + dist;
if (alternative < v->distance) {
v->distance = alternative;
v->predecessorNode = u;
}
}
}
// end Djikstra Algorithm
// reverse assemble path
Node* node = &nodeList[endIndex];
while (1) {
if (node == nullptr) {
if (elementPath[0] == elements[startIndex])// check if starting point was reached
break;
return false;
}
elementPath.prepend(node->element);
//Update Node
node = node->predecessorNode;
}
return true;
}
bool dijkstraAlgorithm(const int numElements, int startIndex, int endIndex, QVector<int> &elementPath, std::function<double(const int, const int)> distanceDij);
}
......@@ -475,7 +475,7 @@ namespace PolygonCalculus {
return;
}
bool shortestPath(QPolygonF polygon,const QPointF &startVertex, const QPointF &endVertex, QList<QPointF> &shortestPath)
bool shortestPath(QPolygonF polygon,const QPointF &startVertex, const QPointF &endVertex, QVector<QPointF> &shortestPath)
{
using namespace PlanimetryCalculus;
offsetPolygon(polygon, 0.01); // solves numerical errors
......@@ -484,22 +484,31 @@ namespace PolygonCalculus {
// lambda
QPolygonF polygon2 = polygon;
offsetPolygon(polygon2, 0.01); // solves numerical errors
std::function<double(const QPointF &, const QPointF &)> distanceDij = [polygon2](const QPointF &p1, const QPointF &p2) -> double {
QVector<QPointF> elementList;
elementList.append(startVertex);
elementList.append(endVertex);
for (auto vertex : polygon) elementList.append(vertex);
const int listSize = elementList.size();
std::function<double(const int, const int)> distanceDij = [polygon2, elementList](const int ind1, const int ind2) -> double {
QPointF p1 = elementList[ind1];
QPointF p2 = elementList[ind2];
double dist = std::numeric_limits<double>::infinity();
if (containsPath(polygon2, p1, p2)){
double dx = p1.x()-p2.x();
double dy = p1.y()-p2.y();
return sqrt(dx*dx+dy*dy);
} else
return std::numeric_limits<double>::infinity();
dist = (dx*dx)+(dy*dy); // sqrt not necessary
}
return dist;
};
QList<QPointF> elementList;
elementList.append(startVertex);
elementList.append(endVertex);
for (int i = 0; i < polygon.size(); i++) {
elementList.append(polygon[i]);
}
return OptimisationTools::dijkstraAlgorithm<QPointF>(elementList, 0, 1, shortestPath, distanceDij);
QVector<int> shortestPathIndex;
bool retVal = OptimisationTools::dijkstraAlgorithm(listSize, 0, 1, shortestPathIndex, distanceDij);
for (auto index : shortestPathIndex) shortestPath.append(elementList[index]);
return retVal;
} else {
return false;
}
......
......@@ -28,7 +28,7 @@ namespace PolygonCalculus {
void offsetPolygon (QPolygonF &polygon, double offset);
bool containsPath (QPolygonF polygon, const QPointF &c1, const QPointF &c2);
void decomposeToConvex (const QPolygonF &polygon, QList<QPolygonF> &convexPolygons);
bool shortestPath (QPolygonF polygon, const QPointF &startVertex, const QPointF &endVertex, QList<QPointF> &shortestPath);
bool shortestPath (QPolygonF polygon, const QPointF &startVertex, const QPointF &endVertex, QVector<QPointF> &shortestPath);
QPolygonF toQPolygonF(const QVector3DList &polygon);
QPolygonF toQPolygonF(const QPointFList &polygon);
......
......@@ -231,6 +231,8 @@ bool WimaArea::join(const WimaArea &area1, const WimaArea &area2, WimaArea &join
using namespace GeoUtilities;
using namespace PolygonCalculus;
Q_UNUSED(errorString);
QList<QGeoCoordinate> GeoPolygon1 = area1.coordinateList();
QList<QGeoCoordinate> GeoPolygon2 = area2.coordinateList();
......
......@@ -380,7 +380,7 @@ bool WimaController::calcShortestPath(const QGeoCoordinate &start, const QGeoCoo
{
using namespace GeoUtilities;
using namespace PolygonCalculus;
QList<QPointF> path2D;
QVector<QPointF> path2D;
bool retVal = PolygonCalculus::shortestPath(
toQPolygonF(toCartesian2D(_joinedArea.coordinateList(), /*origin*/ start)),
/*start point*/ QPointF(0,0),
......
......@@ -671,7 +671,7 @@ bool WimaPlaner::calcShortestPath(const QGeoCoordinate &start, const QGeoCoordin
{
using namespace GeoUtilities;
using namespace PolygonCalculus;
QList<QPointF> path2D;
QVector<QPointF> path2D;
auto startTime = std::chrono::high_resolution_clock::now();
bool retVal = PolygonCalculus::shortestPath(
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment