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)
87 std::cref(matVertices),
88 std::cref(vecNeighborVertices),
89 std::cref(vecVertSubset),
91 static_cast<qint32
>(vecVertSubset.size()),
99 std::cref(matVertices),
100 std::cref(vecNeighborVertices),
101 std::cref(vecVertSubset),
105 iBegin += iSubArraySize;
106 iEnd += iSubArraySize;
110 for (QFuture<void>& f : vecThreads) {
120 const MatrixX3f &matVertices,
121 const std::vector<VectorXi> &vecNeighborVertices,
122 const VectorXi &vecVertSubset,
123 double (*interpolationFunction)(
double),
125 std::function<
void(
int,
int)> progressCallback,
126 const std::atomic<bool> *cancelledFlag)
128 const qint32 nVerts =
static_cast<qint32
>(matVertices.rows());
129 const qint32 nSources =
static_cast<qint32
>(vecVertSubset.size());
130 const qint32 nAdj =
static_cast<qint32
>(vecNeighborVertices.size());
134 QSet<qint32> sourceVertexSet;
135 QHash<qint32, qint32> vertexToSourceIdx;
136 for (qint32 s = 0; s < nSources; ++s) {
137 sourceVertexSet.insert(vecVertSubset[s]);
138 vertexToSourceIdx.insert(vecVertSubset[s], s);
147 struct VertexWeight {
151 struct WeightTriple {
162 int iCores = QThread::idealThreadCount();
167 iCores = qMin(iCores, 2);
169 iCores = qMin(iCores, qMax(1,
static_cast<int>(nSources)));
171 std::atomic<bool> internalCancel(
false);
172 const std::atomic<bool> *cancelView = cancelledFlag ? cancelledFlag : &internalCancel;
174 std::atomic<qint32> progressCounter(0);
176 std::vector<std::vector<WeightTriple>> perThreadTriples(iCores);
178 auto worker = [&](
int threadIdx, qint32 sBegin, qint32 sEnd) {
179 std::vector<WeightTriple> &out = perThreadTriples[threadIdx];
181 out.reserve(
static_cast<size_t>(sEnd - sBegin) * 32);
187 std::vector<qint32> touched;
188 touched.reserve(1024);
192 using QueueEntry = std::pair<float, qint32>;
193 std::priority_queue<QueueEntry, std::vector<QueueEntry>, std::greater<QueueEntry>> vertexQ;
195 const float fCancelDist =
static_cast<float>(dCancelDist);
197 for (qint32 s = sBegin; s < sEnd; ++s) {
200 if (((s - sBegin) & 0xF) == 0
201 && cancelView->load(std::memory_order_relaxed)) {
205 const qint32 iRoot = vecVertSubset[s];
210 while (!vertexQ.empty()) vertexQ.pop();
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])
continue;
223 if (fDist > fCancelDist)
continue;
225 const VectorXi &vecNeighbours = vecNeighborVertices[u];
226 const float ux = matVertices(u, 0);
227 const float uy = matVertices(u, 1);
228 const float uz = matVertices(u, 2);
230 for (Eigen::Index ne = 0; ne < vecNeighbours.size(); ++ne) {
231 const qint32 v = vecNeighbours[ne];
232 const float dx = ux - matVertices(v, 0);
233 const float dy = uy - matVertices(v, 1);
234 const float dz = uz - matVertices(v, 2);
235 const float fDistWithU = fDist + std::sqrt(dx*dx + dy*dy + dz*dz);
237 if (fDistWithU < vecMinDists[v]) {
239 touched.push_back(v);
240 vecMinDists[v] = fDistWithU;
241 if (fDistWithU <= fCancelDist)
242 vertexQ.emplace(fDistWithU, v);
248 for (qint32 idx : touched) {
249 const float d = vecMinDists[idx];
250 if (d < fCancelDist) {
251 out.push_back({idx, s, d});
255 if (progressCallback) {
256 const qint32 done = progressCounter.fetch_add(1, std::memory_order_relaxed) + 1;
257 if ((done % 100) == 0) {
258 progressCallback(done, nSources);
265 worker(0, 0, nSources);
267 QVector<QFuture<void>> vecThreads;
268 vecThreads.reserve(iCores);
269 const qint32 chunk = nSources / iCores;
271 for (
int t = 0; t < iCores; ++t) {
272 const qint32 sEnd = (t == iCores - 1) ? nSources : (sBegin + chunk);
273 vecThreads.push_back(QtConcurrent::run(worker, t, sBegin, sEnd));
276 for (QFuture<void> &f : vecThreads) f.waitForFinished();
279 if (cancelView->load(std::memory_order_relaxed))
280 return QSharedPointer<SparseMatrix<float>>();
283 std::vector<std::vector<VertexWeight>> perVertexWeights(nVerts);
286 std::vector<size_t> counts(nVerts, 0);
287 for (
const auto &chunk : perThreadTriples) {
288 for (
const auto &t : chunk) ++counts[t.vertex];
290 for (qint32 v = 0; v < nVerts; ++v) {
291 if (counts[v]) perVertexWeights[v].reserve(counts[v]);
293 for (
const auto &chunk : perThreadTriples) {
294 for (
const auto &t : chunk) {
295 perVertexWeights[t.vertex].push_back({t.sourceIdx, t.dist});
302 QVector<Eigen::Triplet<float>> vecTriplets;
304 vecTriplets.reserve(nVerts * 10);
306 for (qint32 r = 0; r < nVerts; ++r) {
307 if (sourceVertexSet.contains(r)) {
309 vecTriplets.push_back(Eigen::Triplet<float>(r, vertexToSourceIdx[r], 1.0f));
311 const auto& weights = perVertexWeights[r];
312 if (weights.empty())
continue;
315 float dWeightsSum = 0.0f;
316 QVector<QPair<qint32, float>> vecBelowThresh;
317 vecBelowThresh.reserve(
static_cast<int>(weights.size()));
319 for (
const auto& w : weights) {
320 const float dValueWeight = std::fabs(1.0f /
static_cast<float>(interpolationFunction(w.dist)));
321 dWeightsSum += dValueWeight;
322 vecBelowThresh.push_back(qMakePair(w.sourceIdx, dValueWeight));
325 for (
const auto& qp : vecBelowThresh) {
326 vecTriplets.push_back(Eigen::Triplet<float>(r, qp.first, qp.second / dWeightsSum));
331 auto interpMat = QSharedPointer<SparseMatrix<float>>::create(nVerts, nSources);
332 interpMat->setFromTriplets(vecTriplets.begin(), vecTriplets.end());
340 const MatrixX3f &matSensorPositions)
342 const qint32 iNumSensors =
static_cast<qint32
>(matSensorPositions.rows());
344 qint32 iCores = QThread::idealThreadCount();
350 iCores = qMin(iCores, (qint32)2);
353 const qint32 iSubArraySize = int(
double(iNumSensors) /
double(iCores));
355 if(iSubArraySize <= 1)
357 return nearestNeighbor(matVertices, matSensorPositions, 0, iNumSensors);
360 QVector<QFuture<VectorXi> > vecThreads(iCores);
361 qint32 iBeginOffset = 0;
362 qint32 iEndOffset = iBeginOffset + iSubArraySize;
363 for(qint32 i = 0; i < vecThreads.size(); ++i)
365 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)
395 const VectorXi& partial = vecThreads[i].result();
396 vecOutputArray.segment(iOffset, partial.size()) = partial;
397 iOffset +=
static_cast<qint32
>(partial.size());
400 return vecOutputArray;
436 const MatrixX3f &matVertices,
437 const std::vector<VectorXi> &vecNeighborVertices,
438 const VectorXi &vecVertSubset,
441 double dCancelDistance) {
442 const std::vector<VectorXi> &vecAdjacency = vecNeighborVertices;
443 qint32 n =
static_cast<qint32
>(vecAdjacency.size());
444 QVector<double> vecMinDists(n);
445 std::set< std::pair< double, qint32> > vertexQ;
448 for (qint32 i = iBegin; i < iEnd; ++i) {
449 if ((i - iBegin) > 0 && (i - iBegin) % 100 == 0) {
450 qDebug() <<
"GeometryInfo::iterativeDijkstra progress:" << (i - iBegin) <<
"/" << (iEnd - iBegin) <<
" (Thread range:" << iBegin <<
"-" << iEnd <<
")";
453 qint32 iRoot = vecVertSubset[i];
455 vecMinDists.fill(INF);
456 vecMinDists[iRoot] = 0.0;
457 vertexQ.insert(std::make_pair(vecMinDists[iRoot], iRoot));
459 while (vertexQ.empty() ==
false) {
460 const double dDist = vertexQ.begin()->first;
461 const qint32 u = vertexQ.begin()->second;
462 vertexQ.erase(vertexQ.begin());
464 if (dDist <= dCancelDistance) {
465 const VectorXi& vecNeighbours = vecAdjacency[u];
467 for (Eigen::Index ne = 0; ne < vecNeighbours.size(); ++ne) {
468 qint32 v = vecNeighbours[ne];
470 const double dDistX = matVertices(u, 0) - matVertices(v, 0);
471 const double dDistY = matVertices(u, 1) - matVertices(v, 1);
472 const double dDistZ = matVertices(u, 2) - matVertices(v, 2);
473 const double dDistWithU = dDist + sqrt(dDistX * dDistX + dDistY * dDistY + dDistZ * dDistZ);
475 if (dDistWithU < vecMinDists[v]) {
476 vertexQ.erase(std::make_pair(vecMinDists[v], v));
477 vecMinDists[v] = dDistWithU;
478 vertexQ.insert(std::make_pair(vecMinDists[v], v));
484 for (qint32 m = 0; m < vecMinDists.size(); ++m) {
485 matOutputDistMatrix->coeffRef(m , i) = vecMinDists[m];