From 05952a79857cae3e686fbe9f75cb8f25c4b4ce5c Mon Sep 17 00:00:00 2001 From: Valentin Platzgummer Date: Mon, 13 Jan 2020 14:40:36 +0100 Subject: [PATCH] 123 --- src/Wima/OptimisationTools.cc | 116 ++++++++++++++++++++++++++++++---- src/Wima/OptimisationTools.h | 105 +----------------------------- src/Wima/PolygonCalculus.cc | 33 ++++++---- src/Wima/PolygonCalculus.h | 2 +- src/Wima/WimaArea.cc | 2 + src/Wima/WimaController.cc | 2 +- src/Wima/WimaPlaner.cc | 2 +- 7 files changed, 132 insertions(+), 130 deletions(-) diff --git a/src/Wima/OptimisationTools.cc b/src/Wima/OptimisationTools.cc index 6475c865d..65c3a0ebd 100644 --- a/src/Wima/OptimisationTools.cc +++ b/src/Wima/OptimisationTools.cc @@ -1,22 +1,112 @@ #include "OptimisationTools.h" -#include namespace OptimisationTools { namespace { } // end anonymous namespace - /*! - * \fn bool dijkstraAlgorithm(int startIndex, int endIndex, const QList elements, QList &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 - bool dijkstraAlgorithm(const QList &elements, int startIndex, int endIndex, QList &elementPath, std::function distance); // don't seperate parameters with new lines or documentation will break + bool dijkstraAlgorithm(const int numElements, int startIndex, int endIndex, QVector &elementPath, std::function 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::infinity(); + }; + + // The list with all Nodes (elements) + QVector 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 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::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 diff --git a/src/Wima/OptimisationTools.h b/src/Wima/OptimisationTools.h index 40e7caee6..11c37431d 100644 --- a/src/Wima/OptimisationTools.h +++ b/src/Wima/OptimisationTools.h @@ -1,111 +1,12 @@ #pragma once #include +#include #include -#include +#include namespace OptimisationTools { - /*! - * \fn bool dijkstraAlgorithm(int startIndex, int endIndex, const QList elements, QList &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 - bool dijkstraAlgorithm(const QList &elements, int startIndex, int endIndex, QList &elementPath, std::function 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::infinity(); - Node* predecessorNode = nullptr; - }; - - // The list with all Nodes (elements) - QList 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 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::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 &elementPath, std::function distanceDij); } diff --git a/src/Wima/PolygonCalculus.cc b/src/Wima/PolygonCalculus.cc index e28cc3766..8cec285d1 100644 --- a/src/Wima/PolygonCalculus.cc +++ b/src/Wima/PolygonCalculus.cc @@ -475,7 +475,7 @@ namespace PolygonCalculus { return; } - bool shortestPath(QPolygonF polygon,const QPointF &startVertex, const QPointF &endVertex, QList &shortestPath) + bool shortestPath(QPolygonF polygon,const QPointF &startVertex, const QPointF &endVertex, QVector &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 distanceDij = [polygon2](const QPointF &p1, const QPointF &p2) -> double { + + QVector elementList; + elementList.append(startVertex); + elementList.append(endVertex); + for (auto vertex : polygon) elementList.append(vertex); + const int listSize = elementList.size(); + + + std::function distanceDij = [polygon2, elementList](const int ind1, const int ind2) -> double { + QPointF p1 = elementList[ind1]; + QPointF p2 = elementList[ind2]; + double dist = std::numeric_limits::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::infinity(); + dist = (dx*dx)+(dy*dy); // sqrt not necessary + } + + return dist; }; - QList elementList; - elementList.append(startVertex); - elementList.append(endVertex); - for (int i = 0; i < polygon.size(); i++) { - elementList.append(polygon[i]); - } - return OptimisationTools::dijkstraAlgorithm(elementList, 0, 1, shortestPath, distanceDij); + QVector shortestPathIndex; + bool retVal = OptimisationTools::dijkstraAlgorithm(listSize, 0, 1, shortestPathIndex, distanceDij); + for (auto index : shortestPathIndex) shortestPath.append(elementList[index]); + return retVal; } else { return false; } diff --git a/src/Wima/PolygonCalculus.h b/src/Wima/PolygonCalculus.h index 63d79d5b4..d34cc0915 100644 --- a/src/Wima/PolygonCalculus.h +++ b/src/Wima/PolygonCalculus.h @@ -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 &convexPolygons); - bool shortestPath (QPolygonF polygon, const QPointF &startVertex, const QPointF &endVertex, QList &shortestPath); + bool shortestPath (QPolygonF polygon, const QPointF &startVertex, const QPointF &endVertex, QVector &shortestPath); QPolygonF toQPolygonF(const QVector3DList &polygon); QPolygonF toQPolygonF(const QPointFList &polygon); diff --git a/src/Wima/WimaArea.cc b/src/Wima/WimaArea.cc index 31dd51754..1dff8e84e 100644 --- a/src/Wima/WimaArea.cc +++ b/src/Wima/WimaArea.cc @@ -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 GeoPolygon1 = area1.coordinateList(); QList GeoPolygon2 = area2.coordinateList(); diff --git a/src/Wima/WimaController.cc b/src/Wima/WimaController.cc index 9c140f4fe..a05e6d483 100644 --- a/src/Wima/WimaController.cc +++ b/src/Wima/WimaController.cc @@ -380,7 +380,7 @@ bool WimaController::calcShortestPath(const QGeoCoordinate &start, const QGeoCoo { using namespace GeoUtilities; using namespace PolygonCalculus; - QList path2D; + QVector path2D; bool retVal = PolygonCalculus::shortestPath( toQPolygonF(toCartesian2D(_joinedArea.coordinateList(), /*origin*/ start)), /*start point*/ QPointF(0,0), diff --git a/src/Wima/WimaPlaner.cc b/src/Wima/WimaPlaner.cc index 14823766a..705c8b22f 100644 --- a/src/Wima/WimaPlaner.cc +++ b/src/Wima/WimaPlaner.cc @@ -671,7 +671,7 @@ bool WimaPlaner::calcShortestPath(const QGeoCoordinate &start, const QGeoCoordin { using namespace GeoUtilities; using namespace PolygonCalculus; - QList path2D; + QVector path2D; auto startTime = std::chrono::high_resolution_clock::now(); bool retVal = PolygonCalculus::shortestPath( -- 2.22.0