53 const std::vector<VectorXi>& vecNeighborVertices,
54 VectorXi& vecVertSubset,
58 qint32 iCols =
static_cast<qint32
>(vecVertSubset.size());
59 if (vecVertSubset.size() == 0) {
60 qDebug() <<
"[WARNING] SCDC received empty subset, calculating full distance table, make sure you have enough memory !";
61 vecVertSubset = VectorXi::LinSpaced(matVertices.rows(), 0,
static_cast<int>(matVertices.rows()) - 1);
62 iCols =
static_cast<qint32
>(matVertices.rows());
65 QSharedPointer<MatrixXd> returnMat = QSharedPointer<MatrixXd>::create(matVertices.rows(), iCols);
68 int iCores = QThread::idealThreadCount();
74 iCores = qMin(iCores, 2);
77 qint32 iSubArraySize = int(
double(vecVertSubset.size()) /
double(iCores));
78 QVector<QFuture<void>> vecThreads(iCores);
80 qint32 iEnd = iSubArraySize;
82 for (
int i = 0; i < vecThreads.size(); ++i) {
83 if (i == vecThreads.size() - 1) {
86 std::cref(matVertices),
87 std::cref(vecNeighborVertices),
88 std::cref(vecVertSubset),
90 static_cast<qint32
>(vecVertSubset.size()),
96 std::cref(matVertices),
97 std::cref(vecNeighborVertices),
98 std::cref(vecVertSubset),
102 iBegin += iSubArraySize;
103 iEnd += iSubArraySize;
107 for (QFuture<void>& f : vecThreads) {
117 const MatrixX3f& matVertices,
118 const std::vector<VectorXi>& vecNeighborVertices,
119 const VectorXi& vecVertSubset,
120 double (*interpolationFunction)(
double),
122 std::function<
void(
int,
int)> progressCallback,
123 const std::atomic<bool>* cancelledFlag)
125 const qint32 nVerts =
static_cast<qint32
>(matVertices.rows());
126 const qint32 nSources =
static_cast<qint32
>(vecVertSubset.size());
127 const qint32 nAdj =
static_cast<qint32
>(vecNeighborVertices.size());
131 QSet<qint32> sourceVertexSet;
132 QHash<qint32, qint32> vertexToSourceIdx;
133 for (qint32 s = 0; s < nSources; ++s) {
134 sourceVertexSet.insert(vecVertSubset[s]);
135 vertexToSourceIdx.insert(vecVertSubset[s], s);
161 int iCores = QThread::idealThreadCount();
166 iCores = qMin(iCores, 2);
168 iCores = qMin(iCores, qMax(1,
static_cast<int>(nSources)));
170 std::atomic<bool> internalCancel(
false);
171 const std::atomic<bool>* cancelView = cancelledFlag ? cancelledFlag : &internalCancel;
173 std::atomic<qint32> progressCounter(0);
175 std::vector<std::vector<WeightTriple>> perThreadTriples(iCores);
177 auto worker = [&](
int threadIdx, qint32 sBegin, qint32 sEnd) {
178 std::vector<WeightTriple>& out = perThreadTriples[threadIdx];
180 out.reserve(
static_cast<size_t>(sEnd - sBegin) * 32);
186 std::vector<qint32> touched;
187 touched.reserve(1024);
191 using QueueEntry = std::pair<float, qint32>;
192 std::priority_queue<QueueEntry, std::vector<QueueEntry>, std::greater<QueueEntry>> vertexQ;
194 const float fCancelDist =
static_cast<float>(dCancelDist);
196 for (qint32 s = sBegin; s < sEnd; ++s) {
199 if (((s - sBegin) & 0xF) == 0 && cancelView->load(std::memory_order_relaxed)) {
203 const qint32 iRoot = vecVertSubset[s];
206 for (qint32 idx : touched)
209 while (!vertexQ.empty())
212 vecMinDists[iRoot] = 0.0f;
213 touched.push_back(iRoot);
214 vertexQ.emplace(0.0f, iRoot);
216 while (!vertexQ.empty()) {
217 const float fDist = vertexQ.top().first;
218 const qint32 u = vertexQ.top().second;
222 if (fDist > vecMinDists[u])
224 if (fDist > fCancelDist)
227 const VectorXi& vecNeighbours = vecNeighborVertices[u];
228 const float ux = matVertices(u, 0);
229 const float uy = matVertices(u, 1);
230 const float uz = matVertices(u, 2);
232 for (Eigen::Index ne = 0; ne < vecNeighbours.size(); ++ne) {
233 const qint32 v = vecNeighbours[ne];
234 const float dx = ux - matVertices(v, 0);
235 const float dy = uy - matVertices(v, 1);
236 const float dz = uz - matVertices(v, 2);
237 const float fDistWithU = fDist + std::sqrt(dx * dx + dy * dy + dz * dz);
239 if (fDistWithU < vecMinDists[v]) {
241 touched.push_back(v);
242 vecMinDists[v] = fDistWithU;
243 if (fDistWithU <= fCancelDist)
244 vertexQ.emplace(fDistWithU, v);
250 for (qint32 idx : touched) {
251 const float d = vecMinDists[idx];
252 if (d < fCancelDist) {
253 out.push_back({idx, s, d});
257 if (progressCallback) {
258 const qint32 done = progressCounter.fetch_add(1, std::memory_order_relaxed) + 1;
259 if ((done % 100) == 0) {
260 progressCallback(done, nSources);
267 worker(0, 0, nSources);
269 QVector<QFuture<void>> vecThreads;
270 vecThreads.reserve(iCores);
271 const qint32 chunk = nSources / iCores;
273 for (
int t = 0; t < iCores; ++t) {
274 const qint32 sEnd = (t == iCores - 1) ? nSources : (sBegin + chunk);
275 vecThreads.push_back(QtConcurrent::run(worker, t, sBegin, sEnd));
278 for (QFuture<void>& f : vecThreads)
282 if (cancelView->load(std::memory_order_relaxed))
283 return QSharedPointer<SparseMatrix<float>>();
286 std::vector<std::vector<VertexWeight>> perVertexWeights(nVerts);
289 std::vector<size_t> counts(nVerts, 0);
290 for (
const auto& chunk : perThreadTriples) {
291 for (
const auto& t : chunk)
294 for (qint32 v = 0; v < nVerts; ++v) {
296 perVertexWeights[v].reserve(counts[v]);
298 for (
const auto& chunk : perThreadTriples) {
299 for (
const auto& t : chunk) {
300 perVertexWeights[t.vertex].push_back({t.sourceIdx, t.dist});
307 QVector<Eigen::Triplet<float>> vecTriplets;
309 vecTriplets.reserve(nVerts * 10);
311 for (qint32 r = 0; r < nVerts; ++r) {
312 if (sourceVertexSet.contains(r)) {
314 vecTriplets.push_back(Eigen::Triplet<float>(r, vertexToSourceIdx[r], 1.0f));
316 const auto& weights = perVertexWeights[r];
321 float dWeightsSum = 0.0f;
322 QVector<QPair<qint32, float>> vecBelowThresh;
323 vecBelowThresh.reserve(
static_cast<int>(weights.size()));
325 for (
const auto& w : weights) {
326 const float dValueWeight = std::fabs(1.0f /
static_cast<float>(interpolationFunction(w.dist)));
327 dWeightsSum += dValueWeight;
328 vecBelowThresh.push_back(qMakePair(w.sourceIdx, dValueWeight));
331 for (
const auto& qp : vecBelowThresh) {
332 vecTriplets.push_back(Eigen::Triplet<float>(r, qp.first, qp.second / dWeightsSum));
337 auto interpMat = QSharedPointer<SparseMatrix<float>>::create(nVerts, nSources);
338 interpMat->setFromTriplets(vecTriplets.begin(), vecTriplets.end());
346 const MatrixX3f& matSensorPositions)
348 const qint32 iNumSensors =
static_cast<qint32
>(matSensorPositions.rows());
350 qint32 iCores = QThread::idealThreadCount();
355 iCores = qMin(iCores, (qint32)2);
358 const qint32 iSubArraySize = int(
double(iNumSensors) /
double(iCores));
360 if (iSubArraySize <= 1) {
361 return nearestNeighbor(matVertices, matSensorPositions, 0, iNumSensors);
364 QVector<QFuture<VectorXi>> vecThreads(iCores);
365 qint32 iBeginOffset = 0;
366 qint32 iEndOffset = iBeginOffset + iSubArraySize;
367 for (qint32 i = 0; i < vecThreads.size(); ++i) {
368 if (i == vecThreads.size() - 1) {
381 iBeginOffset = iEndOffset;
382 iEndOffset += iSubArraySize;
386 for (QFuture<VectorXi>& f : vecThreads) {
391 VectorXi vecOutputArray(iNumSensors);
393 for (qint32 i = 0; i < vecThreads.size(); ++i) {
394 const VectorXi& partial = vecThreads[i].result();
395 vecOutputArray.segment(iOffset, partial.size()) = partial;
396 iOffset +=
static_cast<qint32
>(partial.size());
399 return vecOutputArray;
430 const MatrixX3f& matVertices,
431 const std::vector<VectorXi>& vecNeighborVertices,
432 const VectorXi& vecVertSubset,
435 double dCancelDistance)
437 const std::vector<VectorXi>& vecAdjacency = vecNeighborVertices;
438 qint32 n =
static_cast<qint32
>(vecAdjacency.size());
439 QVector<double> vecMinDists(n);
440 std::set<std::pair<double, qint32>> vertexQ;
443 for (qint32 i = iBegin; i < iEnd; ++i) {
444 if ((i - iBegin) > 0 && (i - iBegin) % 100 == 0) {
445 qDebug() <<
"GeometryInfo::iterativeDijkstra progress:" << (i - iBegin) <<
"/" << (iEnd - iBegin) <<
" (Thread range:" << iBegin <<
"-" << iEnd <<
")";
448 qint32 iRoot = vecVertSubset[i];
450 vecMinDists.fill(INF);
451 vecMinDists[iRoot] = 0.0;
452 vertexQ.insert(std::make_pair(vecMinDists[iRoot], iRoot));
454 while (vertexQ.empty() ==
false) {
455 const double dDist = vertexQ.begin()->first;
456 const qint32 u = vertexQ.begin()->second;
457 vertexQ.erase(vertexQ.begin());
459 if (dDist <= dCancelDistance) {
460 const VectorXi& vecNeighbours = vecAdjacency[u];
462 for (Eigen::Index ne = 0; ne < vecNeighbours.size(); ++ne) {
463 qint32 v = vecNeighbours[ne];
465 const double dDistX = matVertices(u, 0) - matVertices(v, 0);
466 const double dDistY = matVertices(u, 1) - matVertices(v, 1);
467 const double dDistZ = matVertices(u, 2) - matVertices(v, 2);
468 const double dDistWithU = dDist + sqrt(dDistX * dDistX + dDistY * dDistY + dDistZ * dDistZ);
470 if (dDistWithU < vecMinDists[v]) {
471 vertexQ.erase(std::make_pair(vecMinDists[v], v));
472 vecMinDists[v] = dDistWithU;
473 vertexQ.insert(std::make_pair(vecMinDists[v], v));
479 for (qint32 m = 0; m < vecMinDists.size(); ++m) {
480 matOutputDistMatrix->coeffRef(m, i) = vecMinDists[m];