Skip to content

Commit

Permalink
Inspection: multi-threaded calculation
Browse files Browse the repository at this point in the history
  • Loading branch information
wwmayer committed Jan 29, 2020
1 parent ddc1555 commit 15dea4f
Show file tree
Hide file tree
Showing 2 changed files with 110 additions and 27 deletions.
109 changes: 91 additions & 18 deletions src/Mod/Inspection/App/InspectionFeature.cpp
Expand Up @@ -653,6 +653,7 @@ unsigned int PropertyDistanceList::getMemSize (void) const

// ----------------------------------------------------------------

namespace Inspection {
// helper class to use Qt's concurrent framework
struct DistanceInspection
{
Expand Down Expand Up @@ -686,6 +687,25 @@ struct DistanceInspection
std::vector<InspectNominalGeometry*> 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()
Expand Down Expand Up @@ -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<unsigned long> index(actual->countPoints());
std::generate(index.begin(), index.end(), Base::iotaGen<unsigned long>(0));
DistanceInspection check(this->SearchRadius.getValue(), actual, inspectNominal);
Expand All @@ -771,36 +791,25 @@ App::DocumentObjectExecReturn* Feature::execute(void)
QFutureWatcher<float> 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<float> 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() << "...";
Base::SequencerLauncher seq(str.str().c_str(), count);

std::vector<float> vals(count);
for (unsigned long index = 0; index < count; index++) {
Base::Vector3f pnt = actual->getPoint(index);

float fMinDist=FLT_MAX;
for (std::vector<InspectNominalGeometry*>::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();
}
Expand All @@ -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<float> vals(count);
std::function<DistanceInspectionRMS(int)> fMap = [&](unsigned int index)
{
DistanceInspectionRMS res;
Base::Vector3f pnt = actual->getPoint(index);

float fMinDist = FLT_MAX;
for (std::vector<InspectNominalGeometry*>::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<unsigned long> index(count);
std::iota(index.begin(), index.end(), 0);
// Perform map-reduce operation : compute distances and update sum of squares for RMS computation
QFuture<DistanceInspectionRMS> future = QtConcurrent::mappedReduced(
index, fMap, &DistanceInspectionRMS::operator+=);
// Setup progress bar
Base::FutureWatcherProgress progress("Inspecting...", actual->countPoints());
QFutureWatcher<DistanceInspectionRMS> 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<InspectNominalGeometry*>::iterator it = inspectNominal.begin(); it != inspectNominal.end(); ++it)
Expand Down
28 changes: 19 additions & 9 deletions src/Mod/Inspection/Gui/ViewProviderInspection.cpp
Expand Up @@ -43,6 +43,7 @@
#include <Inventor/nodes/SoMaterialBinding.h>
#include <Inventor/nodes/SoNormal.h>
#include <Inventor/errors/SoDebugError.h>
#include <Inventor/actions/SoSearchAction.h>

#include <Base/Exception.h>
#include <App/PropertyLinks.h>
Expand Down Expand Up @@ -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<SoCoordinate3*>(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);
}
}
}
}
Expand Down

0 comments on commit 15dea4f

Please sign in to comment.