mirror of
https://github.com/lucaspalomodevelop/meshlab.git
synced 2026-03-13 00:07:24 +00:00
Merge branch 'master' of github.com:PeC-KAYO/meshlab
This commit is contained in:
commit
d139116d2a
@ -32,6 +32,7 @@ if (Qt5_VERSION VERSION_LESS 5.15.0)
|
||||
message(FATAL_ERROR "Minimum supported Qt5 version is 5.15!")
|
||||
endif()
|
||||
find_package(OpenMP)
|
||||
find_package(Threads)
|
||||
|
||||
message(STATUS "Searching for required components with bundled fallback")
|
||||
find_package(GLEW)
|
||||
@ -172,6 +173,7 @@ if(NOT DEFINED MESHLAB_PLUGINS) # it may be already defined in parent directory
|
||||
meshlabplugins/filter_mls
|
||||
meshlabplugins/filter_mutualglobal
|
||||
meshlabplugins/filter_mutualinfo
|
||||
meshlabplugins/filter_parametrization
|
||||
meshlabplugins/filter_plymc
|
||||
meshlabplugins/filter_qhull
|
||||
meshlabplugins/filter_quality
|
||||
|
||||
@ -65,6 +65,7 @@ set(HEADERS
|
||||
plugins/interfaces/filter_plugin.h
|
||||
plugins/interfaces/io_plugin.h
|
||||
plugins/interfaces/render_plugin.h
|
||||
plugins/action_searcher.h
|
||||
plugins/meshlab_plugin_type.h
|
||||
plugins/plugin_manager.h
|
||||
python/function.h
|
||||
@ -81,8 +82,7 @@ set(HEADERS
|
||||
ml_selection_buffers.h
|
||||
ml_thread_safe_memory_info.h
|
||||
mlapplication.h
|
||||
mlexception.h
|
||||
searcher.h)
|
||||
mlexception.h)
|
||||
|
||||
set(SOURCES
|
||||
ml_document/helpers/mesh_document_state_data.cpp
|
||||
@ -107,6 +107,7 @@ set(SOURCES
|
||||
plugins/interfaces/decorate_plugin.cpp
|
||||
plugins/interfaces/filter_plugin.cpp
|
||||
plugins/interfaces/io_plugin.cpp
|
||||
plugins/action_searcher.cpp
|
||||
plugins/meshlab_plugin_type.cpp
|
||||
plugins/plugin_manager.cpp
|
||||
python/function.cpp
|
||||
@ -121,8 +122,7 @@ set(SOURCES
|
||||
filterscript.cpp
|
||||
ml_selection_buffers.cpp
|
||||
ml_thread_safe_memory_info.cpp
|
||||
mlapplication.cpp
|
||||
searcher.cpp)
|
||||
mlapplication.cpp)
|
||||
|
||||
set(RESOURCES meshlab-common.qrc)
|
||||
|
||||
|
||||
@ -29,6 +29,7 @@
|
||||
|
||||
#include "parameters/rich_parameter_list.h"
|
||||
#include "plugins/plugin_manager.h"
|
||||
#include "plugins/action_searcher.h"
|
||||
#include "python/function_set.h"
|
||||
|
||||
QString basePath()
|
||||
@ -141,6 +142,12 @@ PluginManager& meshlab::pluginManagerInstance()
|
||||
return pm;
|
||||
}
|
||||
|
||||
ActionSearcher& meshlab::actionSearcherInstance()
|
||||
{
|
||||
static ActionSearcher as;
|
||||
return as;
|
||||
}
|
||||
|
||||
pymeshlab::FunctionSet& pymeshlab::functionSetInstance()
|
||||
{
|
||||
static FunctionSet fs(meshlab::pluginManagerInstance());
|
||||
|
||||
@ -37,6 +37,7 @@
|
||||
|
||||
class RichParameterList;
|
||||
class PluginManager;
|
||||
class ActionSearcher;
|
||||
|
||||
namespace meshlab {
|
||||
|
||||
@ -46,6 +47,7 @@ QString logDebugFileName();
|
||||
|
||||
RichParameterList& defaultGlobalParameterList();
|
||||
PluginManager& pluginManagerInstance();
|
||||
ActionSearcher& actionSearcherInstance();
|
||||
|
||||
// keep these functions inlined please
|
||||
// each plugin that uses them need to have their own definition
|
||||
|
||||
175
src/common/plugins/action_searcher.cpp
Normal file
175
src/common/plugins/action_searcher.cpp
Normal file
@ -0,0 +1,175 @@
|
||||
/*****************************************************************************
|
||||
* MeshLab o o *
|
||||
* A versatile mesh processing toolbox o o *
|
||||
* _ O _ *
|
||||
* Copyright(C) 2005-2022 \/)\/ *
|
||||
* Visual Computing Lab /\/| *
|
||||
* ISTI - Italian National Research Council | *
|
||||
* \ *
|
||||
* All rights reserved. *
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License as published by *
|
||||
* the Free Software Foundation; either version 2 of the License, or *
|
||||
* (at your option) any later version. *
|
||||
* *
|
||||
* This program is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU General Public License (http://www.gnu.org/licenses/gpl.txt) *
|
||||
* for more details. *
|
||||
* *
|
||||
****************************************************************************/
|
||||
|
||||
#include "action_searcher.h"
|
||||
|
||||
#include <cmath>
|
||||
#include <QRegExp>
|
||||
|
||||
#include "interfaces/filter_plugin.h"
|
||||
|
||||
ActionSearcher::ActionSearcher()
|
||||
{
|
||||
}
|
||||
|
||||
void ActionSearcher::clear()
|
||||
{
|
||||
titleActionsMap.clear();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Adds the given action to the ActionSearcher, allowing queries to it.
|
||||
* @param action
|
||||
*/
|
||||
void ActionSearcher::addAction(QAction *action, bool usePythonFilterNames)
|
||||
{
|
||||
if (action != nullptr) {
|
||||
|
||||
// add title to the action map
|
||||
QString title = action->text();
|
||||
title = title.toLower();
|
||||
title.remove(ignexp);
|
||||
QStringList res = title.split(sepexp, Qt::SkipEmptyParts);
|
||||
res.removeDuplicates();
|
||||
addSubStrings(res);
|
||||
for (const QString& str : qAsConst(res)) {
|
||||
titleActionsMap[str].push_back(action);
|
||||
}
|
||||
if (usePythonFilterNames) {
|
||||
// if the action is a filter, we should add also the python name to the search
|
||||
QObject* parent = action->parent();
|
||||
FilterPlugin* fp = qobject_cast<FilterPlugin*>(parent);
|
||||
if (fp) {
|
||||
QString title = fp->pythonFilterName(action);
|
||||
title.replace("_", " ");
|
||||
title.remove(ignexp);
|
||||
QStringList res = title.split(sepexp, Qt::SkipEmptyParts);
|
||||
res.removeDuplicates();
|
||||
addSubStrings(res);
|
||||
for (const QString& str : qAsConst(res)) {
|
||||
titleActionsMap[str].push_back(action);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// add info to the action map
|
||||
QString info = action->toolTip();
|
||||
info = info.toLower();
|
||||
info.remove(ignexp);
|
||||
res = info.split(sepexp, Qt::SkipEmptyParts);
|
||||
res.removeDuplicates();
|
||||
addSubStrings(res);
|
||||
for (const QString& str : qAsConst(res)) {
|
||||
infoActionsMap[str].push_back(action);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Performs a query using the inputString and returns an array containing the best matching
|
||||
* actions matching to the input string.
|
||||
*
|
||||
* The array will have maximum size equal to maxNumberactions.
|
||||
* @param inputString: query string
|
||||
* @param maxNumberActions: maximum size of the output array
|
||||
* @return array containing the best matching actions
|
||||
*/
|
||||
std::vector<QAction *> ActionSearcher::bestMatchingActions(QString inputString, int maxNumberActions) const
|
||||
{
|
||||
std::vector<QAction *> res;
|
||||
|
||||
// clean the input string
|
||||
inputString = inputString.toLower();
|
||||
inputString.replace("_", " "); // to allow python search
|
||||
inputString.remove(ignexp);
|
||||
|
||||
// split the input string
|
||||
QStringList inputList = inputString.split(sepexp, Qt::SkipEmptyParts);
|
||||
inputList.removeDuplicates();
|
||||
|
||||
const float bonuspertitleword = 1.0f / std::pow(10,inputList.size());
|
||||
|
||||
// store the ranking for each action
|
||||
std::map<QAction*, float> actionRanking;
|
||||
|
||||
// for each input string
|
||||
for (const QString& str : qAsConst(inputList)) {
|
||||
auto it = titleActionsMap.find(str);
|
||||
// if matches in a title of an action
|
||||
if (it != titleActionsMap.end()) {
|
||||
for (QAction* act : it->second) { // for each matching action, increment its ranking
|
||||
actionRanking[act] += bonuspertitleword;
|
||||
}
|
||||
}
|
||||
it = infoActionsMap.find(str);
|
||||
// if matches in a info of an action
|
||||
if (it != infoActionsMap.end()) {
|
||||
for (QAction* act : it->second) { // for each matching action, increment its ranking
|
||||
actionRanking[act]++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::map<float, std::vector<QAction*>> rankingMap; // flipped map of actionRanking
|
||||
// populate the flipped map
|
||||
for (const auto& p : actionRanking) {
|
||||
// for each ranking, push another action havint that ranking
|
||||
rankingMap[p.second].push_back(p.first);
|
||||
}
|
||||
// at the end, the map will store the actions stored by ranking
|
||||
|
||||
int count = 0; // used to stop the number of inserted actions in the resulting vector
|
||||
|
||||
// reverse iteration: start from the biggest ranking
|
||||
for (auto it = rankingMap.rbegin(); it != rankingMap.rend() && count < maxNumberActions; ++it) {
|
||||
auto v1 = it->second;
|
||||
// need to sort properly actions having the same ranking, since they would be sorted using
|
||||
// memory addresses, that are not deterministic: we use action titles
|
||||
std::sort(v1.begin(), v1.end(), ActionComparator());
|
||||
// insert the sorted actions to the result vector
|
||||
res.insert(res.end(), v1.begin(), v1.end());
|
||||
count += it->second.size();
|
||||
}
|
||||
// if at the end the number exceeded the maximum number, we truncate the array
|
||||
if (count >= maxNumberActions) {
|
||||
res.resize(maxNumberActions);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
void ActionSearcher::addSubStrings(QStringList &res)
|
||||
{
|
||||
QStringList resWithPrefix;
|
||||
foreach(QString str, res)
|
||||
{
|
||||
QString strPref = str;
|
||||
resWithPrefix.push_back(strPref);
|
||||
for(int i=0;i<str.length()-3;++i)
|
||||
{
|
||||
strPref.chop(1);
|
||||
resWithPrefix.push_back(strPref);
|
||||
}
|
||||
}
|
||||
resWithPrefix.removeDuplicates();
|
||||
res = resWithPrefix;
|
||||
}
|
||||
62
src/common/plugins/action_searcher.h
Normal file
62
src/common/plugins/action_searcher.h
Normal file
@ -0,0 +1,62 @@
|
||||
/*****************************************************************************
|
||||
* MeshLab o o *
|
||||
* A versatile mesh processing toolbox o o *
|
||||
* _ O _ *
|
||||
* Copyright(C) 2005-2022 \/)\/ *
|
||||
* Visual Computing Lab /\/| *
|
||||
* ISTI - Italian National Research Council | *
|
||||
* \ *
|
||||
* All rights reserved. *
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License as published by *
|
||||
* the Free Software Foundation; either version 2 of the License, or *
|
||||
* (at your option) any later version. *
|
||||
* *
|
||||
* This program is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU General Public License (http://www.gnu.org/licenses/gpl.txt) *
|
||||
* for more details. *
|
||||
* *
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef ACTION_SEARCHER_H
|
||||
#define ACTION_SEARCHER_H
|
||||
|
||||
#include <map>
|
||||
#include <vector>
|
||||
#include <QString>
|
||||
#include <QAction>
|
||||
|
||||
class ActionSearcher
|
||||
{
|
||||
public:
|
||||
ActionSearcher();
|
||||
|
||||
void clear();
|
||||
void addAction(QAction* action, bool usePythonFilterNames = false);
|
||||
|
||||
std::vector<QAction*> bestMatchingActions(QString inputString, int maxNumberActions) const;
|
||||
|
||||
private:
|
||||
const QRegExp sepexp = QRegExp("\\W+");
|
||||
const QRegExp ignexp = QRegExp(
|
||||
"\\b(an|the|of|it|as|in|by|and|or|for)\\b|\\b[a-z]\\b|'s\\b|\\.|<[^>]*>");
|
||||
|
||||
// map that stores, for each string, all the actions that store that string in their titles
|
||||
std::map<QString, std::vector<QAction*>> titleActionsMap;
|
||||
|
||||
// map that stores, for each stirng, all the actions that store that stirng in their info
|
||||
std::map<QString, std::vector<QAction*>> infoActionsMap;
|
||||
|
||||
struct ActionComparator {
|
||||
bool operator()(QAction* a1, QAction* a2) {
|
||||
return a1->text() < a2->text();
|
||||
}
|
||||
};
|
||||
|
||||
static void addSubStrings(QStringList& res);
|
||||
};
|
||||
|
||||
#endif // ACTION_SEARCHER_H
|
||||
@ -61,6 +61,17 @@ QAction* FilterPluginContainer::filterAction(const QString& name)
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
FilterPlugin *FilterPluginContainer::pluginOfFilter(const QAction *action) const
|
||||
{
|
||||
for (FilterPlugin* fp : filterPlugins) {
|
||||
std::list<QAction*> al = fp->actions();
|
||||
auto it = std::find(al.begin(), al.end(), action);
|
||||
if (it != al.end())
|
||||
return fp;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
FilterPluginContainer::FilterPluginRangeIterator FilterPluginContainer::filterPluginIterator(bool iterateAlsoDisabledPlugins) const
|
||||
{
|
||||
return FilterPluginRangeIterator(this, iterateAlsoDisabledPlugins);
|
||||
|
||||
@ -45,6 +45,7 @@ public:
|
||||
void eraseFilterPlugin(FilterPlugin* iFilter);
|
||||
|
||||
QAction* filterAction(const QString& name);
|
||||
FilterPlugin* pluginOfFilter(const QAction* action) const;
|
||||
|
||||
FilterPluginRangeIterator filterPluginIterator(bool iterateAlsoDisabledPlugins = false) const;
|
||||
|
||||
|
||||
@ -291,6 +291,11 @@ QAction* PluginManager::filterAction(const QString& name)
|
||||
return filterPlugins.filterAction(name);
|
||||
}
|
||||
|
||||
FilterPlugin* PluginManager::getFilterPluginFromAction(const QAction *action) const
|
||||
{
|
||||
return filterPlugins.pluginOfFilter(action);
|
||||
}
|
||||
|
||||
IOPlugin* PluginManager::inputMeshPlugin(const QString& inputFormat) const
|
||||
{
|
||||
return ioPlugins.inputMeshPlugin(inputFormat);
|
||||
|
||||
@ -62,6 +62,7 @@ public:
|
||||
DecoratePlugin* getDecoratePlugin(const QString& name);
|
||||
|
||||
QAction* filterAction(const QString& name);
|
||||
FilterPlugin* getFilterPluginFromAction(const QAction* action) const;
|
||||
|
||||
IOPlugin* inputMeshPlugin(const QString& inputFormat) const;
|
||||
IOPlugin* outputMeshPlugin(const QString& outputFormat) const;
|
||||
|
||||
@ -1,151 +0,0 @@
|
||||
#include "searcher.h"
|
||||
#include "mlexception.h"
|
||||
|
||||
#include <cmath>
|
||||
|
||||
WordActionsMap::WordActionsMap()
|
||||
:wordacts()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void WordActionsMap::addWordsPerAction(QAction& act,const QStringList& words)
|
||||
{
|
||||
foreach(QString word,words)
|
||||
wordacts[word].push_back(&act);
|
||||
}
|
||||
|
||||
void WordActionsMap::removeActionReferences(QAction& act )
|
||||
{
|
||||
for(QMap<QString,QList<QAction*> >::iterator it = wordacts.begin();it != wordacts.end();++it)
|
||||
it.value().removeAll(&act);
|
||||
}
|
||||
|
||||
bool WordActionsMap::getActionsPerWord( const QString& word,QList<QAction*>& res ) const
|
||||
{
|
||||
QMap< QString,QList<QAction*> >::const_iterator it = wordacts.find(word);
|
||||
if (it != wordacts.end())
|
||||
{
|
||||
res = it.value();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void WordActionsMap::clear()
|
||||
{
|
||||
wordacts.clear();
|
||||
}
|
||||
|
||||
WordActionsMapAccessor::WordActionsMapAccessor()
|
||||
:map(),sepexp(),ignexp()
|
||||
{
|
||||
sepexp.setPattern("\\W+");
|
||||
ignexp.setPattern("\\b(an|the|of|it|as|in|by|and|or|for)\\b|\\b[a-z]\\b|'s\\b|\\.|<[^>]*>");
|
||||
}
|
||||
|
||||
void WordActionsMapAccessor::addWordsPerAction(QAction& act,const QString& st )
|
||||
{
|
||||
QStringList wlist;
|
||||
purifiedSplit(st,wlist);
|
||||
addSubStrings(wlist);
|
||||
map.addWordsPerAction(act,wlist);
|
||||
}
|
||||
|
||||
int WordActionsMapAccessor::rankedMatchesPerInputString( const QString& input,RankedMatches& rm ) const
|
||||
{
|
||||
QStringList inputlist;
|
||||
purifiedSplit(input,inputlist);
|
||||
return rm.computeRankedMatches(inputlist,map);
|
||||
}
|
||||
|
||||
void WordActionsMapAccessor::purifiedSplit( const QString& input,QStringList& res ) const
|
||||
{
|
||||
res.clear();
|
||||
QString tmp = input;
|
||||
tmp = tmp.toLower();
|
||||
tmp.remove(ignexp);
|
||||
res = tmp.split(sepexp,QString::SkipEmptyParts);
|
||||
res.removeDuplicates();
|
||||
}
|
||||
|
||||
void WordActionsMapAccessor::addSubStrings( QStringList& res ) const
|
||||
{
|
||||
QStringList resWithPrefix;
|
||||
foreach(QString str, res)
|
||||
{
|
||||
QString strPref = str;
|
||||
resWithPrefix.push_back(strPref);
|
||||
for(int i=0;i<str.length()-3;++i)
|
||||
{
|
||||
strPref.chop(1);
|
||||
resWithPrefix.push_back(strPref);
|
||||
}
|
||||
}
|
||||
resWithPrefix.removeDuplicates();
|
||||
res = resWithPrefix;
|
||||
}
|
||||
|
||||
RankedMatches::RankedMatches()
|
||||
:ranking()
|
||||
{
|
||||
}
|
||||
|
||||
int RankedMatches::computeRankedMatches( const QStringList& inputst,const WordActionsMap& map, bool matchesontitlearemoreimportant)
|
||||
{
|
||||
QMap<QAction*, float> wordmatchesperaction;
|
||||
ranking.clear();
|
||||
int inputstsize = inputst.size();
|
||||
ranking.resize(inputstsize);
|
||||
float bonuspertitleword = 0.0f;
|
||||
if (matchesontitlearemoreimportant)
|
||||
bonuspertitleword = 1.0f / std::pow(10,inputstsize);
|
||||
foreach(const QString& st,inputst)
|
||||
{
|
||||
QList<QAction*> res;
|
||||
bool found = map.getActionsPerWord(st,res);
|
||||
if (found)
|
||||
{
|
||||
foreach(QAction* act, res)
|
||||
{
|
||||
++wordmatchesperaction[act];
|
||||
QString title = act->text().toLower().trimmed();
|
||||
if (title.contains(st))
|
||||
wordmatchesperaction[act] = wordmatchesperaction[act] + bonuspertitleword;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
QMap<float, QList<QAction*> > rankedmatches;
|
||||
for (QMap<QAction*, float>::iterator it = wordmatchesperaction.begin(); it != wordmatchesperaction.end(); ++it)
|
||||
rankedmatches[it.value()].push_back(it.key());
|
||||
|
||||
int maxindex = -1;
|
||||
for(QMap<float,QList<QAction*> >::iterator it = rankedmatches.end() - 1;it != rankedmatches.begin() - 1;--it)
|
||||
{
|
||||
int index = std::floor(it.key()) - 1;
|
||||
if (index >= ranking.size())
|
||||
{
|
||||
throw InvalidInvariantException("WARNING! Index contained in wordmatchesperaction it's out-of-bound.");
|
||||
return 0;
|
||||
}
|
||||
if (index > maxindex)
|
||||
maxindex = index;
|
||||
ranking[index].append(it.value());
|
||||
}
|
||||
return maxindex + 1;
|
||||
}
|
||||
|
||||
void RankedMatches::getActionsWithNMatches( const int n,QList<QAction*>& res )
|
||||
{
|
||||
res.clear();
|
||||
int index = n -1;
|
||||
if ((index >= ranking.size()) || (n < 1))
|
||||
{
|
||||
throw InvalidInvariantException(QString("WARNING! Parameter n MUST be in the range [1..") + QString::number(ranking.size()) + "].");
|
||||
return;
|
||||
}
|
||||
res = ranking[index];
|
||||
}
|
||||
|
||||
|
||||
@ -1,58 +0,0 @@
|
||||
#ifndef SEARCHER_H
|
||||
#define SEARCHER_H
|
||||
|
||||
#include<QString>
|
||||
#include<QMap>
|
||||
#include<QList>
|
||||
#include<QAction>
|
||||
#include<QRegExp>
|
||||
#include<QVector>
|
||||
#include<QSet>
|
||||
|
||||
class WordActionsMap
|
||||
{
|
||||
public:
|
||||
WordActionsMap();
|
||||
void addWordsPerAction(QAction& act,const QStringList& words);
|
||||
void removeActionReferences(QAction& act);
|
||||
bool getActionsPerWord( const QString& word,QList<QAction*>& res ) const;
|
||||
void clear();
|
||||
private:
|
||||
QMap<QString,QList<QAction*> > wordacts;
|
||||
};
|
||||
|
||||
class RankedMatches;
|
||||
|
||||
class WordActionsMapAccessor
|
||||
{
|
||||
public:
|
||||
WordActionsMapAccessor();
|
||||
void addWordsPerAction(QAction& act,const QString& st);
|
||||
inline void removeActionReferences(QAction& act) {map.removeActionReferences(act);}
|
||||
inline void setSeparator(const QRegExp& sep) {sepexp = sep;}
|
||||
inline void setIgnoredWords(const QRegExp& ign) {ignexp = ign;}
|
||||
int rankedMatchesPerInputString(const QString& input,RankedMatches& rm) const;
|
||||
inline QRegExp separtor() const {return sepexp;}
|
||||
inline QRegExp ignored() const {return ignexp;}
|
||||
void clear() {map.clear(); sepexp = QRegExp(); ignexp = QRegExp();}
|
||||
|
||||
private:
|
||||
void purifiedSplit(const QString& input,QStringList& res) const;
|
||||
void addSubStrings(QStringList& res) const;
|
||||
WordActionsMap map;
|
||||
QRegExp sepexp;
|
||||
QRegExp ignexp;
|
||||
};
|
||||
|
||||
class RankedMatches
|
||||
{
|
||||
public:
|
||||
RankedMatches();
|
||||
void getActionsWithNMatches(const int n,QList<QAction*>& res);
|
||||
private:
|
||||
friend int WordActionsMapAccessor::rankedMatchesPerInputString(const QString& input,RankedMatches& rm) const;
|
||||
int computeRankedMatches(const QStringList& inputst,const WordActionsMap& map,bool matchesontitlearemoreimportant = true);
|
||||
QVector<QList<QAction*> > ranking;
|
||||
};
|
||||
|
||||
#endif
|
||||
@ -31,9 +31,12 @@
|
||||
typedef Eigen::Matrix<Scalarm, Eigen::Dynamic, 1> EigenVectorXm;
|
||||
typedef Eigen::Matrix<bool, Eigen::Dynamic, 1> EigenVectorXb;
|
||||
typedef Eigen::Matrix<unsigned int, Eigen::Dynamic, 1> EigenVectorXui;
|
||||
typedef Eigen::Matrix<Scalarm, Eigen::Dynamic, 2> EigenMatrixX2m;
|
||||
typedef Eigen::Matrix<Scalarm, Eigen::Dynamic, 3> EigenMatrixX3m;
|
||||
typedef Eigen::Matrix<Scalarm, Eigen::Dynamic, 4> EigenMatrixX4m;
|
||||
|
||||
typedef Eigen::Matrix<Scalarm, Eigen::Dynamic, 2> EigenMatrixX2m;
|
||||
typedef Eigen::Matrix<Scalarm, Eigen::Dynamic, 3> EigenMatrixX3m;
|
||||
typedef Eigen::Matrix<Scalarm, Eigen::Dynamic, 4> EigenMatrixX4m;
|
||||
|
||||
typedef Eigen::Matrix<Scalarm, Eigen::Dynamic, Eigen::Dynamic> EigenMatrixXm;
|
||||
|
||||
namespace meshlab {
|
||||
|
||||
|
||||
@ -8,7 +8,7 @@
|
||||
#include <QStyle>
|
||||
#include <QDebug>
|
||||
|
||||
SearchMenu::SearchMenu(const WordActionsMapAccessor& wm,const int max,QWidget* parent,const int fixedwidth)
|
||||
SearchMenu::SearchMenu(const ActionSearcher& wm,const int max,QWidget* parent,const int fixedwidth)
|
||||
:MenuWithToolTip(QString(),parent),searchline(NULL),wama(wm),maxres(max),fixedwidthsize(fixedwidth)
|
||||
{
|
||||
searchline = new MenuLineEdit(this);
|
||||
@ -24,29 +24,14 @@ SearchMenu::SearchMenu(const WordActionsMapAccessor& wm,const int max,QWidget* p
|
||||
|
||||
void SearchMenu::getResults(const QString& text,QList<QAction*>& result)
|
||||
{
|
||||
try
|
||||
{
|
||||
RankedMatches rm;
|
||||
int ii = wama.rankedMatchesPerInputString(text,rm);
|
||||
int inserted = 0;
|
||||
while(ii > 0)
|
||||
{
|
||||
QList<QAction*> myacts;
|
||||
rm.getActionsWithNMatches(ii,myacts);
|
||||
if (inserted + myacts.size() > maxres)
|
||||
myacts = myacts.mid(0,myacts.size() - (inserted + myacts.size() - maxres));
|
||||
result.append(myacts);
|
||||
QAction* sep = new QAction(this);
|
||||
sep->setSeparator(true);
|
||||
result.append(sep);
|
||||
inserted += myacts.size();
|
||||
--ii;
|
||||
}
|
||||
}
|
||||
catch(InvalidInvariantException& e)
|
||||
{
|
||||
qDebug() << "WARNING!!!!!!!!!!!!!!!!!!!" << e.what() << "\n";
|
||||
}
|
||||
std::vector<QAction*> rm = wama.bestMatchingActions(text, 15);
|
||||
|
||||
for (QAction* act : rm) {
|
||||
result.append(act);
|
||||
}
|
||||
QAction* sep = new QAction(this);
|
||||
sep->setSeparator(true);
|
||||
result.append(sep);
|
||||
}
|
||||
|
||||
void SearchMenu::updateGUI( const QList<QAction*>& results )
|
||||
|
||||
@ -20,7 +20,7 @@
|
||||
#include <QPushButton>
|
||||
#include <QLabel>
|
||||
#include <QSlider>
|
||||
#include "../common/searcher.h"
|
||||
#include "../common/plugins/action_searcher.h"
|
||||
#include <QToolTip>
|
||||
#include <QSyntaxHighlighter>
|
||||
#include <QProxyStyle>
|
||||
@ -75,7 +75,7 @@ class SearchMenu : public MenuWithToolTip
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
SearchMenu(const WordActionsMapAccessor& wm,const int max,QWidget* parent,const int fixedwidth = -1);
|
||||
SearchMenu(const ActionSearcher& wm,const int max,QWidget* parent,const int fixedwidth = -1);
|
||||
int& searchLineWidth();
|
||||
void clearResults();
|
||||
QSize sizeHint () const;
|
||||
@ -84,7 +84,7 @@ protected:
|
||||
void resizeEvent ( QResizeEvent * event);
|
||||
private:
|
||||
MenuLineEdit* searchline;
|
||||
const WordActionsMapAccessor& wama;
|
||||
const ActionSearcher& wama;
|
||||
int maxres;
|
||||
int fixedwidthsize;
|
||||
|
||||
|
||||
@ -119,7 +119,7 @@ void PluginInfoDialog::on_loadPluginsPushButton_clicked()
|
||||
QStringList fileList = QFileDialog::getOpenFileNames(this, "Load Plugins", "", pluginFileFormat);
|
||||
PluginManager& pm = meshlab::pluginManagerInstance();
|
||||
bool loadOk = false;
|
||||
for (const QString& fileName : fileList){
|
||||
for (const QString& fileName : qAsConst(fileList)){
|
||||
QFileInfo finfo(fileName);
|
||||
|
||||
try {
|
||||
|
||||
@ -256,8 +256,6 @@ private:
|
||||
void createActions();
|
||||
void createMenus();
|
||||
void initSearchEngine();
|
||||
void initItemForSearching(QAction* act);
|
||||
void initMenuForSearching(QMenu* menu);
|
||||
void fillFilterMenu();
|
||||
void fillRenderMenu();
|
||||
void fillShadersMenu();
|
||||
@ -361,7 +359,7 @@ public:
|
||||
QMenu* rasterLayerMenu() { return filterMenuRasterLayer; }
|
||||
|
||||
private:
|
||||
WordActionsMapAccessor wama;
|
||||
ActionSearcher& searcher;
|
||||
//////// ToolBars ///////////////
|
||||
QToolBar* mainToolBar;
|
||||
QToolBar* decoratorToolBar;
|
||||
|
||||
@ -36,7 +36,6 @@
|
||||
#include <QWidgetAction>
|
||||
#include <QMessageBox>
|
||||
#include "mainwindow.h"
|
||||
#include <common/searcher.h>
|
||||
#include <common/mlapplication.h>
|
||||
#include <common/mlexception.h>
|
||||
#include <common/globals.h>
|
||||
@ -47,13 +46,14 @@
|
||||
|
||||
QProgressBar *MainWindow::qb;
|
||||
|
||||
MainWindow::MainWindow():
|
||||
httpReq(this),
|
||||
gpumeminfo(NULL),
|
||||
defaultGlobalParams(meshlab::defaultGlobalParameterList()),
|
||||
lastUsedDirectory(QDir::home()),
|
||||
PM(meshlab::pluginManagerInstance()),
|
||||
_currviewcontainer(NULL)
|
||||
MainWindow::MainWindow() :
|
||||
searcher(meshlab::actionSearcherInstance()),
|
||||
httpReq(this),
|
||||
gpumeminfo(NULL),
|
||||
defaultGlobalParams(meshlab::defaultGlobalParameterList()),
|
||||
lastUsedDirectory(QDir::home()),
|
||||
PM(meshlab::pluginManagerInstance()),
|
||||
_currviewcontainer(NULL)
|
||||
{
|
||||
QSettings settings;
|
||||
//toDelete plugins, flagged in the last session
|
||||
@ -651,7 +651,7 @@ void MainWindow::createMenus()
|
||||
{
|
||||
initSearchEngine();
|
||||
int longest = longestActionWidthInAllMenus();
|
||||
searchMenu = new SearchMenu(wama, 15, searchButton, longest);
|
||||
searchMenu = new SearchMenu(searcher, 15, searchButton, longest);
|
||||
searchButton->setMenu(searchMenu);
|
||||
connect(searchShortCut, SIGNAL(activated()), searchButton, SLOT(openMenu()));
|
||||
}
|
||||
@ -659,41 +659,23 @@ void MainWindow::createMenus()
|
||||
|
||||
void MainWindow::initSearchEngine()
|
||||
{
|
||||
searcher.clear();
|
||||
for (const auto& p : PM.filterPluginIterator()){
|
||||
for (QAction* act : p->actions())
|
||||
initItemForSearching(act);
|
||||
searcher.addAction(act);
|
||||
}
|
||||
/*for (const auto& p : PM.editPluginFactoryIterator()){
|
||||
for (const auto& p : PM.editPluginFactoryIterator()){
|
||||
for (QAction* act : p->actions())
|
||||
initItemForSearching(act);
|
||||
searcher.addAction(act);
|
||||
}
|
||||
for (const auto& p : PM.renderPluginIterator()){
|
||||
for (QAction* act : p->actions())
|
||||
initItemForSearching(act);
|
||||
}*/
|
||||
|
||||
initMenuForSearching(editMenu);
|
||||
initMenuForSearching(renderMenu);
|
||||
}
|
||||
|
||||
void MainWindow::initMenuForSearching(QMenu* menu)
|
||||
{
|
||||
if (menu == NULL)
|
||||
return;
|
||||
const QList<QAction*>& acts = menu->actions();
|
||||
for(QAction* act: acts) {
|
||||
QMenu* submenu = act->menu();
|
||||
if (!act->isSeparator() && (submenu == NULL))
|
||||
initItemForSearching(act);
|
||||
else if (!act->isSeparator())
|
||||
initMenuForSearching(submenu);
|
||||
searcher.addAction(act);
|
||||
}
|
||||
for (const auto& p : PM.decoratePluginIterator()){
|
||||
for (QAction* act : p->actions())
|
||||
searcher.addAction(act);
|
||||
}
|
||||
}
|
||||
|
||||
void MainWindow::initItemForSearching(QAction* act)
|
||||
{
|
||||
QString tx = act->text() + " " + act->toolTip();
|
||||
wama.addWordsPerAction(*act, tx);
|
||||
}
|
||||
|
||||
QString MainWindow::getDecoratedFileName(const QString& name)
|
||||
@ -930,20 +912,6 @@ void MainWindow::updateAllPluginsActions()
|
||||
|
||||
filterToolBar->clear();
|
||||
updateFilterToolBar();
|
||||
|
||||
//TODO update the searcher: this seems to be an impossible task due to unreadable code.
|
||||
//for now, just close and reopen meshlab....
|
||||
/*
|
||||
disconnect(searchShortCut, SIGNAL(activated()), searchButton, SLOT(openMenu()));
|
||||
wama.clear();
|
||||
delete searchMenu;
|
||||
|
||||
initSearchEngine();
|
||||
int longest = longestActionWidthInAllMenus();
|
||||
searchMenu = new SearchMenu(wama, 15, searchButton, longest);
|
||||
searchButton->setMenu(searchMenu);
|
||||
connect(searchShortCut, SIGNAL(activated()), searchButton, SLOT(openMenu()));
|
||||
*/
|
||||
}
|
||||
|
||||
void MainWindow::loadDefaultSettingsFromPlugins()
|
||||
|
||||
@ -2576,6 +2576,7 @@ void MainWindow::aboutPlugins()
|
||||
PluginInfoDialog dialog(this);
|
||||
dialog.exec();
|
||||
updateAllPluginsActions();
|
||||
initSearchEngine();
|
||||
QSettings settings;
|
||||
QStringList disabledPlugins;
|
||||
for (MeshLabPlugin* pf : PM.pluginIterator(true)){
|
||||
|
||||
15
src/meshlabplugins/filter_parametrization/CMakeLists.txt
Normal file
15
src/meshlabplugins/filter_parametrization/CMakeLists.txt
Normal file
@ -0,0 +1,15 @@
|
||||
# Copyright 2019, 2020, Visual Computing Lab, ISTI - Italian National Research Council
|
||||
|
||||
if (TARGET external-libigl AND TARGET Threads::Threads)
|
||||
|
||||
set(SOURCES filter_parametrization.cpp)
|
||||
|
||||
set(HEADERS filter_parametrization.h)
|
||||
|
||||
add_meshlab_plugin(filter_parametrization ${SOURCES} ${HEADERS})
|
||||
|
||||
target_link_libraries(filter_parametrization PRIVATE external-libigl Threads::Threads)
|
||||
else()
|
||||
message(
|
||||
STATUS "Skipping filter_parametrization - don't know about libigl or Threads::Threads on this system.")
|
||||
endif()
|
||||
@ -0,0 +1,219 @@
|
||||
/****************************************************************************
|
||||
* MeshLab o o *
|
||||
* A versatile mesh processing toolbox o o *
|
||||
* _ O _ *
|
||||
* Copyright(C) 2005-2021 \/)\/ *
|
||||
* Visual Computing Lab /\/| *
|
||||
* ISTI - Italian National Research Council | *
|
||||
* \ *
|
||||
* All rights reserved. *
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License as published by *
|
||||
* the Free Software Foundation; either version 2 of the License, or *
|
||||
* (at your option) any later version. *
|
||||
* *
|
||||
* This program is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU General Public License (http://www.gnu.org/licenses/gpl.txt) *
|
||||
* for more details. *
|
||||
* *
|
||||
****************************************************************************/
|
||||
|
||||
#include "filter_parametrization.h"
|
||||
|
||||
#include <common/utilities/eigen_mesh_conversions.h>
|
||||
|
||||
#include <igl/boundary_loop.h>
|
||||
#include <igl/harmonic.h>
|
||||
#include <igl/lscm.h>
|
||||
#include <igl/map_vertices_to_circle.h>
|
||||
|
||||
FilterParametrizationPlugin::FilterParametrizationPlugin()
|
||||
{
|
||||
typeList = { FP_HARMONIC_PARAM, FP_LEAST_SQUARES_PARAM};
|
||||
|
||||
for(const ActionIDType& tt : typeList)
|
||||
actionList.push_back(new QAction(filterName(tt), this));
|
||||
}
|
||||
|
||||
QString FilterParametrizationPlugin::pluginName() const
|
||||
{
|
||||
return "FilterParametrization";
|
||||
}
|
||||
|
||||
QString FilterParametrizationPlugin::vendor() const
|
||||
{
|
||||
return "CNR-ISTI-VCLab";
|
||||
}
|
||||
|
||||
QString FilterParametrizationPlugin::filterName(ActionIDType filterId) const
|
||||
{
|
||||
switch(filterId) {
|
||||
case FP_HARMONIC_PARAM :
|
||||
return "Harmonic Parametrization";
|
||||
case FP_LEAST_SQUARES_PARAM:
|
||||
return "Least Squares Conformal Maps Parametrization";
|
||||
default :
|
||||
assert(0);
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
QString FilterParametrizationPlugin::pythonFilterName(ActionIDType filter) const
|
||||
{
|
||||
switch(filter) {
|
||||
case FP_HARMONIC_PARAM :
|
||||
return "compute_texcoord_parametrization_harmonic";
|
||||
case FP_LEAST_SQUARES_PARAM:
|
||||
return "compute_texcoord_parametrization_least_squares_conformal_maps";
|
||||
default :
|
||||
assert(0);
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
QString FilterParametrizationPlugin::filterInfo(ActionIDType filterId) const
|
||||
{
|
||||
QString commonDescription =
|
||||
"The resulting parametrization is saved in the per vertex texture coordinates.<br>"
|
||||
"The filter uses the original code provided in the "
|
||||
"<a href=\"https://libigl.github.io/\">libigl library</a>.<br>";
|
||||
switch(filterId) {
|
||||
case FP_HARMONIC_PARAM :
|
||||
return "Computes a single patch, fixed boundary harmonic parametrization of a mesh. The "
|
||||
"filter requires that the input mesh has a single fixed boundary." +
|
||||
commonDescription;
|
||||
case FP_LEAST_SQUARES_PARAM:
|
||||
return "Compuites a least squares conformal maps parametrization of a mesh. " +
|
||||
commonDescription;
|
||||
default :
|
||||
assert(0);
|
||||
return "Unknown Filter";
|
||||
}
|
||||
}
|
||||
|
||||
FilterParametrizationPlugin::FilterClass FilterParametrizationPlugin::getClass(const QAction *a) const
|
||||
{
|
||||
switch(ID(a)) {
|
||||
case FP_HARMONIC_PARAM :
|
||||
case FP_LEAST_SQUARES_PARAM:
|
||||
return FilterPlugin::Texture;
|
||||
default :
|
||||
assert(0);
|
||||
return FilterPlugin::Generic;
|
||||
}
|
||||
}
|
||||
|
||||
FilterPlugin::FilterArity FilterParametrizationPlugin::filterArity(const QAction*) const
|
||||
{
|
||||
return SINGLE_MESH;
|
||||
}
|
||||
|
||||
int FilterParametrizationPlugin::getPreConditions(const QAction*) const
|
||||
{
|
||||
return MeshModel::MM_VERTCOORD | MeshModel::MM_FACEVERT;
|
||||
}
|
||||
|
||||
int FilterParametrizationPlugin::getRequirements(const QAction*)
|
||||
{
|
||||
return MeshModel::MM_VERTTEXCOORD;
|
||||
}
|
||||
|
||||
int FilterParametrizationPlugin::postCondition(const QAction*) const
|
||||
{
|
||||
return MeshModel::MM_VERTTEXCOORD;
|
||||
}
|
||||
|
||||
RichParameterList FilterParametrizationPlugin::initParameterList(const QAction *action, const MeshModel &)
|
||||
{
|
||||
RichParameterList parlst;
|
||||
switch(ID(action)) {
|
||||
case FP_HARMONIC_PARAM :
|
||||
parlst.addParam(RichInt("harm_function", 1,"N-Harmonic Function", "1 denotes harmonic function, 2 biharmonic, 3 triharmonic, etc."));
|
||||
break;
|
||||
case FP_LEAST_SQUARES_PARAM:
|
||||
|
||||
break;
|
||||
default :
|
||||
assert(0);
|
||||
}
|
||||
return parlst;
|
||||
}
|
||||
|
||||
std::map<std::string, QVariant> FilterParametrizationPlugin::applyFilter(
|
||||
const QAction * action,
|
||||
const RichParameterList & par,
|
||||
MeshDocument &md,
|
||||
unsigned int& /*postConditionMask*/,
|
||||
vcg::CallBackPos *)
|
||||
{
|
||||
switch(ID(action)) {
|
||||
case FP_HARMONIC_PARAM : {
|
||||
int f = par.getInt("harm_function");
|
||||
if (f < 1)
|
||||
throw MLException("Invalid N-Harmonic Function value. Must be >= 1.");
|
||||
|
||||
EigenMatrixX3m v = meshlab::vertexMatrix(md.mm()->cm);
|
||||
Eigen::MatrixX3d verts = v.cast<double>();
|
||||
Eigen::MatrixX3i faces = meshlab::faceMatrix(md.mm()->cm);
|
||||
|
||||
Eigen::MatrixXd V_uv, bnd_uv;
|
||||
Eigen::VectorXi bnd;
|
||||
|
||||
igl::boundary_loop(faces,bnd);
|
||||
if (bnd.size() == 0)
|
||||
throw MLException(
|
||||
"Harmonic Parametrization can be applied only on meshes that have a boundary.");
|
||||
igl::map_vertices_to_circle(verts, bnd, bnd_uv);
|
||||
igl::harmonic(verts,faces,bnd,bnd_uv,1,V_uv);
|
||||
|
||||
unsigned int i = 0;
|
||||
for (auto& v : md.mm()->cm.vert){
|
||||
v.T().u() =V_uv(i, 0);
|
||||
v.T().v() =V_uv(i, 1);
|
||||
i++;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
case FP_LEAST_SQUARES_PARAM: {
|
||||
EigenMatrixX3m v = meshlab::vertexMatrix(md.mm()->cm);
|
||||
Eigen::MatrixX3d verts = v.cast<double>();
|
||||
Eigen::MatrixX3i faces = meshlab::faceMatrix(md.mm()->cm);
|
||||
Eigen::VectorXi bnd, boundaryPoints(2, 1);
|
||||
|
||||
Eigen::MatrixXd V_uv;
|
||||
|
||||
igl::boundary_loop(faces,bnd);
|
||||
if (bnd.size() == 0)
|
||||
throw MLException(
|
||||
"Least Squares Conformal Maps Parametrization can be applied only on meshes that "
|
||||
"have a boundary.");
|
||||
|
||||
boundaryPoints(0) = bnd(0);
|
||||
boundaryPoints(1) = bnd(bnd.size()/2);
|
||||
|
||||
Eigen::MatrixXd bc(2,2);
|
||||
bc<<0,0,1,0;
|
||||
|
||||
// LSCM parametrization
|
||||
igl::lscm(verts,faces,boundaryPoints,bc,V_uv);
|
||||
|
||||
unsigned int i = 0;
|
||||
for (auto& v : md.mm()->cm.vert){
|
||||
v.T().u() =V_uv(i, 0);
|
||||
v.T().v() =V_uv(i, 1);
|
||||
i++;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
default :
|
||||
wrongActionCalled(action);
|
||||
}
|
||||
return std::map<std::string, QVariant>();
|
||||
}
|
||||
|
||||
MESHLAB_PLUGIN_NAME_EXPORTER(FilterSamplePlugin)
|
||||
@ -0,0 +1,66 @@
|
||||
/****************************************************************************
|
||||
* MeshLab o o *
|
||||
* A versatile mesh processing toolbox o o *
|
||||
* _ O _ *
|
||||
* Copyright(C) 2005-2021 \/)\/ *
|
||||
* Visual Computing Lab /\/| *
|
||||
* ISTI - Italian National Research Council | *
|
||||
* \ *
|
||||
* All rights reserved. *
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License as published by *
|
||||
* the Free Software Foundation; either version 2 of the License, or *
|
||||
* (at your option) any later version. *
|
||||
* *
|
||||
* This program is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU General Public License (http://www.gnu.org/licenses/gpl.txt) *
|
||||
* for more details. *
|
||||
* *
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef MESHLAB_FILTER_PARAMETRIZATION_PLUGIN_H
|
||||
#define MESHLAB_FILTER_PARAMETRIZATION_PLUGIN_H
|
||||
|
||||
#include <common/plugins/interfaces/filter_plugin.h>
|
||||
|
||||
class FilterParametrizationPlugin : public QObject, public FilterPlugin
|
||||
{
|
||||
//keep these three lines unchanged
|
||||
Q_OBJECT
|
||||
MESHLAB_PLUGIN_IID_EXPORTER(FILTER_PLUGIN_IID)
|
||||
Q_INTERFACES(FilterPlugin)
|
||||
|
||||
public:
|
||||
//enum used to give an ID to every filter implemented in the plugin
|
||||
enum FileterIds {
|
||||
FP_HARMONIC_PARAM,
|
||||
FP_LEAST_SQUARES_PARAM};
|
||||
|
||||
FilterParametrizationPlugin();
|
||||
|
||||
QString pluginName() const;
|
||||
QString vendor() const;
|
||||
|
||||
QString filterName(ActionIDType filter) const;
|
||||
QString pythonFilterName(ActionIDType filter) const;
|
||||
QString filterInfo(ActionIDType filter) const;
|
||||
FilterClass getClass(const QAction* a) const;
|
||||
FilterArity filterArity(const QAction*) const;
|
||||
int getPreConditions(const QAction *) const;
|
||||
int getRequirements(const QAction *);
|
||||
int postCondition(const QAction* ) const;
|
||||
RichParameterList initParameterList(const QAction*, const MeshModel &/*m*/);
|
||||
std::map<std::string, QVariant> applyFilter(
|
||||
const QAction* action,
|
||||
const RichParameterList & params,
|
||||
MeshDocument &md,
|
||||
unsigned int& postConditionMask,
|
||||
vcg::CallBackPos * cb);
|
||||
|
||||
private:
|
||||
};
|
||||
|
||||
#endif //MESHLAB_FILTER_PARAMETRIZATION_PLUGIN_H
|
||||
@ -162,6 +162,7 @@ RichParameterList FilterSamplePlugin::initParameterList(const QAction *action,co
|
||||
case FP_MOVE_VERTEX :
|
||||
parlst.addParam(RichBool ("UpdateNormals", true, "Recompute normals", "Toggle the recomputation of the normals after the random displacement.\n\nIf disabled the face normals will remains unchanged resulting in a visually pleasant effect."));
|
||||
parlst.addParam(RichAbsPerc("Displacement", m.cm.bbox.Diag()/100.0f,0.0f,m.cm.bbox.Diag(), "Max displacement", "The vertex are displaced of a vector whose norm is bounded by this value"));
|
||||
parlst.addParam(RichInt("RandomSeed", 0, "Random Seed", "The seed used to generate random values. If seed is zero no random seed is used"));
|
||||
break;
|
||||
default :
|
||||
assert(0);
|
||||
@ -181,7 +182,7 @@ std::map<std::string, QVariant> FilterSamplePlugin::applyFilter(const QAction *
|
||||
{
|
||||
switch(ID(action)) {
|
||||
case FP_MOVE_VERTEX :
|
||||
vertexDisplacement(md, cb, parameters.getBool("UpdateNormals"), parameters.getAbsPerc("Displacement"));
|
||||
vertexDisplacement(md, cb, parameters.getInt("RandomSeed"), parameters.getBool("UpdateNormals"), parameters.getAbsPerc("Displacement"));
|
||||
break;
|
||||
default :
|
||||
wrongActionCalled(action);
|
||||
@ -190,23 +191,25 @@ std::map<std::string, QVariant> FilterSamplePlugin::applyFilter(const QAction *
|
||||
}
|
||||
|
||||
bool FilterSamplePlugin::vertexDisplacement(
|
||||
MeshDocument &md,
|
||||
vcg::CallBackPos *cb,
|
||||
bool updateNormals,
|
||||
Scalarm max_displacement)
|
||||
MeshDocument &md,
|
||||
vcg::CallBackPos *cb,
|
||||
int randomSeed,
|
||||
bool updateNormals,
|
||||
Scalarm max_displacement)
|
||||
{
|
||||
CMeshO &m = md.mm()->cm;
|
||||
srand(time(NULL));
|
||||
if(randomSeed==0) srand(time(NULL));
|
||||
else srand(randomSeed);
|
||||
|
||||
for(unsigned int i = 0; i< m.vert.size(); i++){
|
||||
// Typical usage of the callback for showing a nice progress bar in the bottom.
|
||||
// First parameter is a 0..100 number indicating percentage of completion, the second is an info string.
|
||||
cb(100*i/m.vert.size(), "Randomly Displacing...");
|
||||
|
||||
Scalarm rndax = (Scalarm(2.0*rand())/RAND_MAX - 1.0 ) *max_displacement;
|
||||
Scalarm rnday = (Scalarm(2.0*rand())/RAND_MAX - 1.0 ) *max_displacement;
|
||||
Scalarm rndaz = (Scalarm(2.0*rand())/RAND_MAX - 1.0 ) *max_displacement;
|
||||
m.vert[i].P() += Point3m(rndax,rnday,rndaz);
|
||||
|
||||
Scalarm rndax = (Scalarm(2.0*rand())/float(RAND_MAX) - 1.0 ) *max_displacement;
|
||||
Scalarm rnday = (Scalarm(2.0*rand())/float(RAND_MAX) - 1.0 ) *max_displacement;
|
||||
Scalarm rndaz = (Scalarm(2.0*rand())/float(RAND_MAX) - 1.0 ) *max_displacement;
|
||||
m.vert[i].P() += Point3m(rndax,rnday,rndaz);
|
||||
}
|
||||
|
||||
// Log function dump textual info in the lower part of the MeshLab screen.
|
||||
|
||||
@ -74,6 +74,7 @@ private:
|
||||
bool vertexDisplacement(
|
||||
MeshDocument &md,
|
||||
vcg::CallBackPos *cb,
|
||||
int randomSeed,
|
||||
bool updateNormals,
|
||||
Scalarm max_displacement);
|
||||
};
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user