From 4e02de80c0605775c8018175bd888a07f3ac3bc6 Mon Sep 17 00:00:00 2001 From: wmayer Date: Wed, 29 Jan 2020 11:55:49 +0100 Subject: [PATCH] Inspection: multi-threaded calculation --- src/Mod/Inspection/App/InspectionFeature.cpp | 109 +++++++++++++++--- .../Inspection/Gui/ViewProviderInspection.cpp | 28 +++-- 2 files changed, 110 insertions(+), 27 deletions(-) diff --git a/src/Mod/Inspection/App/InspectionFeature.cpp b/src/Mod/Inspection/App/InspectionFeature.cpp index b4c465fc81..f25ca00e83 100644 --- a/src/Mod/Inspection/App/InspectionFeature.cpp +++ b/src/Mod/Inspection/App/InspectionFeature.cpp @@ -653,6 +653,7 @@ unsigned int PropertyDistanceList::getMemSize (void) const // ---------------------------------------------------------------- +namespace Inspection { // helper class to use Qt's concurrent framework struct DistanceInspection { @@ -686,6 +687,25 @@ struct DistanceInspection std::vector nominal; }; +// Helper internal class for QtConcurrent map operation. Holds sums-of-squares and counts for RMS calculation +class DistanceInspectionRMS { +public: + DistanceInspectionRMS() : m_numv(0), m_sumsq(0.0) {}; + DistanceInspectionRMS& operator += (const DistanceInspectionRMS& rhs) + { + this->m_numv += rhs.m_numv; + this->m_sumsq += rhs.m_sumsq; + return *this; + } + double getRMS() + { + return sqrt(this->m_sumsq / (double)this->m_numv); + } + int m_numv; + double m_sumsq; +}; +} + PROPERTY_SOURCE(Inspection::Feature, App::DocumentObject) Feature::Feature() @@ -759,8 +779,8 @@ App::DocumentObjectExecReturn* Feature::execute(void) inspectNominal.push_back(nominal); } -#if 0 // test with some huge data sets - Standard::SetReentrant(Standard_True); +#if 0 +#if 1 // test with some huge data sets std::vector index(actual->countPoints()); std::generate(index.begin(), index.end(), Base::iotaGen(0)); DistanceInspection check(this->SearchRadius.getValue(), actual, inspectNominal); @@ -771,16 +791,17 @@ App::DocumentObjectExecReturn* Feature::execute(void) QFutureWatcher watcher; QObject::connect(&watcher, SIGNAL(progressValueChanged(int)), &progress, SLOT(progressValueChanged(int))); - watcher.setFuture(future); // keep it responsive during computation QEventLoop loop; QObject::connect(&watcher, SIGNAL(finished()), &loop, SLOT(quit())); + watcher.setFuture(future); loop.exec(); std::vector vals; vals.insert(vals.end(), future.begin(), future.end()); #else + DistanceInspection insp(this->SearchRadius.getValue(), actual, inspectNominal); unsigned long count = actual->countPoints(); std::stringstream str; str << "Inspecting " << this->Label.getValue() << "..."; @@ -788,19 +809,7 @@ App::DocumentObjectExecReturn* Feature::execute(void) std::vector vals(count); for (unsigned long index = 0; index < count; index++) { - Base::Vector3f pnt = actual->getPoint(index); - - float fMinDist=FLT_MAX; - for (std::vector::iterator it = inspectNominal.begin(); it != inspectNominal.end(); ++it) { - float fDist = (*it)->getDistance(pnt); - if (fabs(fDist) < fabs(fMinDist)) - fMinDist = fDist; - } - - if (fMinDist > this->SearchRadius.getValue()) - fMinDist = FLT_MAX; - else if (-fMinDist > this->SearchRadius.getValue()) - fMinDist = -FLT_MAX; + float fMinDist = insp.mapped(index); vals[index] = fMinDist; seq.next(); } @@ -822,8 +831,72 @@ App::DocumentObjectExecReturn* Feature::execute(void) fRMS = sqrt(fRMS); } - Base::Console().Message("RMS value for '%s' with search radius=%.4f is: %.4f\n", - this->Label.getValue(), this->SearchRadius.getValue(), fRMS); + Base::Console().Message("RMS value for '%s' with search radius [%.4f,%.4f] is: %.4f\n", + this->Label.getValue(), -this->SearchRadius.getValue(), this->SearchRadius.getValue(), fRMS); +#else + bool useMultithreading = true; + unsigned long count = actual->countPoints(); + std::vector vals(count); + std::function fMap = [&](unsigned int index) + { + DistanceInspectionRMS res; + Base::Vector3f pnt = actual->getPoint(index); + + float fMinDist = FLT_MAX; + for (std::vector::iterator it = inspectNominal.begin(); it != inspectNominal.end(); ++it) { + float fDist = (*it)->getDistance(pnt); + if (fabs(fDist) < fabs(fMinDist)) + fMinDist = fDist; + } + + if (fMinDist > this->SearchRadius.getValue()) + fMinDist = FLT_MAX; + else if (-fMinDist > this->SearchRadius.getValue()) + fMinDist = -FLT_MAX; + else { + res.m_sumsq += fMinDist * fMinDist; + res.m_numv++; + } + + vals[index] = fMinDist; + return res; + }; + + DistanceInspectionRMS res; + + if (useMultithreading) { + // Build vector of increasing indices + std::vector index(count); + std::iota(index.begin(), index.end(), 0); + // Perform map-reduce operation : compute distances and update sum of squares for RMS computation + QFuture future = QtConcurrent::mappedReduced( + index, fMap, &DistanceInspectionRMS::operator+=); + // Setup progress bar + Base::FutureWatcherProgress progress("Inspecting...", actual->countPoints()); + QFutureWatcher watcher; + QObject::connect(&watcher, SIGNAL(progressValueChanged(int)), + &progress, SLOT(progressValueChanged(int))); + // Keep UI responsive during computation + QEventLoop loop; + QObject::connect(&watcher, SIGNAL(finished()), &loop, SLOT(quit())); + watcher.setFuture(future); + loop.exec(); + res = future.result(); + } + else { + // Single-threaded operation + std::stringstream str; + str << "Inspecting " << this->Label.getValue() << "..."; + Base::SequencerLauncher seq(str.str().c_str(), count); + + for (unsigned int i = 0; i < count; i++) + res += fMap(i); + } + + Base::Console().Message("RMS value for '%s' with search radius [%.4f,%.4f] is: %.4f\n", + this->Label.getValue(), -this->SearchRadius.getValue(), this->SearchRadius.getValue(), res.getRMS()); + Distances.setValues(vals); +#endif delete actual; for (std::vector::iterator it = inspectNominal.begin(); it != inspectNominal.end(); ++it) diff --git a/src/Mod/Inspection/Gui/ViewProviderInspection.cpp b/src/Mod/Inspection/Gui/ViewProviderInspection.cpp index 74f96a8dc4..e7cd7dd3dd 100644 --- a/src/Mod/Inspection/Gui/ViewProviderInspection.cpp +++ b/src/Mod/Inspection/Gui/ViewProviderInspection.cpp @@ -43,6 +43,7 @@ #include #include #include +#include #include #include @@ -585,15 +586,24 @@ QString ViewProviderInspection::inspectDistance(const SoPickedPoint* pp) const info = QObject::tr("Distance: < %1").arg(-fSearchRadius); } else { - const SbVec3f& v1 = this->pcCoords->point[index1]; - const SbVec3f& v2 = this->pcCoords->point[index2]; - const SbVec3f& v3 = this->pcCoords->point[index3]; - const SbVec3f& p = pp->getObjectPoint(); - // get the weights - float w1, w2, w3; - calcWeights(v1,v2,v3,p,w1,w2,w3); - float fVal = w1*fVal1+w2*fVal2+w3*fVal3; - info = QObject::tr("Distance: %1").arg(fVal); + SoSearchAction searchAction; + searchAction.setType(SoCoordinate3::getClassTypeId()); + searchAction.setInterest(SoSearchAction::FIRST); + searchAction.apply(pp->getPath()->getNodeFromTail(1)); + SoPath* selectionPath = searchAction.getPath(); + + if (selectionPath) { + SoCoordinate3* coords = static_cast(selectionPath->getTail()); + const SbVec3f& v1 = coords->point[index1]; + const SbVec3f& v2 = coords->point[index2]; + const SbVec3f& v3 = coords->point[index3]; + const SbVec3f& p = pp->getObjectPoint(); + // get the weights + float w1, w2, w3; + calcWeights(v1, v2, v3, p, w1, w2, w3); + float fVal = w1 * fVal1 + w2 * fVal2 + w3 * fVal3; + info = QObject::tr("Distance: %1").arg(fVal); + } } } }