Commit 9282a10c authored by Valentin Platzgummer's avatar Valentin Platzgummer

route variants added to circular survey

parent 053f9768
This diff is collapsed.
...@@ -99,23 +99,58 @@ Rectangle { ...@@ -99,23 +99,58 @@ Rectangle {
Layout.columnSpan: 2 Layout.columnSpan: 2
} }
property var typeFact: missionItem.type
property int type: typeFact.value
property var names: ["Circular", "Linear"]
ExclusiveGroup{id: typeGroup}
Repeater{ Repeater{
id: typeRepeater
property var typeFact: missionItem.type
property int type: typeFact.value
property var names: ["Circular", "Linear"]
model: missionItem.typeCount model: missionItem.typeCount
QGCRadioButton { QGCRadioButton {
checked: index === generalGrid.type checked: index === typeRepeater.type
text: qsTr(generalGrid.names[index]) text: qsTr(typeRepeater.names[index])
onCheckedChanged: { onCheckedChanged: {
if (checked){ if (checked){
missionItem.type.value = index missionItem.type.value = index
} }
checked = Qt.binding(function(){ return index === generalGrid.type}) checked = Qt.binding(function(){ return index === typeRepeater.type})
}
}
}
QGCLabel {
text: qsTr("Variant")
Layout.columnSpan: 2
}
GridLayout{
Layout.columnSpan: 2
columnSpacing: _margin
rowSpacing: _margin
columns: 4
Repeater{
id: variantRepeater
property var fact: missionItem.variant
property int variant: fact.value
property var names: missionItem.variantNames
property int len: missionItem.variantNames.length
model: len
QGCRadioButton {
checked: index === variantRepeater.variant
text: variantRepeater.names[index]
onCheckedChanged: {
if (checked){
missionItem.variant.value = index
}
checked = Qt.binding(function(){ return index === variantRepeater.variant})
}
} }
} }
} }
......
This diff is collapsed.
...@@ -34,9 +34,12 @@ public: ...@@ -34,9 +34,12 @@ public:
Q_PROPERTY(Fact *alpha READ alpha CONSTANT) Q_PROPERTY(Fact *alpha READ alpha CONSTANT)
Q_PROPERTY(Fact *minLength READ minLength CONSTANT) Q_PROPERTY(Fact *minLength READ minLength CONSTANT)
Q_PROPERTY(Fact *type READ type CONSTANT) Q_PROPERTY(Fact *type READ type CONSTANT)
Q_PROPERTY(Fact *variant READ variant CONSTANT)
Q_PROPERTY(int typeCount READ typeCount CONSTANT) Q_PROPERTY(int typeCount READ typeCount CONSTANT)
Q_PROPERTY(bool calculating READ calculating NOTIFY calculatingChanged) Q_PROPERTY(bool calculating READ calculating NOTIFY calculatingChanged)
Q_PROPERTY(bool hidePolygon READ hidePolygon NOTIFY hidePolygonChanged) Q_PROPERTY(bool hidePolygon READ hidePolygon NOTIFY hidePolygonChanged)
Q_PROPERTY(
QList<QString> variantNames READ variantNames NOTIFY variantNamesChanged)
Q_INVOKABLE void resetReference(void); Q_INVOKABLE void resetReference(void);
Q_INVOKABLE void reverse(void); Q_INVOKABLE void reverse(void);
...@@ -53,9 +56,11 @@ public: ...@@ -53,9 +56,11 @@ public:
Fact *alpha(); Fact *alpha();
Fact *minLength(); Fact *minLength();
Fact *type(); Fact *type();
Fact *variant();
int typeCount() const; int typeCount() const;
bool calculating() const; bool calculating() const;
bool hidePolygon() const; bool hidePolygon() const;
QList<QString> variantNames() const;
QGeoCoordinate depot() const; QGeoCoordinate depot() const;
QList<QGeoCoordinate> safeArea() const; QList<QGeoCoordinate> safeArea() const;
const QList<QList<QGeoCoordinate>> &rawTransects() const; const QList<QList<QGeoCoordinate>> &rawTransects() const;
...@@ -81,6 +86,7 @@ public: ...@@ -81,6 +86,7 @@ public:
static const char *alphaName; static const char *alphaName;
static const char *minLengthName; static const char *minLengthName;
static const char *typeName; static const char *typeName;
static const char *variantName;
static const char *CircularSurveyName; static const char *CircularSurveyName;
static const char *refPointLongitudeName; static const char *refPointLongitudeName;
static const char *refPointLatitudeName; static const char *refPointLatitudeName;
...@@ -92,6 +98,7 @@ signals: ...@@ -92,6 +98,7 @@ signals:
void hidePolygonChanged(); void hidePolygonChanged();
void depotChanged(); void depotChanged();
void safeAreaChanged(); void safeAreaChanged();
void variantNamesChanged();
private slots: private slots:
// Overrides from TransectStyleComplexItem // Overrides from TransectStyleComplexItem
...@@ -105,6 +112,11 @@ private: ...@@ -105,6 +112,11 @@ private:
QObject *missionItemParent); QObject *missionItemParent);
void _buildAndAppendMissionItems(QList<MissionItem *> &items, void _buildAndAppendMissionItems(QList<MissionItem *> &items,
QObject *missionItemParent); QObject *missionItemParent);
void _changeVariant();
void _updateWorker();
void _changeVariantWorker();
void _reverseWorker();
void _storeWorker();
// center of the circular lanes, e.g. base station // center of the circular lanes, e.g. base station
QGeoCoordinate _referencePoint; QGeoCoordinate _referencePoint;
...@@ -117,16 +129,26 @@ private: ...@@ -117,16 +129,26 @@ private:
// this value // this value
SettingsFact _minLength; SettingsFact _minLength;
SettingsFact _type; SettingsFact _type;
SettingsFact _variant;
QList<QString> _variantNames;
// Worker // Worker
using PtrWorker = std::shared_ptr<RoutingThread>; using PtrWorker = std::shared_ptr<RoutingThread>;
PtrWorker _pWorker; PtrWorker _pWorker;
PtrRoutingData _workerOutput; PtrRoutingData _workerOutput;
QList<QList<QGeoCoordinate>> _rawTransects;
bool _needsStoring;
bool _needsReversal;
bool _hidePolygon;
// Data and State.
QGeoCoordinate _depot; QGeoCoordinate _depot;
QList<QGeoCoordinate> _safeArea; QList<QGeoCoordinate> _safeArea;
QList<QList<QGeoCoordinate>> _rawTransects;
QVector<Transects> _routes;
enum class STATE {
DEFAULT,
STORE,
REVERSE,
VARIANT_CHANGE,
};
STATE _state;
bool _hidePolygon;
}; };
...@@ -23,11 +23,11 @@ RoutingThread::~RoutingThread() { ...@@ -23,11 +23,11 @@ RoutingThread::~RoutingThread() {
bool RoutingThread::calculating() const { return this->_calculating; } bool RoutingThread::calculating() const { return this->_calculating; }
void RoutingThread::route(const snake::FPolygon &safeArea, void RoutingThread::route(const RoutingParameter &par,
const RoutingThread::Generator &generator) { const Generator &generator) {
// Sample input. // Sample input.
Lock lk(this->_mutex); Lock lk(this->_mutex);
this->_safeArea = safeArea; this->_par = par;
this->_generator = generator; this->_generator = generator;
lk.unlock(); lk.unlock();
...@@ -54,9 +54,12 @@ void RoutingThread::run() { ...@@ -54,9 +54,12 @@ void RoutingThread::run() {
this->_calculating = true; this->_calculating = true;
emit calculatingChanged(); emit calculatingChanged();
Lock lk(this->_mutex); Lock lk(this->_mutex);
auto safeAreaENU = this->_safeArea; auto par = this->_par;
auto generator = this->_generator; auto generator = this->_generator;
lk.unlock(); lk.unlock();
auto safeAreaENU = par.safeArea;
auto numRuns = par.numRuns;
auto numSolutionsPerRun = par.numSolutionsPerRun;
PtrRoutingData pRouteData(new RoutingData()); PtrRoutingData pRouteData(new RoutingData());
auto &transectsENU = pRouteData->transects; auto &transectsENU = pRouteData->transects;
...@@ -70,53 +73,29 @@ void RoutingThread::run() { ...@@ -70,53 +73,29 @@ void RoutingThread::run() {
#endif #endif
} else { } else {
// Prepare data for routing. // Prepare data for routing.
auto &transectsInfo = pRouteData->transectsInfo; auto &routeInfoVector = pRouteData->routeInfoVector;
auto &route = pRouteData->route; auto &routeVector = pRouteData->routeVector;
const auto routingStart = std::chrono::high_resolution_clock::now(); snake::RouteParameter snakePar;
snakePar.numSolutionsPerRun = numSolutionsPerRun;
const auto maxRoutingTime = std::chrono::minutes(10); const auto maxRoutingTime = std::chrono::minutes(10);
const auto routingEnd = routingStart + maxRoutingTime; const auto routingEnd =
std::chrono::high_resolution_clock::now() + maxRoutingTime;
const auto &restart = this->_restart; const auto &restart = this->_restart;
auto stopLambda = [&restart, routingEnd] { snakePar.stop = [&restart, routingEnd] {
bool expired = std::chrono::high_resolution_clock::now() > routingEnd; bool expired = std::chrono::high_resolution_clock::now() > routingEnd;
return restart || expired; return restart || expired;
}; };
std::string errorString;
// Route transects // Route transects.
//#ifdef SHOW_CIRCULAR_SURVEY_TIME bool success = snake::route(safeAreaENU, transectsENU, routeInfoVector,
// auto s = std::chrono::high_resolution_clock::now(); routeVector, snakePar);
//#endif
// snake::route_old(safeAreaENU, transectsENU, transectsInfo,
// route,
// stopLambda, errorString);
//#ifdef SHOW_CIRCULAR_SURVEY_TIME
// qWarning() << "RoutingWorker::run(): route_old time: "
// <<
// std::chrono::duration_cast<std::chrono::milliseconds>(
// std::chrono::high_resolution_clock::now() -
// s) .count()
// << " ms";
//#endif
//#ifdef SHOW_CIRCULAR_SURVEY_TIME
// s = std::chrono::high_resolution_clock::now();
//#endif
// transectsInfo.clear();
// route.clear();
// errorString.clear();
bool success = snake::route(safeAreaENU, transectsENU, transectsInfo,
route, stopLambda, errorString);
//#ifdef SHOW_CIRCULAR_SURVEY_TIME
// qWarning() << "RoutingWorker::run(): route time: "
// <<
// std::chrono::duration_cast<std::chrono::milliseconds>(
// std::chrono::high_resolution_clock::now() -
// s) .count()
// << " ms";
//#endif
// Check if routing was successful. // Check if routing was successful.
if ((!success || route.size() < 3) && !this->_restart) { if ((!success || routeVector.size() < 1) && !this->_restart) {
#ifdef DEBUG_CIRCULAR_SURVEY #ifdef DEBUG_CIRCULAR_SURVEY
qWarning() << "RoutingWorker::run(): " qWarning() << "RoutingWorker::run(): "
"routing failed."; "routing failed.";
qWarning() << snakePar.errorString.c_str();
#endif #endif
} else if (this->_restart) { } else if (this->_restart) {
#ifdef DEBUG_CIRCULAR_SURVEY #ifdef DEBUG_CIRCULAR_SURVEY
...@@ -145,6 +124,7 @@ void RoutingThread::run() { ...@@ -145,6 +124,7 @@ void RoutingThread::run() {
.count() .count()
<< " ms"; << " ms";
#endif #endif
// Signal calulation end and set thread to sleep.
this->_calculating = false; this->_calculating = false;
emit calculatingChanged(); emit calculatingChanged();
Lock lk2(this->_mutex); Lock lk2(this->_mutex);
......
...@@ -11,11 +11,18 @@ ...@@ -11,11 +11,18 @@
#include <mutex> #include <mutex>
struct RoutingData { struct RoutingData {
snake::FLineString route;
snake::Transects transects; snake::Transects transects;
std::vector<snake::TransectInfo> transectsInfo; std::vector<snake::Route> routeVector;
std::vector<snake::RouteInfo> routeInfoVector;
std::string errorString;
}; };
struct RoutingParameter {
RoutingParameter() : numSolutionsPerRun(1), numRuns(1) {}
snake::FPolygon safeArea;
std::size_t numSolutionsPerRun;
std::size_t numRuns;
};
//! //!
//! \brief The CSWorker class //! \brief The CSWorker class
//! \note Don't call QThread::start, QThread::quit, etc. onyl use Worker //! \note Don't call QThread::start, QThread::quit, etc. onyl use Worker
...@@ -35,7 +42,7 @@ public: ...@@ -35,7 +42,7 @@ public:
bool calculating() const; bool calculating() const;
public slots: public slots:
void route(const snake::FPolygon &safeArea, const Generator &generator); void route(const RoutingParameter &par, const Generator &generator);
signals: signals:
void result(PtrRoutingData pTransects); void result(PtrRoutingData pTransects);
...@@ -48,7 +55,7 @@ private: ...@@ -48,7 +55,7 @@ private:
mutable std::mutex _mutex; mutable std::mutex _mutex;
mutable std::condition_variable _cv; mutable std::condition_variable _cv;
// Internal data // Internal data
snake::FPolygon _safeArea; RoutingParameter _par;
Generator _generator; // transect generator Generator _generator; // transect generator
// State // State
std::atomic_bool _calculating; std::atomic_bool _calculating;
......
...@@ -627,8 +627,8 @@ bool transectsFromScenario(Length distance, Length minLength, Angle angle, ...@@ -627,8 +627,8 @@ bool transectsFromScenario(Length distance, Length minLength, Angle angle,
} }
bool route(const FPolygon &area, const Transects &transects, bool route(const FPolygon &area, const Transects &transects,
std::vector<TransectInfo> &transectInfo, Route &r, std::vector<RouteInfo> &routeInfoVector,
std::function<bool()> stop, string &errorString) { std::vector<Route> &routeVector, const RouteParameter &par) {
#ifdef SNAKE_SHOW_TIME #ifdef SNAKE_SHOW_TIME
auto start = std::chrono::high_resolution_clock::now(); auto start = std::chrono::high_resolution_clock::now();
...@@ -761,7 +761,7 @@ bool route(const FPolygon &area, const Transects &transects, ...@@ -761,7 +761,7 @@ bool route(const FPolygon &area, const Transects &transects,
if (std::isinf(dist)) { if (std::isinf(dist)) {
std::vector<std::size_t> route; std::vector<std::size_t> route;
if (!dijkstraAlgorithm(n, i, j, route, dist, distLambda)) { if (!dijkstraAlgorithm(n, i, j, route, dist, distLambda)) {
errorString = "Distance matrix calculation failed."; par.errorString = "Distance matrix calculation failed.";
return false; return false;
} }
(void)route; (void)route;
...@@ -833,9 +833,11 @@ bool route(const FPolygon &area, const Transects &transects, ...@@ -833,9 +833,11 @@ bool route(const FPolygon &area, const Transects &transects,
auto searchParameters = DefaultRoutingSearchParameters(); auto searchParameters = DefaultRoutingSearchParameters();
searchParameters.set_first_solution_strategy( searchParameters.set_first_solution_strategy(
FirstSolutionStrategy::PATH_CHEAPEST_ARC); FirstSolutionStrategy::PATH_CHEAPEST_ARC);
// Number of solutions.
searchParameters.set_number_of_solutions_to_collect(par.numSolutionsPerRun);
// Set costume limit. // Set costume limit.
auto *solver = routing.solver(); auto *solver = routing.solver();
auto *limit = solver->MakeCustomLimit(stop); auto *limit = solver->MakeCustomLimit(par.stop);
routing.AddSearchMonitor(limit); routing.AddSearchMonitor(limit);
#ifdef SNAKE_SHOW_TIME #ifdef SNAKE_SHOW_TIME
auto delta = std::chrono::duration_cast<std::chrono::milliseconds>( auto delta = std::chrono::duration_cast<std::chrono::milliseconds>(
...@@ -849,97 +851,128 @@ bool route(const FPolygon &area, const Transects &transects, ...@@ -849,97 +851,128 @@ bool route(const FPolygon &area, const Transects &transects,
#ifdef SNAKE_SHOW_TIME #ifdef SNAKE_SHOW_TIME
start = std::chrono::high_resolution_clock::now(); start = std::chrono::high_resolution_clock::now();
#endif #endif
const Assignment *solution = routing.SolveWithParameters(searchParameters); auto pSolutions = std::make_unique<std::vector<const Assignment *>>();
(void)routing.SolveWithParameters(searchParameters, pSolutions.get());
#ifdef SNAKE_SHOW_TIME #ifdef SNAKE_SHOW_TIME
delta = std::chrono::duration_cast<std::chrono::milliseconds>( delta = std::chrono::duration_cast<std::chrono::milliseconds>(
std::chrono::high_resolution_clock::now() - start); std::chrono::high_resolution_clock::now() - start);
cout << "solve routing model: " << delta.count() << " ms" << endl; cout << "solve routing model: " << delta.count() << " ms" << endl;
#endif #endif
if (par.stop()) {
if (!solution || solution->Size() <= 1) { par.errorString = "User terminated.";
errorString = "Not able to solve the routing problem.";
return false;
} else if (stop()) {
errorString = "User terminated.";
return false; return false;
} }
//================================================================
// Construc route.
//================================================================
#ifdef SNAKE_SHOW_TIME #ifdef SNAKE_SHOW_TIME
start = std::chrono::high_resolution_clock::now(); start = std::chrono::high_resolution_clock::now();
#endif #endif
// Create index list. long long counter = -1;
auto index = routing.Start(0); // Note: route number 0 corresponds to the best route which is the last entry
std::vector<size_t> route_idx; // of *pSolutions.
route_idx.push_back(manager.IndexToNode(index).value()); for (auto solution = pSolutions->end() - 1; solution >= pSolutions->begin();
while (!routing.IsEnd(index)) { --solution) {
index = solution->Value(routing.NextVar(index)); ++counter;
if (!*solution || (*solution)->Size() <= 1) {
std::stringstream ss;
ss << par.errorString << "Solution " << counter << "invalid."
<< std::endl;
par.errorString = ss.str();
continue;
}
//================================================================
// Construc route.
//================================================================
// Create index list.
auto index = routing.Start(0);
std::vector<size_t> route_idx;
route_idx.push_back(manager.IndexToNode(index).value()); route_idx.push_back(manager.IndexToNode(index).value());
} while (!routing.IsEnd(index)) {
index = (*solution)->Value(routing.NextVar(index));
route_idx.push_back(manager.IndexToNode(index).value());
}
#ifdef SNAKE_DEBUG #ifdef SNAKE_DEBUG
// Print route. // Print route.
std::cout << "route_idx.size() = " << route_idx.size() << std::endl; std::cout << "route " << counter
std::cout << "route: "; << " route_idx.size() = " << route_idx.size() << std::endl;
for (const auto &idx : route_idx) { std::cout << "route: ";
std::cout << idx << ", "; for (const auto &idx : route_idx) {
} std::cout << idx << ", ";
std::cout << std::endl; }
std::cout << std::endl;
#endif #endif
if (route_idx.size() < 2) { if (route_idx.size() < 2) {
errorString = "Error while assembling route."; std::stringstream ss;
return false; ss << par.errorString << "Error while assembling route " << counter << "."
} << std::endl;
par.errorString = ss.str();
continue;
}
// Construct route. // Construct route.
for (size_t i = 0; i < route_idx.size() - 1; ++i) { Route r;
size_t nodeIndex0 = route_idx[i]; RouteInfo routeInfo;
size_t nodeIndex1 = route_idx[i + 1]; for (size_t i = 0; i < route_idx.size() - 1; ++i) {
const auto &n2t0 = nodeToTransectList[nodeIndex0]; size_t nodeIndex0 = route_idx[i];
transectInfo.emplace_back(n2t0.transectsIndex, n2t0.reversed); size_t nodeIndex1 = route_idx[i + 1];
// Copy transect to route. const auto &n2t0 = nodeToTransectList[nodeIndex0];
const auto &t = transects[n2t0.transectsIndex]; routeInfo.emplace_back(n2t0.transectsIndex, n2t0.reversed);
if (n2t0.reversed) { // transect reversal needed? // Copy transect to route.
for (auto it = t.end() - 1; it > t.begin(); --it) { const auto &t = transects[n2t0.transectsIndex];
r.push_back(*it); if (n2t0.reversed) { // transect reversal needed?
for (auto it = t.end() - 1; it > t.begin(); --it) {
r.push_back(*it);
}
} else {
for (auto it = t.begin(); it < t.end() - 1; ++it) {
r.push_back(*it);
}
} }
} else { // Connect transects.
for (auto it = t.begin(); it < t.end() - 1; ++it) { std::vector<size_t> idxList;
r.push_back(*it); if (!shortestPathFromGraph(connectionGraph,
nodeList[nodeIndex0].fromIndex,
nodeList[nodeIndex1].toIndex, idxList)) {
std::stringstream ss;
ss << par.errorString << "Error while assembling route " << counter
<< "." << std::endl;
par.errorString = ss.str();
continue;
}
if (i != route_idx.size() - 2) {
idxList.pop_back();
}
for (auto idx : idxList) {
auto p = int2Float(vertices[idx]);
r.push_back(p);
} }
} }
// Connect transects. // Append last transect info.
std::vector<size_t> idxList; const auto &n2t0 = nodeToTransectList.back();
if (!shortestPathFromGraph(connectionGraph, nodeList[nodeIndex0].fromIndex, routeInfo.emplace_back(n2t0.transectsIndex, n2t0.reversed);
nodeList[nodeIndex1].toIndex, idxList)) {
errorString = "Error while assembling route."; if (r.size() < 2 || routeInfo.size() < 2) {
return false; std::stringstream ss;
} ss << par.errorString << "Route " << counter << " empty." << std::endl;
if (i != route_idx.size() - 2) { par.errorString = ss.str();
idxList.pop_back(); continue;
}
for (auto idx : idxList) {
auto p = int2Float(vertices[idx]);
r.push_back(p);
} }
routeVector.push_back(std::move(r));
routeInfoVector.push_back(std::move(routeInfo));
} }
// Append last transect info.
const auto &n2t0 = nodeToTransectList.back();
transectInfo.emplace_back(n2t0.transectsIndex, n2t0.reversed);
#ifdef SNAKE_SHOW_TIME #ifdef SNAKE_SHOW_TIME
delta = std::chrono::duration_cast<std::chrono::milliseconds>( delta = std::chrono::duration_cast<std::chrono::milliseconds>(
std::chrono::high_resolution_clock::now() - start); std::chrono::high_resolution_clock::now() - start);
cout << "reconstruct route: " << delta.count() << " ms" << endl; cout << "reconstruct route: " << delta.count() << " ms" << endl;
#endif #endif
if (r.size() < 2) { if (routeVector.size() > 0 && routeVector.size() == routeInfoVector.size()) {
errorString = "Route empty."; return true;
} else {
return false; return false;
} }
return true;
} }
bool route_old(const FPolygon &area, const Transects &transects, bool route_old(const FPolygon &area, const Transects &transects,
...@@ -1156,13 +1189,6 @@ bool route_old(const FPolygon &area, const Transects &transects, ...@@ -1156,13 +1189,6 @@ bool route_old(const FPolygon &area, const Transects &transects,
return route_old(area, transects, transectInfo, r, stop, errorString); return route_old(area, transects, transectInfo, r, stop, errorString);
} }
bool route(const FPolygon &area, const Transects &transects,
std::vector<TransectInfo> &transectInfo, Route &r,
string &errorString) {
auto stop = [] { return false; };
return route(area, transects, transectInfo, r, stop, errorString);
}
FPoint int2Float(const IPoint &ip) { return int2Float(ip, stdScale); } FPoint int2Float(const IPoint &ip) { return int2Float(ip, stdScale); }
FPoint int2Float(const IPoint &ip, IntType scale) { FPoint int2Float(const IPoint &ip, IntType scale) {
......
...@@ -228,12 +228,19 @@ struct TransectInfo { ...@@ -228,12 +228,19 @@ struct TransectInfo {
size_t index; size_t index;
bool reversed; bool reversed;
}; };
using RouteInfo = std::vector<TransectInfo>;
struct RouteParameter {
RouteParameter()
: numSolutionsPerRun(1), numRuns(1), stop([] { return false; }) {}
std::size_t numSolutionsPerRun;
std::size_t numRuns;
std::function<bool(void)> stop;
mutable std::string errorString;
};
bool route(const FPolygon &area, const Transects &transects, bool route(const FPolygon &area, const Transects &transects,
std::vector<TransectInfo> &transectInfo, Route &r, std::vector<RouteInfo> &routeInfoVector,
string &errorString); std::vector<Route> &routeVector,
bool route(const FPolygon &area, const Transects &transects, const RouteParameter &par = RouteParameter());
std::vector<TransectInfo> &transectInfo, Route &r,
std::function<bool(void)> stop, string &errorString);
bool route_old(const FPolygon &area, const Transects &transects, bool route_old(const FPolygon &area, const Transects &transects,
std::vector<TransectInfo> &transectInfo, Route &r, std::vector<TransectInfo> &transectInfo, Route &r,
......
...@@ -798,14 +798,15 @@ void WimaController::_storeRoute(RoutingThread::PtrRoutingData data) { ...@@ -798,14 +798,15 @@ void WimaController::_storeRoute(RoutingThread::PtrRoutingData data) {
// Copy waypoints to waypoint manager. // Copy waypoints to waypoint manager.
_snakeWM.clear(); _snakeWM.clear();
if (data->route.size() > 0) { if (data->routeVector.size() > 0 && data->routeVector.front().size() > 0 &&
data->routeInfoVector.size() > 0) {
// Store route. // Store route.
const auto &transectsENU = data->transects; const auto &transectsENU = data->transects;
const auto &transectsInfo = data->transectsInfo; const auto &routeInfo = data->routeInfoVector.front();
const auto &route = data->route; const auto &route = data->routeVector.front();
// Find index of first waypoint. // Find index of first waypoint.
std::size_t idxFirst = 0; std::size_t idxFirst = 0;
const auto &infoFirst = transectsInfo.front(); const auto &infoFirst = routeInfo.front();
const auto &firstTransect = transectsENU[infoFirst.index]; const auto &firstTransect = transectsENU[infoFirst.index];