Merge pull request #1407 from davidboening/devel

Added approximated geodesic compuation to filter_geodesic
This commit is contained in:
Alessandro Muntoni 2023-07-31 11:29:09 +02:00 committed by GitHub
commit e20fc348aa
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 87 additions and 20 deletions

View File

@ -152,7 +152,7 @@ if(NOT DEFINED MESHLAB_PLUGINS) # it may be already defined in parent directory
meshlabplugins/filter_developability
meshlabplugins/filter_dirt
meshlabplugins/filter_fractal
meshlabplugins/filter_func
meshlabplugins/filter_func
meshlabplugins/filter_img_patch_param
meshlabplugins/filter_icp
meshlabplugins/filter_io_nxs

View File

@ -44,7 +44,8 @@ FilterGeodesic::FilterGeodesic()
typeList = {
FP_QUALITY_BORDER_GEODESIC,
FP_QUALITY_POINT_GEODESIC,
FP_QUALITY_SELECTED_GEODESIC
FP_QUALITY_SELECTED_GEODESIC,
FP_QUALITY_SELECTED_GEODESIC_HEAT
};
for(ActionIDType tt : types())
@ -67,6 +68,8 @@ QString FilterGeodesic::filterName(ActionIDType filter) const
return QString("Colorize by geodesic distance from a given point");
case FP_QUALITY_SELECTED_GEODESIC:
return QString("Colorize by geodesic distance from the selected points");
case FP_QUALITY_SELECTED_GEODESIC_HEAT:
return QString("Colorize by approximated geodesic distance from the selected points");
default: assert(0); return QString();
}
}
@ -79,6 +82,8 @@ QString FilterGeodesic::pythonFilterName(ActionIDType f) const
return QString("compute_scalar_by_geodesic_distance_from_given_point_per_vertex");
case FP_QUALITY_SELECTED_GEODESIC:
return QString("compute_scalar_by_geodesic_distance_from_selection_per_vertex");
case FP_QUALITY_SELECTED_GEODESIC_HEAT:
return QString("compute_scalar_by_heat_geodesic_distance_from_selection_per_vertex");
default: assert(0); return QString();
}
}
@ -87,9 +92,10 @@ QString FilterGeodesic::filterInfo(ActionIDType filterId) const
{
switch(filterId)
{
case FP_QUALITY_BORDER_GEODESIC : return tr("Store in the quality field the geodesic distance from borders and color the mesh accordingly.");
case FP_QUALITY_POINT_GEODESIC : return tr("Store in the quality field the geodesic distance from a given point on the mesh surface and color the mesh accordingly.");
case FP_QUALITY_SELECTED_GEODESIC : return tr("Store in the quality field the geodesic distance from the selected points on the mesh surface and color the mesh accordingly.");
case FP_QUALITY_BORDER_GEODESIC : return tr("Store in the quality field the geodesic distance from borders and color the mesh accordingly.");
case FP_QUALITY_POINT_GEODESIC : return tr("Store in the quality field the geodesic distance from a given point on the mesh surface and color the mesh accordingly.");
case FP_QUALITY_SELECTED_GEODESIC : return tr("Store in the quality field the geodesic distance from the selected points on the mesh surface and color the mesh accordingly.");
case FP_QUALITY_SELECTED_GEODESIC_HEAT : return tr("Store in the quality field the approximated geodesic distance, computed via heat method (Crane et al.), from the selected points on the mesh surface and color the mesh accordingly. As this implementation does not use intrinsic triangulation it is very sensitive to trinagulation. First run takes longer as factorization has to be build. ");
default : assert(0);
}
return QString("error!");
@ -99,9 +105,10 @@ FilterGeodesic::FilterClass FilterGeodesic::getClass(const QAction *a) const
{
switch(ID(a))
{
case FP_QUALITY_BORDER_GEODESIC :
case FP_QUALITY_SELECTED_GEODESIC :
case FP_QUALITY_POINT_GEODESIC : return FilterGeodesic::FilterClass(FilterPlugin::VertexColoring + FilterPlugin::Quality);
case FP_QUALITY_BORDER_GEODESIC :
case FP_QUALITY_SELECTED_GEODESIC :
case FP_QUALITY_POINT_GEODESIC :
case FP_QUALITY_SELECTED_GEODESIC_HEAT : return FilterGeodesic::FilterClass(FilterPlugin::VertexColoring + FilterPlugin::Quality);
default : assert(0);
}
return FilterPlugin::Generic;
@ -111,15 +118,16 @@ int FilterGeodesic::getRequirements(const QAction *action)
{
switch(ID(action))
{
case FP_QUALITY_BORDER_GEODESIC :
case FP_QUALITY_SELECTED_GEODESIC:
case FP_QUALITY_POINT_GEODESIC : return MeshModel::MM_VERTFACETOPO;
case FP_QUALITY_BORDER_GEODESIC :
case FP_QUALITY_SELECTED_GEODESIC :
case FP_QUALITY_POINT_GEODESIC : return MeshModel::MM_VERTFACETOPO;
case FP_QUALITY_SELECTED_GEODESIC_HEAT : return MeshModel::MM_VERTFACETOPO + MeshModel::MM_FACEFACETOPO;
default: assert(0);
}
return 0;
}
std::map<std::string, QVariant> FilterGeodesic::applyFilter(const QAction *filter, const RichParameterList & par, MeshDocument &md, unsigned int& /*postConditionMask*/, vcg::CallBackPos * /*cb*/)
std::map<std::string, QVariant> FilterGeodesic::applyFilter(const QAction *filter, const RichParameterList & par, MeshDocument &md, unsigned int& /*postConditionMask*/, vcg::CallBackPos *cb)
{
MeshModel &m=*(md.mm());
CMeshO::VertexIterator vi;
@ -236,7 +244,60 @@ std::map<std::string, QVariant> FilterGeodesic::applyFilter(const QAction *filte
else
log("Warning: no vertices are selected! aborting geodesic computation.");
}
break;
break;
case FP_QUALITY_SELECTED_GEODESIC_HEAT:
{
m.updateDataMask(MeshModel::MM_FACEFACETOPO);
m.updateDataMask(MeshModel::MM_VERTFACETOPO);
m.updateDataMask(MeshModel::MM_FACEQUALITY);
m.updateDataMask(MeshModel::MM_FACENORMAL);
m.updateDataMask(MeshModel::MM_VERTQUALITY);
m.updateDataMask(MeshModel::MM_VERTCOLOR);
std::vector<CMeshO::VertexPointer> seedVec;
ForEachVertex(m.cm, [&seedVec] (CMeshO::VertexType & v) {
if (v.IsS()) seedVec.push_back(&v);
});
float param_m = par.getFloat("m");
if (seedVec.size() > 0){
// cache factorizations to reduce runtime on successive computations
std::pair<float, tri::GeodesicHeat<CMeshO>::GeodesicHeatCache> cache;
if (!vcg::tri::HasPerMeshAttribute(m.cm, "GeodesicHeatCache")){
cb(20, "Building Cache: Computing Factorizations...");
cache = std::make_pair(param_m, tri::GeodesicHeat<CMeshO>::BuildCache(m.cm, param_m));
// save cache for next compute
auto GeodesicHeatCacheHandle = tri::Allocator<CMeshO>::GetPerMeshAttribute<std::pair<float, tri::GeodesicHeat<CMeshO>::GeodesicHeatCache>>(m.cm, std::string("GeodesicHeatCache"));
GeodesicHeatCacheHandle() = cache;
}
else {
cb(10, "Recovering Cache...");
// recover cache
auto GeodesicHeatCacheHandle = vcg::tri::Allocator<CMeshO>::GetPerMeshAttribute<std::pair<float, tri::GeodesicHeat<CMeshO>::GeodesicHeatCache>>(m.cm, std::string("GeodesicHeatCache"));
// if m has changed rebuild everything
if (std::get<0>(GeodesicHeatCacheHandle()) != param_m){
cb(20, "Parameter Changed: Rebuilding Factorizations...");
GeodesicHeatCacheHandle() = std::make_pair(param_m, tri::GeodesicHeat<CMeshO>::BuildCache(m.cm, param_m));
}
cache = GeodesicHeatCacheHandle();
}
cb(80, "Computing Geodesic Distance...");
if (tri::GeodesicHeat<CMeshO>::ComputeFromCache(m.cm, seedVec, std::get<1>(cache))){
tri::UpdateColor<CMeshO>::PerVertexQualityRamp(m.cm);
}
else{
log("Warning: heat method has failed. The mesh is most likely badly conditioned (e.g. angles ~ 0deg) or has disconnected components");
// delete cache as its most likely useless after failure
auto GeodesicHeatCacheHandle = vcg::tri::Allocator<CMeshO>::GetPerMeshAttribute<std::pair<float, tri::GeodesicHeat<CMeshO>::GeodesicHeatCache>>(m.cm, std::string("GeodesicHeatCache"));
tri::Allocator<CMeshO>::DeletePerMeshAttribute<std::pair<float, tri::GeodesicHeat<CMeshO>::GeodesicHeatCache>>(m.cm, GeodesicHeatCacheHandle);
}
}
else
log("Warning: no vertices are selected! aborting geodesic computation.");
}
break;
default:
wrongActionCalled(filter);
break;
@ -255,7 +316,10 @@ RichParameterList FilterGeodesic::initParameterList(const QAction *action, const
break;
case FP_QUALITY_SELECTED_GEODESIC :
parlst.addParam(RichPercentage("maxDistance",m.cm.bbox.Diag(),0,m.cm.bbox.Diag()*2,"Max Distance","If not zero it indicates a cut off value to be used during geodesic distance computation."));
break;
break;
case FP_QUALITY_SELECTED_GEODESIC_HEAT :
parlst.addParam(RichFloat("m", 1.0, tr("Euler Step"), tr("Multiplier used in backward Euler timestep. Changing this value will reset the cache.")));
break;
default: break; // do not add any parameter for the other filters
}
return parlst;
@ -265,10 +329,11 @@ int FilterGeodesic::postCondition(const QAction * filter) const
{
switch (ID(filter))
{
case FP_QUALITY_BORDER_GEODESIC :
case FP_QUALITY_SELECTED_GEODESIC :
case FP_QUALITY_POINT_GEODESIC : return MeshModel::MM_VERTCOLOR + MeshModel::MM_VERTQUALITY;
default : return MeshModel::MM_ALL;
case FP_QUALITY_BORDER_GEODESIC :
case FP_QUALITY_SELECTED_GEODESIC :
case FP_QUALITY_POINT_GEODESIC : return MeshModel::MM_VERTCOLOR + MeshModel::MM_VERTQUALITY;
case FP_QUALITY_SELECTED_GEODESIC_HEAT : return MeshModel::MM_VERTCOLOR + MeshModel::MM_VERTQUALITY + MeshModel::MM_FACEQUALITY;
default : return MeshModel::MM_ALL;
}
}
MESHLAB_PLUGIN_NAME_EXPORTER(FilterGeodesic)

View File

@ -26,6 +26,7 @@
#include <QObject>
#include <common/plugins/interfaces/filter_plugin.h>
#include <vcg/complex/algorithms/geodesic.h>
#include <vcg/complex/algorithms/geodesic_heat.h>
class FilterGeodesic : public QObject, public FilterPlugin
@ -42,7 +43,8 @@ class FilterGeodesic : public QObject, public FilterPlugin
enum {
FP_QUALITY_BORDER_GEODESIC,
FP_QUALITY_POINT_GEODESIC,
FP_QUALITY_SELECTED_GEODESIC
FP_QUALITY_SELECTED_GEODESIC,
FP_QUALITY_SELECTED_GEODESIC_HEAT
} ;

@ -1 +1 @@
Subproject commit 87edc09b9077b9e9b5fc474544ea76b17b665399
Subproject commit 80b1d21bdab5031c2ffdba971ff8b0b7c7a76911