From 75f2133e978ea363db5b7aafa83b70539da47702 Mon Sep 17 00:00:00 2001 From: Daniel Girardeau-Montaut Date: Fri, 3 May 2019 23:52:33 +0200 Subject: [PATCH] Fix SF namings --- ContextBasedFeature.cpp | 2 +- FeaturesInterface.cpp | 4 ++-- FeaturesInterface.h | 2 +- NeighborhoodFeature.cpp | 4 ++-- PointFeature.cpp | 38 ++++++++++++++++------------------ ScalarFieldCollector.cpp | 44 ++++++++++++++++++++++------------------ ScalarFieldCollector.h | 18 +++++++++++++--- q3DMASC.cpp | 36 ++++++++++++++------------------ q3DMASCCommands.h | 9 +++----- q3DMASCTools.cpp | 2 +- 10 files changed, 81 insertions(+), 78 deletions(-) diff --git a/ContextBasedFeature.cpp b/ContextBasedFeature.cpp index d6846ed..712bcbd 100644 --- a/ContextBasedFeature.cpp +++ b/ContextBasedFeature.cpp @@ -119,7 +119,7 @@ bool ContextBasedFeature::prepare( const CorePoints& corePoints, //and the scalar field assert(!sf); - sf = PrepareSF(corePoints.cloud, qPrintable(resultSFName), generatedScalarFields); + sf = PrepareSF(corePoints.cloud, qPrintable(resultSFName), generatedScalarFields, SFCollector::CAN_REMOVE); if (!sf) { errorMessage = QString("Failed to prepare scalar %1 @ scale %2").arg(resultSFName).arg(scale); diff --git a/FeaturesInterface.cpp b/FeaturesInterface.cpp index 8f4cfc7..dab69c7 100644 --- a/FeaturesInterface.cpp +++ b/FeaturesInterface.cpp @@ -25,7 +25,7 @@ using namespace masc; -CCLib::ScalarField* Feature::PrepareSF(ccPointCloud* cloud, const char* resultSFName, SFCollector* generatedScalarFields/*=nullptr*/) +CCLib::ScalarField* Feature::PrepareSF(ccPointCloud* cloud, const char* resultSFName, SFCollector* generatedScalarFields/*=nullptr*/, SFCollector::Behavior behavior/*=SFCollector::CAN_REMOVE*/) { if (!cloud || !resultSFName) { @@ -54,7 +54,7 @@ CCLib::ScalarField* Feature::PrepareSF(ccPointCloud* cloud, const char* resultSF if (generatedScalarFields) { //track the generated scalar-field - generatedScalarFields->push(cloud, newSF); + generatedScalarFields->push(cloud, newSF, behavior); } resultSF = newSF; diff --git a/FeaturesInterface.h b/FeaturesInterface.h index e652055..7dd158a 100644 --- a/FeaturesInterface.h +++ b/FeaturesInterface.h @@ -210,7 +210,7 @@ namespace masc public: //helpers //! Creates (or resets) a scalar field with the given name on the input core points cloud - static CCLib::ScalarField* PrepareSF(ccPointCloud* cloud, const char* resultSFName, SFCollector* generatedScalarFields = nullptr); + static CCLib::ScalarField* PrepareSF(ccPointCloud* cloud, const char* resultSFName, SFCollector* generatedScalarFields/*= nullptr*/, SFCollector::Behavior behavior); //! Performs a mathematical operation between two scalars static ScalarType PerformMathOp(double s1, double s2, Operation op); diff --git a/NeighborhoodFeature.cpp b/NeighborhoodFeature.cpp index ec17430..87c33ac 100644 --- a/NeighborhoodFeature.cpp +++ b/NeighborhoodFeature.cpp @@ -88,7 +88,7 @@ bool NeighborhoodFeature::prepare( const CorePoints& corePoints, //and the scalar field assert(!sf1); - sf1 = PrepareSF(corePoints.cloud, qPrintable(resultSFName), generatedScalarFields); + sf1 = PrepareSF(corePoints.cloud, qPrintable(resultSFName), generatedScalarFields, SFCollector::CAN_REMOVE); if (!sf1) { error = QString("Failed to prepare scalar %1 @ scale %2").arg(resultSFName).arg(scale); @@ -102,7 +102,7 @@ bool NeighborhoodFeature::prepare( const CorePoints& corePoints, keepSF2 = (corePoints.cloud->getScalarFieldIndexByName(qPrintable(resultSFName2)) >= 0); //we remember that the scalar field was already existing! assert(!sf2); - sf2 = PrepareSF(corePoints.cloud, qPrintable(resultSFName2), generatedScalarFields); + sf2 = PrepareSF(corePoints.cloud, qPrintable(resultSFName2), generatedScalarFields, SFCollector::ALWAYS_REMOVE); if (!sf2) { error = QString("Failed to prepare scalar field for %1 @ scale %2").arg(cloud2Label).arg(scale); diff --git a/PointFeature.cpp b/PointFeature.cpp index ba0ee6f..f5c508d 100644 --- a/PointFeature.cpp +++ b/PointFeature.cpp @@ -479,13 +479,12 @@ bool PointFeature::prepare( const CorePoints& corePoints, bool isScaled = scaled(); //build the final SF name - QString resultSFName; - if (cloud2) + QString resultSFName = field1->getName(); + if (cloud2 || corePoints.role != cloud1Label) { - resultSFName = cloud1Label + "."; + resultSFName += "_" + cloud1Label; } - resultSFName += field1->getName(); - + if (isScaled) { //shall we extract a statistical measure? (mandatory for scaled feature) @@ -496,15 +495,6 @@ bool PointFeature::prepare( const CorePoints& corePoints, return false; } resultSFName += QString("_") + Feature::StatToString(stat); - - //prepare the corresponding scalar field - statSF1 = PrepareSF(corePoints.cloud, qPrintable(resultSFName), generatedScalarFields); - if (!statSF1) - { - error = QString("Failed to prepare scalar field for field '%1' @ scale %2").arg(field1->getName()).arg(scale); - return false; - } - source.name = statSF1->getName(); } else //not scaled { @@ -519,7 +509,7 @@ bool PointFeature::prepare( const CorePoints& corePoints, if (field2 && op != Feature::NO_OPERATION) { //include the math operation as well if necessary! - resultSFName += "_" + Feature::OpToString(op) + "_" + cloud2Label + "." + field2->getName(); + resultSFName += "_" + Feature::OpToString(op) + "_" + field2->getName() + "_" + cloud2Label; if (isScaled) { assert(stat != Feature::NO_STAT); @@ -530,17 +520,23 @@ bool PointFeature::prepare( const CorePoints& corePoints, if (isScaled) { resultSFName += "@" + QString::number(scale); - } - if (isScaled) - { + //prepare the corresponding scalar field + statSF1 = PrepareSF(corePoints.cloud, qPrintable(resultSFName), generatedScalarFields, SFCollector::CAN_REMOVE); + if (!statSF1) + { + error = QString("Failed to prepare scalar field for field '%1' @ scale %2").arg(field1->getName()).arg(scale); + return false; + } + source.name = statSF1->getName(); + if (field2 && op != Feature::NO_OPERATION) { - QString resultSFName2 = cloud2Label + "." + field2->getName() + QString("_") + Feature::StatToString(stat) + "@" + QString::number(scale); + QString resultSFName2 = field2->getName() + QString("_") + Feature::StatToString(stat) + "_" + cloud2Label + "@" + QString::number(scale); //keepStatSF2 = (corePoints.cloud->getScalarFieldIndexByName(qPrintable(resultSFName2)) >= 0); //we remember that the scalar field was already existing! assert(!statSF2); - statSF2 = PrepareSF(corePoints.cloud, qPrintable(resultSFName2), generatedScalarFields); + statSF2 = PrepareSF(corePoints.cloud, qPrintable(resultSFName2), generatedScalarFields, SFCollector::ALWAYS_REMOVE); if (!statSF2) { error = QString("Failed to prepare scalar field for field '%1' @ scale %2").arg(field2->getName()).arg(scale); @@ -605,7 +601,7 @@ bool PointFeature::prepare( const CorePoints& corePoints, if (generatedScalarFields) { //track the generated scalar-field - generatedScalarFields->push(corePoints.cloud, resultSF); + generatedScalarFields->push(corePoints.cloud, resultSF, SFCollector::CAN_REMOVE); } corePoints.cloud->setCurrentDisplayedScalarField(newSFIdx); diff --git a/ScalarFieldCollector.cpp b/ScalarFieldCollector.cpp index a6a0d61..869dbc7 100644 --- a/ScalarFieldCollector.cpp +++ b/ScalarFieldCollector.cpp @@ -26,33 +26,37 @@ //system #include -void SFCollector::push(ccPointCloud* cloud, CCLib::ScalarField* sf) +void SFCollector::push(ccPointCloud* cloud, CCLib::ScalarField* sf, Behavior behavior) { - (*this)[cloud].insert(sf); + assert(!scalarFields.contains(sf)); + SFDesc desc; + desc.behavior = behavior; + desc.cloud = cloud; + scalarFields[sf] = desc; } -void SFCollector::releaseAllSFs() +void SFCollector::releaseSFs(bool keepByDefault) { - for (QMap< ccPointCloud*, std::set >::iterator it = begin(); it != end(); ++it) + for (Map::iterator it = scalarFields.begin(); it != scalarFields.end(); ++it) { - ccPointCloud* cloud = it.key(); - std::set& sfs = it.value(); - - for (CCLib::ScalarField* sf : sfs) + const SFDesc& desc = it.value(); + if (desc.behavior == ALWAYS_KEEP || (keepByDefault && desc.behavior == CAN_REMOVE)) { - int sfIdx = cloud->getScalarFieldIndexByName(sf->getName()); - if (sfIdx >= 0) - { - cloud->deleteScalarField(sfIdx); - } - else - { - ccLog::Warning(QString("[SFCollector] Scalar field '%1' can't be found anymore").arg(sf->getName())); - } + //keep this SF + continue; + } + + CCLib::ScalarField* sf = it.key(); + int sfIdx = desc.cloud->getScalarFieldIndexByName(sf->getName()); + if (sfIdx >= 0) + { + desc.cloud->deleteScalarField(sfIdx); + } + else + { + ccLog::Warning(QString("[SFCollector] Scalar field '%1' can't be found anymore").arg(sf->getName())); } - - sfs.clear(); } - clear(); + scalarFields.clear(); } diff --git a/ScalarFieldCollector.h b/ScalarFieldCollector.h index 1e89ae2..9aa1a73 100644 --- a/ScalarFieldCollector.h +++ b/ScalarFieldCollector.h @@ -33,11 +33,23 @@ namespace CCLib //! SF collector /** For tracking the creation and removing a set of scalar fields **/ -class SFCollector : QMap< ccPointCloud*, std::set > +class SFCollector { public: - void push(ccPointCloud* cloud, CCLib::ScalarField* sf); + enum Behavior { ALWAYS_KEEP, CAN_REMOVE, ALWAYS_REMOVE }; - void releaseAllSFs(); + void push(ccPointCloud* cloud, CCLib::ScalarField* sf, Behavior behavior); + + void releaseSFs(bool keepByDefault); + + struct SFDesc + { + ccPointCloud* cloud = nullptr; + CCLib::ScalarField* sf = nullptr; + Behavior behavior = CAN_REMOVE; + }; + + using Map = QMap< CCLib::ScalarField*, SFDesc >; + Map scalarFields; }; diff --git a/q3DMASC.cpp b/q3DMASC.cpp index 644f39d..35acb70 100644 --- a/q3DMASC.cpp +++ b/q3DMASC.cpp @@ -186,7 +186,7 @@ void q3DMASCPlugin::doClassifyAction() if (!masc::Tools::PrepareFeatures(corePoints, features, error, &progressDlg, &generatedScalarFields)) { m_app->dispToConsole(error, ccMainAppInterface::ERR_CONSOLE_MESSAGE); - generatedScalarFields.releaseAllSFs(); + generatedScalarFields.releaseSFs(false); return; } progressDlg.close(); @@ -201,14 +201,11 @@ void q3DMASCPlugin::doClassifyAction() if (!classifier.classify(featureSources, corePoints.cloud, errorMessage, m_app->getMainWindow())) { m_app->dispToConsole(errorMessage, ccMainAppInterface::ERR_CONSOLE_MESSAGE); - generatedScalarFields.releaseAllSFs(); + generatedScalarFields.releaseSFs(false); return; } - if (!s_keepAttributes) - { - generatedScalarFields.releaseAllSFs(); - } + generatedScalarFields.releaseSFs(s_keepAttributes); } } @@ -484,8 +481,8 @@ void q3DMASCPlugin::doTrainAction() if (!masc::Tools::PrepareFeatures(corePoints, toPrepare, error, &progressDlg, &generatedScalarFields)) { m_app->dispToConsole(error, ccMainAppInterface::ERR_CONSOLE_MESSAGE); - generatedScalarFields.releaseAllSFs(); - generatedScalarFieldsTest.releaseAllSFs(); + generatedScalarFields.releaseSFs(false); + generatedScalarFieldsTest.releaseSFs(false); return; } progressDlg.setAutoClose(true); //restore the default behavior of the progress dialog @@ -533,8 +530,8 @@ void q3DMASCPlugin::doTrainAction() if (!masc::Tools::RandomSubset(corePoints.cloud, testDataRatio, testSubset.data(), trainSubset.data())) { m_app->dispToConsole("Not enough memory to generate the test subsets", ccMainAppInterface::ERR_CONSOLE_MESSAGE); - generatedScalarFields.releaseAllSFs(); - generatedScalarFieldsTest.releaseAllSFs(); + generatedScalarFields.releaseSFs(false); + generatedScalarFieldsTest.releaseSFs(false); return; } previousTestSubsetRatio = testDataRatio; @@ -558,8 +555,8 @@ void q3DMASCPlugin::doTrainAction() )) { m_app->dispToConsole(errorMessage, ccMainAppInterface::ERR_CONSOLE_MESSAGE); - generatedScalarFields.releaseAllSFs(); - generatedScalarFieldsTest.releaseAllSFs(); + generatedScalarFields.releaseSFs(false); + generatedScalarFieldsTest.releaseSFs(false); return; } trainDlg.setFirstRunDone(); @@ -602,8 +599,8 @@ void q3DMASCPlugin::doTrainAction() if (!masc::Tools::PrepareFeatures(corePointsTest, toPrepareTest, error, &progressDlg, &generatedScalarFieldsTest)) { m_app->dispToConsole(error, ccMainAppInterface::ERR_CONSOLE_MESSAGE); - generatedScalarFields.releaseAllSFs(); - generatedScalarFieldsTest.releaseAllSFs(); + generatedScalarFields.releaseSFs(false); + generatedScalarFieldsTest.releaseSFs(false); return; } progressDlg.setAutoClose(true); //restore the default behavior of the progress dialog @@ -632,8 +629,8 @@ void q3DMASCPlugin::doTrainAction() m_app->getMainWindow())) { m_app->dispToConsole(errorMessage, ccMainAppInterface::ERR_CONSOLE_MESSAGE); - generatedScalarFields.releaseAllSFs(); - generatedScalarFieldsTest.releaseAllSFs(); + generatedScalarFields.releaseSFs(false); + generatedScalarFieldsTest.releaseSFs(false); return; } @@ -671,11 +668,8 @@ void q3DMASCPlugin::doTrainAction() if (!trainDlg.exec()) { //the dialog can be closed - if (!s_keepAttributes) - { - generatedScalarFields.releaseAllSFs(); - generatedScalarFieldsTest.releaseAllSFs(); - } + generatedScalarFields.releaseSFs(s_keepAttributes); + generatedScalarFieldsTest.releaseSFs(s_keepAttributes); return; } diff --git a/q3DMASCCommands.h b/q3DMASCCommands.h index 5103a75..70aec47 100644 --- a/q3DMASCCommands.h +++ b/q3DMASCCommands.h @@ -226,7 +226,7 @@ struct Command3DMASCClassif : public ccCommandLineInterface::Command QString errorMessage; if (!masc::Tools::PrepareFeatures(corePoints, features, errorMessage, pDlg.data(), &generatedScalarFields)) { - generatedScalarFields.releaseAllSFs(); + generatedScalarFields.releaseSFs(false); return cmd.error(errorMessage); } @@ -279,14 +279,11 @@ struct Command3DMASCClassif : public ccCommandLineInterface::Command QString errorMessage; if (!classifier.classify(featureSources, classifiedCloud, errorMessage, cmd.widgetParent())) { - generatedScalarFields.releaseAllSFs(); + generatedScalarFields.releaseSFs(false); return cmd.error(errorMessage); } - if (!keepAttributes) - { - generatedScalarFields.releaseAllSFs(); - } + generatedScalarFields.releaseSFs(keepAttributes); } if (cmd.autoSaveMode() || onlyFeatures) diff --git a/q3DMASCTools.cpp b/q3DMASCTools.cpp index e57f1dd..63800cc 100644 --- a/q3DMASCTools.cpp +++ b/q3DMASCTools.cpp @@ -1199,7 +1199,7 @@ bool Tools::PrepareFeatures(const CorePoints& corePoints, Feature::Set& features } } - //Neighborhhod features + //Neighborhood features for (NeighborhoodFeature::Shared& feature : fas.neighborhoodFeaturesPerScale[fas.scales[scaleIndex]]) { if (feature->cloud1 == sourceCloud && feature->sf1)