From 5647d436330e3aca1cbe894581553cdd39e4cfc1 Mon Sep 17 00:00:00 2001 From: alemuntoni Date: Wed, 22 Sep 2021 11:30:19 +0200 Subject: [PATCH 01/10] remove compact vert and face filters --- .../filter_clean/cleanfilter.cpp | 24 +------------------ src/meshlabplugins/filter_clean/cleanfilter.h | 4 +--- .../filter_unsharp/filter_unsharp.cpp | 24 +++++++++---------- 3 files changed, 13 insertions(+), 39 deletions(-) diff --git a/src/meshlabplugins/filter_clean/cleanfilter.cpp b/src/meshlabplugins/filter_clean/cleanfilter.cpp index bacfa2142..ef87699ed 100644 --- a/src/meshlabplugins/filter_clean/cleanfilter.cpp +++ b/src/meshlabplugins/filter_clean/cleanfilter.cpp @@ -54,9 +54,7 @@ CleanFilter::CleanFilter() FP_REMOVE_DUPLICATED_VERTEX, FP_REMOVE_FACE_ZERO_AREA, FP_MERGE_CLOSE_VERTEX, - FP_MERGE_WEDGE_TEX, - FP_COMPACT_FACE, - FP_COMPACT_VERT + FP_MERGE_WEDGE_TEX }; for(ActionIDType tt : types()) @@ -96,8 +94,6 @@ QString CleanFilter::filterName(ActionIDType filter) const case FP_REMOVE_UNREFERENCED_VERTEX: return QString("Remove Unreferenced Vertices"); case FP_REMOVE_DUPLICATED_VERTEX: return QString("Remove Duplicate Vertices"); case FP_REMOVE_FACE_ZERO_AREA: return QString("Remove Zero Area Faces"); - case FP_COMPACT_VERT: return QString("Compact vertices"); - case FP_COMPACT_FACE: return QString("Compact faces"); default: assert(0); } return QString("error!"); @@ -133,8 +129,6 @@ QString CleanFilter::filterInfo(ActionIDType filterId) const case FP_REMOVE_UNREFERENCED_VERTEX: return QString("Check for every vertex on the mesh: if it is NOT referenced by a face, removes it"); case FP_REMOVE_DUPLICATED_VERTEX: return QString("Check for every vertex on the mesh: if there are two vertices with same coordinates they are merged into a single one."); case FP_REMOVE_FACE_ZERO_AREA: return QString("Remove null faces (the one with area equal to zero)"); - case FP_COMPACT_VERT: return QString("Compact all the vertices that have been deleted and put them to the end of the vector"); - case FP_COMPACT_FACE: return QString("Compact all the faces that have been deleted and put them to the end of the vector"); default: assert(0); } return QString("error!"); @@ -159,8 +153,6 @@ CleanFilter::FilterClass CleanFilter::getClass(const QAction *a) const case FP_REMOVE_FACE_ZERO_AREA: case FP_REMOVE_UNREFERENCED_VERTEX: case FP_REMOVE_DUPLICATED_VERTEX: - case FP_COMPACT_VERT: - case FP_COMPACT_FACE: return FilterPlugin::Cleaning; case FP_BALL_PIVOTING: return FilterPlugin::Remeshing; case FP_MERGE_WEDGE_TEX: return FilterPlugin::FilterClass(FilterPlugin::Cleaning + FilterPlugin::Texture); default : assert(0); @@ -172,8 +164,6 @@ int CleanFilter::getRequirements(const QAction *action) { switch(ID(action)) { - case FP_COMPACT_FACE: - case FP_COMPACT_VERT: case FP_REMOVE_WRT_Q: case FP_BALL_PIVOTING: return MeshModel::MM_VERTMARK; case FP_REMOVE_ISOLATED_COMPLEXITY: @@ -217,8 +207,6 @@ int CleanFilter::postCondition(const QAction* action) const case FP_REMOVE_DUPLICATED_VERTEX: case FP_REMOVE_FACE_ZERO_AREA: case FP_REMOVE_NON_MANIF_EDGE_SPLIT: return MeshModel::MM_GEOMETRY_AND_TOPOLOGY_CHANGE; - case FP_COMPACT_VERT: - case FP_COMPACT_FACE: return MeshModel::MM_NONE; // only internal vector storage should change, nothing more } return MeshModel::MM_ALL; } @@ -468,16 +456,6 @@ std::map CleanFilter::applyFilter(const QAction *filter, m.clearDataMask(MeshModel::MM_VERTFACETOPO); } break; - case FP_COMPACT_FACE : - { - vcg::tri::Allocator::CompactFaceVector(m.cm); - } break; - - case FP_COMPACT_VERT : - { - vcg::tri::Allocator::CompactVertexVector(m.cm); - } break; - default : wrongActionCalled(filter); // unknown filter; } diff --git a/src/meshlabplugins/filter_clean/cleanfilter.h b/src/meshlabplugins/filter_clean/cleanfilter.h index 58d522b36..e6374e0a9 100644 --- a/src/meshlabplugins/filter_clean/cleanfilter.h +++ b/src/meshlabplugins/filter_clean/cleanfilter.h @@ -55,9 +55,7 @@ class CleanFilter : public QObject, public FilterPlugin FP_REMOVE_DUPLICATED_VERTEX, FP_REMOVE_FACE_ZERO_AREA, FP_MERGE_CLOSE_VERTEX, - FP_MERGE_WEDGE_TEX, - FP_COMPACT_VERT, - FP_COMPACT_FACE + FP_MERGE_WEDGE_TEX } ; CleanFilter(); diff --git a/src/meshlabplugins/filter_unsharp/filter_unsharp.cpp b/src/meshlabplugins/filter_unsharp/filter_unsharp.cpp index f874dac41..0fc38151f 100644 --- a/src/meshlabplugins/filter_unsharp/filter_unsharp.cpp +++ b/src/meshlabplugins/filter_unsharp/filter_unsharp.cpp @@ -476,9 +476,8 @@ std::map FilterUnsharp::applyFilter( float alpha = 1; switch (stepNum) { - case 0: // ***** Storing Vertex Data ***** - { - if(tri::HasPerVertexAttribute(m.cm,AttribName)) { + case 0: { // ***** Storing Vertex Data ***** + if(tri::HasPerVertexAttribute(m.cm,AttribName)) { vcg::tri::Allocator::DeletePerVertexAttribute(m.cm,AttribName); } CMeshO::PerVertexAttributeHandle h = tri::Allocator::AddPerVertexAttribute (m.cm,AttribName); @@ -490,27 +489,26 @@ std::map FilterUnsharp::applyFilter( log( "Stored Position %d vertices", m.cm.vn); break; } - case 1: // ***** Recovering and Projection Vertex Data ***** - { - if(!tri::HasPerVertexAttribute(m.cm,AttribName)) { + case 1: { // ***** Recovering and Projection Vertex Data ***** + if(!tri::HasPerVertexAttribute(m.cm,AttribName)) { throw MLException("Failed to retrieve the stored vertex position. First Store than recover."); } CMeshO::PerVertexAttributeHandle h = tri::Allocator::GetPerVertexAttribute (m.cm,AttribName); CMeshO::VertexIterator vi; - for(vi= m.cm.vert.begin();vi!= m.cm.vert.end();++vi) - { - Point3m d = h[vi] - viewpoint; d.Normalize(); - float s = d * ( (*vi).cP() - h[vi] ); + for(vi= m.cm.vert.begin();vi!= m.cm.vert.end();++vi) { + Point3m d = h[vi] - viewpoint; + d.Normalize(); + Scalarm s = d * ( (*vi).cP() - h[vi] ); (*vi).P() = h[vi] + d * (s*alpha); } m.updateBoxAndNormals(); - log( "Projected smoothed Position %d vertices", m.cm.vn); - } + log("Projected smoothed Position %d vertices", m.cm.vn); break; } - } + } break; + } case FP_SD_LAPLACIAN_SMOOTH: { tri::UpdateFlags::FaceBorderFromNone(m.cm); From d4a50703b78bcf284a625ef71597269093508f36 Mon Sep 17 00:00:00 2001 From: alemuntoni Date: Wed, 22 Sep 2021 14:47:45 +0200 Subject: [PATCH 02/10] unique remove t-vertices filter --- .../filter_clean/cleanfilter.cpp | 792 ++++++++++-------- src/meshlabplugins/filter_clean/cleanfilter.h | 111 ++- 2 files changed, 501 insertions(+), 402 deletions(-) diff --git a/src/meshlabplugins/filter_clean/cleanfilter.cpp b/src/meshlabplugins/filter_clean/cleanfilter.cpp index ef87699ed..cf9930a9b 100644 --- a/src/meshlabplugins/filter_clean/cleanfilter.cpp +++ b/src/meshlabplugins/filter_clean/cleanfilter.cpp @@ -1,39 +1,39 @@ -/**************************************************************************** -* MeshLab o o * -* An extendible mesh processor o o * -* _ O _ * -* Copyright(C) 2005, 2006 \/)\/ * -* 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. * -* * -****************************************************************************/ +/***************************************************************************** + * MeshLab o o * + * An extendible mesh processor 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 "cleanfilter.h" +#include #include +#include #include #include -#include #include -#include using namespace std; using namespace vcg; -int SnapVertexBorder(CMeshO &m, Scalarm threshold,vcg::CallBackPos * cb); +int SnapVertexBorder(CMeshO& m, Scalarm threshold, vcg::CallBackPos* cb); CleanFilter::CleanFilter() { @@ -42,8 +42,7 @@ CleanFilter::CleanFilter() FP_REMOVE_WRT_Q, FP_REMOVE_ISOLATED_COMPLEXITY, FP_REMOVE_ISOLATED_DIAMETER, - FP_REMOVE_TVERTEX_FLIP, - FP_REMOVE_TVERTEX_COLLAPSE, + FP_REMOVE_TVERTEX, FP_SNAP_MISMATCHED_BORDER, FP_REMOVE_DUPLICATE_FACE, FP_REMOVE_FOLD_FACE, @@ -54,18 +53,18 @@ CleanFilter::CleanFilter() FP_REMOVE_DUPLICATED_VERTEX, FP_REMOVE_FACE_ZERO_AREA, FP_MERGE_CLOSE_VERTEX, - FP_MERGE_WEDGE_TEX - }; + FP_MERGE_WEDGE_TEX}; - for(ActionIDType tt : types()) + for (ActionIDType tt : types()) actionList.push_back(new QAction(filterName(tt), this)); - + QCoreApplication* app = QCoreApplication::instance(); if (app != nullptr) getFilterAction(FP_SNAP_MISMATCHED_BORDER)->setShortcut(QKeySequence("ALT+`")); } -CleanFilter::~CleanFilter() { +CleanFilter::~CleanFilter() +{ } QString CleanFilter::pluginName() const @@ -75,25 +74,24 @@ QString CleanFilter::pluginName() const QString CleanFilter::filterName(ActionIDType filter) const { - switch(filter) - { - case FP_BALL_PIVOTING: return QString("Surface Reconstruction: Ball Pivoting"); - case FP_REMOVE_WRT_Q: return QString("Remove Vertices wrt Quality"); - case FP_REMOVE_ISOLATED_DIAMETER: return QString("Remove Isolated pieces (wrt Diameter)"); - case FP_REMOVE_ISOLATED_COMPLEXITY: return QString("Remove Isolated pieces (wrt Face Num.)"); - case FP_REMOVE_TVERTEX_FLIP: return QString("Remove T-Vertices by Edge Flip"); - case FP_REMOVE_TVERTEX_COLLAPSE: return QString("Remove T-Vertices by Edge Collapse"); - case FP_SNAP_MISMATCHED_BORDER: return QString("Snap Mismatched Borders"); - case FP_MERGE_CLOSE_VERTEX: return QString("Merge Close Vertices"); - case FP_MERGE_WEDGE_TEX: return QString("Merge Wedge Texture Coord"); - case FP_REMOVE_DUPLICATE_FACE: return QString("Remove Duplicate Faces"); - case FP_REMOVE_FOLD_FACE: return QString("Remove Isolated Folded Faces by Edge Flip"); - case FP_REMOVE_NON_MANIF_EDGE: return QString("Repair non Manifold Edges by removing faces"); - case FP_REMOVE_NON_MANIF_EDGE_SPLIT: return QString("Repair non Manifold Edges by splitting vertices"); - case FP_REMOVE_NON_MANIF_VERT: return QString("Repair non Manifold Vertices by splitting"); - case FP_REMOVE_UNREFERENCED_VERTEX: return QString("Remove Unreferenced Vertices"); - case FP_REMOVE_DUPLICATED_VERTEX: return QString("Remove Duplicate Vertices"); - case FP_REMOVE_FACE_ZERO_AREA: return QString("Remove Zero Area Faces"); + switch (filter) { + case FP_BALL_PIVOTING: return QString("Surface Reconstruction: Ball Pivoting"); + case FP_REMOVE_WRT_Q: return QString("Remove Vertices wrt Quality"); + case FP_REMOVE_ISOLATED_DIAMETER: return QString("Remove Isolated pieces (wrt Diameter)"); + case FP_REMOVE_ISOLATED_COMPLEXITY: return QString("Remove Isolated pieces (wrt Face Num.)"); + case FP_REMOVE_TVERTEX: return QString("Remove T-Vertices"); + case FP_SNAP_MISMATCHED_BORDER: return QString("Snap Mismatched Borders"); + case FP_MERGE_CLOSE_VERTEX: return QString("Merge Close Vertices"); + case FP_MERGE_WEDGE_TEX: return QString("Merge Wedge Texture Coord"); + case FP_REMOVE_DUPLICATE_FACE: return QString("Remove Duplicate Faces"); + case FP_REMOVE_FOLD_FACE: return QString("Remove Isolated Folded Faces by Edge Flip"); + case FP_REMOVE_NON_MANIF_EDGE: return QString("Repair non Manifold Edges by removing faces"); + case FP_REMOVE_NON_MANIF_EDGE_SPLIT: + return QString("Repair non Manifold Edges by splitting vertices"); + case FP_REMOVE_NON_MANIF_VERT: return QString("Repair non Manifold Vertices by splitting"); + case FP_REMOVE_UNREFERENCED_VERTEX: return QString("Remove Unreferenced Vertices"); + case FP_REMOVE_DUPLICATED_VERTEX: return QString("Remove Duplicate Vertices"); + case FP_REMOVE_FACE_ZERO_AREA: return QString("Remove Zero Area Faces"); default: assert(0); } return QString("error!"); @@ -101,50 +99,93 @@ QString CleanFilter::filterName(ActionIDType filter) const QString CleanFilter::filterInfo(ActionIDType filterId) const { - switch(filterId) - { - case FP_BALL_PIVOTING : return QString("Given a point cloud with normals it reconstructs a surface using the Ball Pivoting Algorithm." - "Starting with a seed triangle, the BPA algorithm pivots a ball of the given radius around the already formed edges" - "until it touches another point, forming another triangle. The process continues until all reachable edges have been tried." - "This surface reconstruction algorithm uses the existing points without creating new ones. Works better with uniformly sampled point clouds. " - "If needed first perform a poisson disk subsampling of the point cloud.
" - "Bernardini F., Mittleman J., Rushmeier H., Silva C., Taubin G.
" - "The ball-pivoting algorithm for surface reconstruction.
" - "IEEE TVCG 1999"); - case FP_REMOVE_ISOLATED_COMPLEXITY: return QString("Delete isolated connected components composed by a limited number of triangles"); - case FP_REMOVE_ISOLATED_DIAMETER: return QString("Delete isolated connected components whose diameter is smaller than the specified constant"); - case FP_REMOVE_WRT_Q: return QString("Delete all the vertices with a quality lower smaller than the specified constant"); - case FP_REMOVE_TVERTEX_COLLAPSE : return QString("Delete t-vertices from the mesh by collapsing the shortest of the incident edges"); - case FP_REMOVE_TVERTEX_FLIP : return QString("Delete t-vertices by flipping the opposite edge on the degenerate face if the triangulation quality improves"); - case FP_SNAP_MISMATCHED_BORDER : return QString("Try to snap together adjacent borders that are slightly mismatched.
" - "This situation can happen on badly triangulated adjacent patches defined by high order surfaces.
" - "For each border vertex the filter snap it onto the closest boundary edge only if it is closest of edge_length*threshold. When vertex is snapped the corresponding face is split and a new vertex is created."); - case FP_MERGE_CLOSE_VERTEX : return QString("Merge together all the vertices that are nearer than the specified threshold. Like a unify duplicated vertices but with some tolerance."); - case FP_MERGE_WEDGE_TEX : return QString("Merge together per-wedge texture coords that are very close. Used to correct apparent texture seams that can arise from numerical approximations when saving in ascii formats."); - case FP_REMOVE_DUPLICATE_FACE : return QString("Delete all the duplicate faces. Two faces are considered equal if they are composed by the same set of vertices, regardless of the order of the vertices."); - case FP_REMOVE_FOLD_FACE : return QString("Delete all the single folded faces. A face is considered folded if its normal is opposite to all the adjacent faces. It is removed by flipping it against the face f adjacent along the edge e such that the vertex opposite to e fall inside f"); - case FP_REMOVE_NON_MANIF_EDGE : return QString("For each non Manifold edge it iteratively deletes the smallest area face until it becomes 2-Manifold."); - case FP_REMOVE_NON_MANIF_EDGE_SPLIT:return QString("Remove all non manifold edges splitting vertices. Each non manifold edges chain will become a border"); - case FP_REMOVE_NON_MANIF_VERT : return QString("Split non Manifold vertices until it becomes 2-Manifold."); - case FP_REMOVE_UNREFERENCED_VERTEX: return QString("Check for every vertex on the mesh: if it is NOT referenced by a face, removes it"); - case FP_REMOVE_DUPLICATED_VERTEX: return QString("Check for every vertex on the mesh: if there are two vertices with same coordinates they are merged into a single one."); - case FP_REMOVE_FACE_ZERO_AREA: return QString("Remove null faces (the one with area equal to zero)"); + switch (filterId) { + case FP_BALL_PIVOTING: + return QString( + "Given a point cloud with normals it reconstructs a surface using the Ball Pivoting " + "Algorithm." + "Starting with a seed triangle, the BPA algorithm pivots a ball of the given radius " + "around the already formed edges until it touches another point, forming another " + "triangle. The process continues until all reachable edges have been tried. This " + "surface reconstruction algorithm uses the existing points without creating new ones. " + "Works better with uniformly sampled point clouds. If needed first perform a poisson " + "disk subsampling of the point cloud.
" + "Bernardini F., Mittleman J., Rushmeier H., Silva C., Taubin G.
" + "The ball-pivoting algorithm for surface reconstruction.
" + "IEEE TVCG 1999"); + case FP_REMOVE_ISOLATED_COMPLEXITY: + return QString( + "Delete isolated connected components composed by a limited number of triangles"); + case FP_REMOVE_ISOLATED_DIAMETER: + return QString( + "Delete isolated connected components whose diameter is smaller than the specified " + "constant"); + case FP_REMOVE_WRT_Q: + return QString( + "Delete all the vertices with a quality lower smaller than the specified constant"); + case FP_REMOVE_TVERTEX: + return QString( + "Delete t-vertices from the mesh by edge collapse (collapsing the shortest of the " + "incident edges) or edge flip (flipping the opposite edge on the degenerate face if " + "the triangulation quality improves)."); + case FP_SNAP_MISMATCHED_BORDER: + return QString( + "Try to snap together adjacent borders that are slightly mismatched.
" + "This situation can happen on badly triangulated adjacent patches defined by high " + "order surfaces.
For each border vertex the filter snap it onto the closest " + "boundary edge only if it is closest of edge_length*threshold. When vertex is " + "snapped the corresponding face is split and a new vertex is created."); + case FP_MERGE_CLOSE_VERTEX: + return QString( + "Merge together all the vertices that are nearer than the specified threshold. Like a " + "unify duplicated vertices but with some tolerance."); + case FP_MERGE_WEDGE_TEX: + return QString( + "Merge together per-wedge texture coords that are very close. Used to correct apparent " + "texture seams that can arise from numerical approximations when saving in ascii " + "formats."); + case FP_REMOVE_DUPLICATE_FACE: + return QString( + "Delete all the duplicate faces. Two faces are considered equal if they are composed " + "by the same set of vertices, regardless of the order of the vertices."); + case FP_REMOVE_FOLD_FACE: + return QString( + "Delete all the single folded faces. A face is considered folded if its normal is " + "opposite to all the adjacent faces. It is removed by flipping it against the face f " + "adjacent along the edge e such that the vertex opposite to e fall inside f"); + case FP_REMOVE_NON_MANIF_EDGE: + return QString( + "For each non Manifold edge it iteratively deletes the smallest area face until it " + "becomes 2-Manifold."); + case FP_REMOVE_NON_MANIF_EDGE_SPLIT: + return QString( + "Remove all non manifold edges splitting vertices. Each non manifold edges chain will " + "become a border"); + case FP_REMOVE_NON_MANIF_VERT: + return QString("Split non Manifold vertices until it becomes 2-Manifold."); + case FP_REMOVE_UNREFERENCED_VERTEX: + return QString( + "Check for every vertex on the mesh: if it is NOT referenced by a face, removes it"); + case FP_REMOVE_DUPLICATED_VERTEX: + return QString( + "Check for every vertex on the mesh: if there are two vertices with same coordinates " + "they are merged into a single one."); + case FP_REMOVE_FACE_ZERO_AREA: + return QString("Remove null faces (the one with area equal to zero)"); default: assert(0); } return QString("error!"); } -CleanFilter::FilterClass CleanFilter::getClass(const QAction *a) const +CleanFilter::FilterClass CleanFilter::getClass(const QAction* a) const { - switch(ID(a)) - { - case FP_REMOVE_WRT_Q : - case FP_REMOVE_ISOLATED_DIAMETER : - case FP_REMOVE_ISOLATED_COMPLEXITY : - case FP_REMOVE_TVERTEX_COLLAPSE : - case FP_REMOVE_TVERTEX_FLIP : - case FP_REMOVE_FOLD_FACE : - case FP_MERGE_CLOSE_VERTEX : + switch (ID(a)) { + case FP_REMOVE_WRT_Q: + case FP_REMOVE_ISOLATED_DIAMETER: + case FP_REMOVE_ISOLATED_COMPLEXITY: + case FP_REMOVE_TVERTEX: + case FP_REMOVE_FOLD_FACE: + case FP_MERGE_CLOSE_VERTEX: case FP_REMOVE_DUPLICATE_FACE: case FP_SNAP_MISMATCHED_BORDER: case FP_REMOVE_NON_MANIF_EDGE: @@ -153,34 +194,34 @@ CleanFilter::FilterClass CleanFilter::getClass(const QAction *a) const case FP_REMOVE_FACE_ZERO_AREA: case FP_REMOVE_UNREFERENCED_VERTEX: case FP_REMOVE_DUPLICATED_VERTEX: - case FP_BALL_PIVOTING: return FilterPlugin::Remeshing; - case FP_MERGE_WEDGE_TEX: return FilterPlugin::FilterClass(FilterPlugin::Cleaning + FilterPlugin::Texture); - default : assert(0); + case FP_BALL_PIVOTING: return FilterPlugin::Remeshing; + case FP_MERGE_WEDGE_TEX: + return FilterPlugin::FilterClass(FilterPlugin::Cleaning + FilterPlugin::Texture); + default: assert(0); } return FilterPlugin::Generic; } -int CleanFilter::getRequirements(const QAction *action) +int CleanFilter::getRequirements(const QAction* action) { - switch(ID(action)) - { + switch (ID(action)) { case FP_REMOVE_WRT_Q: - case FP_BALL_PIVOTING: return MeshModel::MM_VERTMARK; + case FP_BALL_PIVOTING: return MeshModel::MM_VERTMARK; case FP_REMOVE_ISOLATED_COMPLEXITY: - case FP_REMOVE_ISOLATED_DIAMETER: return MeshModel::MM_FACEFACETOPO | MeshModel::MM_FACEMARK; - case FP_REMOVE_TVERTEX_COLLAPSE: return MeshModel::MM_VERTMARK; - case FP_REMOVE_TVERTEX_FLIP: return MeshModel::MM_FACEFACETOPO | MeshModel::MM_VERTMARK; - case FP_REMOVE_NON_MANIF_EDGE: return MeshModel::MM_FACEFACETOPO | MeshModel::MM_VERTMARK; - case FP_REMOVE_NON_MANIF_EDGE_SPLIT: return MeshModel::MM_FACEFACETOPO | MeshModel::MM_VERTMARK; - case FP_REMOVE_NON_MANIF_VERT: return MeshModel::MM_FACEFACETOPO | MeshModel::MM_VERTMARK; - case FP_SNAP_MISMATCHED_BORDER: return MeshModel::MM_FACEFACETOPO | MeshModel::MM_VERTMARK| MeshModel::MM_FACEMARK; - case FP_REMOVE_FOLD_FACE: return MeshModel::MM_FACEFACETOPO | MeshModel::MM_VERTMARK; + case FP_REMOVE_ISOLATED_DIAMETER: return MeshModel::MM_FACEFACETOPO | MeshModel::MM_FACEMARK; + case FP_REMOVE_TVERTEX: return MeshModel::MM_FACEFACETOPO | MeshModel::MM_VERTMARK; + case FP_REMOVE_NON_MANIF_EDGE: return MeshModel::MM_FACEFACETOPO | MeshModel::MM_VERTMARK; + case FP_REMOVE_NON_MANIF_EDGE_SPLIT: return MeshModel::MM_FACEFACETOPO | MeshModel::MM_VERTMARK; + case FP_REMOVE_NON_MANIF_VERT: return MeshModel::MM_FACEFACETOPO | MeshModel::MM_VERTMARK; + case FP_SNAP_MISMATCHED_BORDER: + return MeshModel::MM_FACEFACETOPO | MeshModel::MM_VERTMARK | MeshModel::MM_FACEMARK; + case FP_REMOVE_FOLD_FACE: return MeshModel::MM_FACEFACETOPO | MeshModel::MM_VERTMARK; case FP_MERGE_CLOSE_VERTEX: - case FP_REMOVE_DUPLICATE_FACE: return MeshModel::MM_NONE; - case FP_MERGE_WEDGE_TEX: return MeshModel::MM_VERTFACETOPO | MeshModel::MM_WEDGTEXCOORD; - case FP_REMOVE_UNREFERENCED_VERTEX: return MeshModel::MM_NONE; - case FP_REMOVE_DUPLICATED_VERTEX: return MeshModel::MM_NONE; - case FP_REMOVE_FACE_ZERO_AREA: return MeshModel::MM_NONE; + case FP_REMOVE_DUPLICATE_FACE: return MeshModel::MM_NONE; + case FP_MERGE_WEDGE_TEX: return MeshModel::MM_VERTFACETOPO | MeshModel::MM_WEDGTEXCOORD; + case FP_REMOVE_UNREFERENCED_VERTEX: return MeshModel::MM_NONE; + case FP_REMOVE_DUPLICATED_VERTEX: return MeshModel::MM_NONE; + case FP_REMOVE_FACE_ZERO_AREA: return MeshModel::MM_NONE; default: assert(0); } return 0; @@ -188,14 +229,12 @@ int CleanFilter::getRequirements(const QAction *action) int CleanFilter::postCondition(const QAction* action) const { - switch (ID(action)) - { + switch (ID(action)) { case FP_BALL_PIVOTING: case FP_REMOVE_WRT_Q: case FP_REMOVE_ISOLATED_DIAMETER: case FP_REMOVE_ISOLATED_COMPLEXITY: - case FP_REMOVE_TVERTEX_FLIP: - case FP_REMOVE_TVERTEX_COLLAPSE: + case FP_REMOVE_TVERTEX: case FP_SNAP_MISMATCHED_BORDER: case FP_MERGE_CLOSE_VERTEX: case FP_MERGE_WEDGE_TEX: @@ -206,264 +245,345 @@ int CleanFilter::postCondition(const QAction* action) const case FP_REMOVE_UNREFERENCED_VERTEX: case FP_REMOVE_DUPLICATED_VERTEX: case FP_REMOVE_FACE_ZERO_AREA: - case FP_REMOVE_NON_MANIF_EDGE_SPLIT: return MeshModel::MM_GEOMETRY_AND_TOPOLOGY_CHANGE; + case FP_REMOVE_NON_MANIF_EDGE_SPLIT: return MeshModel::MM_GEOMETRY_AND_TOPOLOGY_CHANGE; } return MeshModel::MM_ALL; } -RichParameterList CleanFilter::initParameterList(const QAction *action, const MeshDocument &md) +RichParameterList CleanFilter::initParameterList(const QAction* action, const MeshDocument& md) { - RichParameterList parlst; - pair qualityRange; - switch(ID(action)) - { - case FP_BALL_PIVOTING : - parlst.addParam(RichAbsPerc("BallRadius",0.0f,0.0f,md.mm()->cm.bbox.Diag(),"Pivoting Ball radius (0 autoguess)","The radius of the ball pivoting (rolling) over the set of points. Gaps that are larger than the ball radius will not be filled; similarly the small pits that are smaller than the ball radius will be filled.")); - parlst.addParam(RichFloat("Clustering",20.0f,"Clustering radius (% of ball radius)","To avoid the creation of too small triangles, if a vertex is found too close to a previous one, it is clustered/merged with it.")); - parlst.addParam(RichFloat("CreaseThr", 90.0f,"Angle Threshold (degrees)","If we encounter a crease angle that is too large we should stop the ball rolling")); - parlst.addParam(RichBool("DeleteFaces",false,"Delete initial set of faces","if true all the initial faces of the mesh are deleted and the whole surface is rebuilt from scratch. Otherwise the current faces are used as a starting point. Useful if you run the algorithm multiple times with an increasing ball radius.")); + RichParameterList parlst; + pair qualityRange; + switch (ID(action)) { + case FP_BALL_PIVOTING: + parlst.addParam(RichAbsPerc( + "BallRadius", + 0.0f, + 0.0f, + md.mm()->cm.bbox.Diag(), + "Pivoting Ball radius (0 autoguess)", + "The radius of the ball pivoting (rolling) over the set of points. Gaps that are " + "larger than the ball radius will not be filled; similarly the small pits that are " + "smaller than the ball radius will be filled.")); + parlst.addParam(RichFloat( + "Clustering", + 20.0f, + "Clustering radius (% of ball radius)", + "To avoid the creation of too small triangles, if a vertex is found too close to a " + "previous one, it is clustered/merged with it.")); + parlst.addParam(RichFloat( + "CreaseThr", + 90.0f, + "Angle Threshold (degrees)", + "If we encounter a crease angle that is too large we should stop the ball rolling")); + parlst.addParam(RichBool( + "DeleteFaces", + false, + "Delete initial set of faces", + "if true all the initial faces of the mesh are deleted and the whole surface is " + "rebuilt from scratch. Otherwise the current faces are used as a starting point. " + "Useful if you run the algorithm multiple times with an increasing ball radius.")); break; case FP_REMOVE_ISOLATED_DIAMETER: - parlst.addParam(RichAbsPerc("MinComponentDiag",md.mm()->cm.bbox.Diag()/10.0f,0.0f,md.mm()->cm.bbox.Diag(),"Enter max diameter of isolated pieces","Delete all the connected components (floating pieces) with a diameter smaller than the specified one")); - parlst.addParam(RichBool("removeUnref", true, "Remove unfreferenced vertices", "if true, the unreferenced vertices remaining after the face deletion are removed.")); + parlst.addParam(RichAbsPerc( + "MinComponentDiag", + md.mm()->cm.bbox.Diag() / 10.0f, + 0.0f, + md.mm()->cm.bbox.Diag(), + "Enter max diameter of isolated pieces", + "Delete all the connected components (floating pieces) with a diameter smaller than " + "the specified one")); + parlst.addParam(RichBool( + "removeUnref", + true, + "Remove unfreferenced vertices", + "if true, the unreferenced vertices remaining after the face deletion are removed.")); break; case FP_REMOVE_ISOLATED_COMPLEXITY: - parlst.addParam(RichInt("MinComponentSize",25,"Enter minimum conn. comp size:","Delete all the connected components (floating pieces) composed by a number of triangles smaller than the specified one")); - parlst.addParam(RichBool("removeUnref", true, "Remove unfreferenced vertices", "if true, the unreferenced vertices remaining after the face deletion are removed.")); + parlst.addParam(RichInt( + "MinComponentSize", + 25, + "Enter minimum conn. comp size:", + "Delete all the connected components (floating pieces) composed by a number of " + "triangles smaller than the specified one")); + parlst.addParam(RichBool( + "removeUnref", + true, + "Remove unfreferenced vertices", + "if true, the unreferenced vertices remaining after the face deletion are removed.")); break; case FP_REMOVE_WRT_Q: - qualityRange=tri::Stat::ComputePerVertexQualityMinMax(md.mm()->cm); - parlst.addParam(RichAbsPerc("MaxQualityThr",(float)1.0, qualityRange.first, qualityRange.second,"Delete all vertices with quality under:")); + qualityRange = tri::Stat::ComputePerVertexQualityMinMax(md.mm()->cm); + parlst.addParam(RichAbsPerc( + "MaxQualityThr", + (float) 1.0, + qualityRange.first, + qualityRange.second, + "Delete all vertices with quality under:")); break; - case FP_MERGE_CLOSE_VERTEX: - parlst.addParam(RichAbsPerc("Threshold",md.mm()->cm.bbox.Diag()/10000.0f,0.0f,md.mm()->cm.bbox.Diag()/100.0f,"Merging distance","All the vertices that closer than this threshold are merged together. Use very small values, default values is 1/10000 of bounding box diagonal. ")); + case FP_MERGE_CLOSE_VERTEX: + parlst.addParam(RichAbsPerc( + "Threshold", + md.mm()->cm.bbox.Diag() / 10000.0f, + 0.0f, + md.mm()->cm.bbox.Diag() / 100.0f, + "Merging distance", + "All the vertices that closer than this threshold are merged together. Use very small " + "values, default values is 1/10000 of bounding box diagonal. ")); break; - case FP_MERGE_WEDGE_TEX : - parlst.addParam(RichFloat("MergeThr",1.0f/10000.0f,"Merging Threshold","All the per-wedge texture coords that are on the same vertex and are distant less then the given threshold are merged together. It can be used to remove the fake texture seams that arise from error. Distance is in texture space (the default, 1e-4, corresponds to one texel on a 10kx10x texture) ")); + case FP_MERGE_WEDGE_TEX: + parlst.addParam(RichFloat( + "MergeThr", + 1.0f / 10000.0f, + "Merging Threshold", + "All the per-wedge texture coords that are on the same vertex and are distant less " + "then the given threshold are merged together. It can be used to remove the fake " + "texture seams that arise from error. Distance is in texture space (the default, 1e-4, " + "corresponds to one texel on a 10kx10x texture) ")); break; case FP_SNAP_MISMATCHED_BORDER: - parlst.addParam(RichFloat("EdgeDistRatio",1/100.0f,"Edge Distance Ratio", "Collapse edge when the edge / distance ratio is greater than this value. E.g. for default value 1000 two straight border edges are collapsed if the central vertex dist from the straight line composed by the two edges less than a 1/1000 of the sum of the edges length. Larger values enforce that only vertices very close to the line are removed.")); - parlst.addParam(RichBool("UnifyVertices",true,"UnifyVertices","if true the snap vertices are weld together.")); - break; - case FP_REMOVE_TVERTEX_COLLAPSE : - case FP_REMOVE_TVERTEX_FLIP : parlst.addParam(RichFloat( - "Threshold", 40, "Ratio", "Detects faces where the base/height ratio is lower than this value")); + "EdgeDistRatio", + 1 / 100.0f, + "Edge Distance Ratio", + "Collapse edge when the edge / distance ratio is greater than this value. E.g. for " + "default value 1000 two straight border edges are collapsed if the central vertex dist " + "from the straight line composed by the two edges less than a 1/1000 of the sum of the " + "edges length. Larger values enforce that only vertices very close to the line are " + "removed.")); parlst.addParam(RichBool( - "Repeat", true, "Iterate until convergence", "Iterates the algorithm until it reaches convergence")); + "UnifyVertices", + true, + "UnifyVertices", + "if true the snap vertices are weld together.")); break; - case FP_REMOVE_NON_MANIF_VERT : - parlst.addParam(RichFloat("VertDispRatio", 0, "Vertex Displacement Ratio", "This parameter denote the ratio ⍺ of displacement of a vertex. When a vertex v is split, it is moved towards the barycenter b of the FF connected faces sharing it of a (v-b)*⍺. When ⍺ is zero vertex is not displaced. When ⍺ is 0.5 the new vertex is half away toward the barycenter of the face. Reasonable values are in the [0 .. 0.1] range. ")); + case FP_REMOVE_TVERTEX: + parlst.addParam(RichEnum( + "method", + 0, + {"Edge Collapse", "Edge Flip"}, + "Method", + "Selects wether to remove t-vertices by edge collapse or edge flip.")); + parlst.addParam(RichFloat( + "Threshold", + 40, + "Ratio", + "Detects faces where the base/height ratio is lower than this value")); + parlst.addParam(RichBool( + "Repeat", + true, + "Iterate until convergence", + "Iterates the algorithm until it reaches convergence")); + break; + case FP_REMOVE_NON_MANIF_VERT: + parlst.addParam(RichFloat( + "VertDispRatio", + 0, + "Vertex Displacement Ratio", + "This parameter denote the ratio ⍺ of displacement of a vertex. When a vertex v " + "is split, it is moved towards the barycenter b of the FF connected faces " + "sharing it of a (v-b)*⍺. When ⍺ is zero vertex is not displaced. When ⍺ " + "is 0.5 the new vertex is half away toward the barycenter of the face. Reasonable " + "values are in the [0 .. 0.1] range.")); break; default: break; // do not add any parameter for the other filters } return parlst; } -std::map CleanFilter::applyFilter(const QAction *filter, const RichParameterList & par, MeshDocument &md, unsigned int& postConditionMask, vcg::CallBackPos * cb) +std::map CleanFilter::applyFilter( + const QAction* filter, + const RichParameterList& par, + MeshDocument& md, + unsigned int& postConditionMask, + vcg::CallBackPos* cb) { - MeshModel &m=*(md.mm()); - switch(ID(filter)) - { - case FP_BALL_PIVOTING: - { + MeshModel& m = *(md.mm()); + switch (ID(filter)) { + case FP_BALL_PIVOTING: { vcg::tri::Allocator::CompactEveryVector(m.cm); - Scalarm Radius = par.getAbsPerc("BallRadius"); - Scalarm Clustering = par.getFloat("Clustering") / 100.0f; - Scalarm CreaseThr = math::ToRad(par.getFloat("CreaseThr")); - bool DeleteFaces = par.getBool("DeleteFaces"); - if(DeleteFaces) - { - m.cm.fn=0; + Scalarm Radius = par.getAbsPerc("BallRadius"); + Scalarm Clustering = par.getFloat("Clustering") / 100.0f; + Scalarm CreaseThr = math::ToRad(par.getFloat("CreaseThr")); + bool DeleteFaces = par.getBool("DeleteFaces"); + if (DeleteFaces) { + m.cm.fn = 0; m.cm.face.resize(0); } m.updateDataMask(MeshModel::MM_VERTFACETOPO); - int startingFn=m.cm.fn; + int startingFn = m.cm.fn; tri::BallPivoting pivot(m.cm, Radius, Clustering, CreaseThr); // the main processing pivot.BuildMesh(cb); m.clearDataMask(MeshModel::MM_FACEFACETOPO); - log("Reconstructed surface. Added %i faces",m.cm.fn-startingFn); + log("Reconstructed surface. Added %i faces", m.cm.fn - startingFn); } break; - case FP_REMOVE_ISOLATED_DIAMETER: - { - Scalarm minCC= par.getAbsPerc("MinComponentDiag"); - std::pair delInfo= tri::Clean::RemoveSmallConnectedComponentsDiameter(m.cm,minCC); + case FP_REMOVE_ISOLATED_DIAMETER: { + Scalarm minCC = par.getAbsPerc("MinComponentDiag"); + std::pair delInfo = + tri::Clean::RemoveSmallConnectedComponentsDiameter(m.cm, minCC); log("Removed %i connected components out of %i", delInfo.second, delInfo.first); - if (par.getBool("removeUnref")) - { + if (par.getBool("removeUnref")) { int delvert = tri::Clean::RemoveUnreferencedVertex(m.cm); log("Removed %d unreferenced vertices", delvert); } m.updateBoxAndNormals(); - }break; - case FP_REMOVE_ISOLATED_COMPLEXITY: - { - int minCC= par.getInt("MinComponentSize"); - std::pair delInfo=tri::Clean::RemoveSmallConnectedComponentsSize(m.cm,minCC); + } break; + case FP_REMOVE_ISOLATED_COMPLEXITY: { + int minCC = par.getInt("MinComponentSize"); + std::pair delInfo = + tri::Clean::RemoveSmallConnectedComponentsSize(m.cm, minCC); log("Removed %i connected components out of %i", delInfo.second, delInfo.first); - if (par.getBool("removeUnref")) - { + if (par.getBool("removeUnref")) { int delvert = tri::Clean::RemoveUnreferencedVertex(m.cm); log("Removed %d unreferenced vertices", delvert); } m.updateBoxAndNormals(); } break; - case FP_REMOVE_WRT_Q: - { - int deletedFN=0; - int deletedVN=0; - Scalarm val=par.getAbsPerc("MaxQualityThr"); + case FP_REMOVE_WRT_Q: { + int deletedFN = 0; + int deletedVN = 0; + Scalarm val = par.getAbsPerc("MaxQualityThr"); CMeshO::VertexIterator vi; - for(vi=m.cm.vert.begin();vi!=m.cm.vert.end();++vi) - if(!(*vi).IsD() && (*vi).Q()::DeleteVertex(m.cm, *vi); deletedVN++; } CMeshO::FaceIterator fi; - for(fi=m.cm.face.begin();fi!=m.cm.face.end();++fi) if(!(*fi).IsD()) - if((*fi).V(0)->IsD() ||(*fi).V(1)->IsD() ||(*fi).V(2)->IsD() ) - { - tri::Allocator::DeleteFace(m.cm, *fi); - deletedFN++; - } + for (fi = m.cm.face.begin(); fi != m.cm.face.end(); ++fi) + if (!(*fi).IsD()) + if ((*fi).V(0)->IsD() || (*fi).V(1)->IsD() || (*fi).V(2)->IsD()) { + tri::Allocator::DeleteFace(m.cm, *fi); + deletedFN++; + } m.clearDataMask(MeshModel::MM_FACEFACETOPO); - log("Deleted %i vertices and %i faces with a quality lower than %f", deletedVN,deletedFN,val); + log("Deleted %i vertices and %i faces with a quality lower than %f", + deletedVN, + deletedFN, + val); m.updateBoxAndNormals(); } break; - case FP_REMOVE_TVERTEX_COLLAPSE : - { - bool hadFF = false; - bool hadVF = false; - if (m.hasDataMask(MeshModel::MM_FACEFACETOPO)){ - m.clearDataMask(MeshModel::MM_FACEFACETOPO); - hadFF = true; - } - if (m.hasDataMask(MeshModel::MM_VERTFACETOPO)){ - m.clearDataMask(MeshModel::MM_VERTFACETOPO); - hadVF = true; - } + case FP_REMOVE_TVERTEX: { + int total = 0; Scalarm threshold = par.getFloat("Threshold"); - bool repeat = par.getBool("Repeat"); - int total = tri::Clean::RemoveTVertexByCollapse(m.cm, threshold, repeat); - log("Successfully removed %d t-vertices", total); - if (hadFF) - m.updateDataMask(MeshModel::MM_FACEFACETOPO); - if (hadVF) - m.updateDataMask(MeshModel::MM_VERTFACETOPO); - } break; + bool repeat = par.getBool("Repeat"); + if (par.getEnum("method") == 0) { // edge collapse + bool hadFF = false; + bool hadVF = false; + if (m.hasDataMask(MeshModel::MM_FACEFACETOPO)) { + m.clearDataMask(MeshModel::MM_FACEFACETOPO); + hadFF = true; + } + if (m.hasDataMask(MeshModel::MM_VERTFACETOPO)) { + m.clearDataMask(MeshModel::MM_VERTFACETOPO); + hadVF = true; + } + total = tri::Clean::RemoveTVertexByCollapse(m.cm, threshold, repeat); - case FP_REMOVE_TVERTEX_FLIP : - { - if (vcg::tri::Clean::CountNonManifoldEdgeFF(m.cm) > 0 || - vcg::tri::Clean::CountNonManifoldVertexFF(m.cm) > 0){ - throw MLException("Non manifold mesh. Please clean the mesh first."); + if (hadFF) + m.updateDataMask(MeshModel::MM_FACEFACETOPO); + if (hadVF) + m.updateDataMask(MeshModel::MM_VERTFACETOPO); + } + else { // edge flip + if (vcg::tri::Clean::CountNonManifoldEdgeFF(m.cm) > 0 || + vcg::tri::Clean::CountNonManifoldVertexFF(m.cm) > 0) { + throw MLException("Non manifold mesh. Please clean the mesh first."); + } + total = tri::Clean::RemoveTVertexByFlip(m.cm, threshold, repeat); } - Scalarm threshold = par.getFloat("Threshold"); - bool repeat = par.getBool("Repeat"); - int total = tri::Clean::RemoveTVertexByFlip(m.cm, threshold, repeat); log("Successfully removed %d t-vertices", total); } break; - case FP_MERGE_WEDGE_TEX : - { + case FP_MERGE_WEDGE_TEX: { Scalarm threshold = par.getFloat("MergeThr"); tri::UpdateTopology::VertexFace(m.cm); int total = tri::UpdateTexture::WedgeTexMergeClose(m.cm, threshold); - log("Successfully merged %d wedge tex coord distant less than %f", total,threshold); + log("Successfully merged %d wedge tex coord distant less than %f", total, threshold); } break; - case FP_MERGE_CLOSE_VERTEX : - { + case FP_MERGE_CLOSE_VERTEX: { Scalarm threshold = par.getAbsPerc("Threshold"); - int total = tri::Clean::MergeCloseVertex(m.cm, threshold); + int total = tri::Clean::MergeCloseVertex(m.cm, threshold); log("Successfully merged %d vertices", total); } break; - case FP_REMOVE_DUPLICATE_FACE : - { + case FP_REMOVE_DUPLICATE_FACE: { int total = tri::Clean::RemoveDuplicateFace(m.cm); log("Successfully deleted %d duplicated faces", total); } break; - case FP_REMOVE_FOLD_FACE: - { + case FP_REMOVE_FOLD_FACE: { m.updateDataMask(MeshModel::MM_FACECOLOR); int total = tri::Clean::RemoveFaceFoldByFlip(m.cm); log("Successfully flipped %d folded faces", total); m.updateBoxAndNormals(); } break; - case FP_REMOVE_NON_MANIF_EDGE : - { + case FP_REMOVE_NON_MANIF_EDGE: { int total = tri::Clean::RemoveNonManifoldFace(m.cm); log("Successfully removed %d non-manifold faces", total); m.updateBoxAndNormals(); } break; - case FP_REMOVE_NON_MANIF_EDGE_SPLIT : - { + case FP_REMOVE_NON_MANIF_EDGE_SPLIT: { int total = tri::Clean::SplitManifoldComponents(m.cm); log("Successfully split the mesh into %d edge manifold components", total); m.updateBoxAndNormals(); if (m.hasDataMask(MeshModel::MM_WEDGTEXCOORD)) - postConditionMask = MeshModel::MM_GEOMETRY_AND_TOPOLOGY_CHANGE | MeshModel::MM_WEDGTEXCOORD; + postConditionMask = + MeshModel::MM_GEOMETRY_AND_TOPOLOGY_CHANGE | MeshModel::MM_WEDGTEXCOORD; } break; - case FP_REMOVE_NON_MANIF_VERT : - { + case FP_REMOVE_NON_MANIF_VERT: { Scalarm threshold = par.getFloat("VertDispRatio"); - int total = tri::Clean::SplitNonManifoldVertex(m.cm,threshold); + int total = tri::Clean::SplitNonManifoldVertex(m.cm, threshold); log("Successfully split %d non manifold vertices faces", total); m.updateBoxAndNormals(); } break; - case FP_REMOVE_FACE_ZERO_AREA: - { + case FP_REMOVE_FACE_ZERO_AREA: { int nullFaces = tri::Clean::RemoveFaceOutOfRangeArea(m.cm, 0); log("Removed %d null faces", nullFaces); m.clearDataMask(MeshModel::MM_FACEFACETOPO); } break; - case FP_REMOVE_UNREFERENCED_VERTEX: - { + case FP_REMOVE_UNREFERENCED_VERTEX: { int delvert = tri::Clean::RemoveUnreferencedVertex(m.cm); log("Removed %d unreferenced vertices", delvert); - if (delvert != 0) m.updateBoxAndNormals(); + if (delvert != 0) + m.updateBoxAndNormals(); } break; - case FP_REMOVE_DUPLICATED_VERTEX: - { + case FP_REMOVE_DUPLICATED_VERTEX: { int delvert = tri::Clean::RemoveDuplicateVertex(m.cm); log("Removed %d duplicated vertices", delvert); - if (delvert != 0) m.updateBoxAndNormals(); + if (delvert != 0) + m.updateBoxAndNormals(); m.clearDataMask(MeshModel::MM_FACEFACETOPO); m.clearDataMask(MeshModel::MM_VERTFACETOPO); } break; - case FP_SNAP_MISMATCHED_BORDER : - { + case FP_SNAP_MISMATCHED_BORDER: { Scalarm threshold = par.getFloat("EdgeDistRatio"); - int total = SnapVertexBorder(m.cm, threshold,cb); + int total = SnapVertexBorder(m.cm, threshold, cb); log("Successfully Split %d faces to snap", total); m.clearDataMask(MeshModel::MM_FACEFACETOPO); m.clearDataMask(MeshModel::MM_VERTFACETOPO); } break; - default : - wrongActionCalled(filter); // unknown filter; + default: wrongActionCalled(filter); // unknown filter; } return std::map(); } - -int SnapVertexBorder(CMeshO &m, Scalarm threshold, vcg::CallBackPos * cb) +int SnapVertexBorder(CMeshO& m, Scalarm threshold, vcg::CallBackPos* cb) { tri::Allocator::CompactEveryVector(m); @@ -471,73 +591,67 @@ int SnapVertexBorder(CMeshO &m, Scalarm threshold, vcg::CallBackPos * cb) tri::UpdateFlags::FaceBorderFromFF(m); tri::UpdateFlags::VertexBorderFromFaceBorder(m); tri::UpdateNormal::PerVertexNormalizedPerFaceNormalized(m); - typedef GridStaticPtr MetroMeshFaceGrid; - MetroMeshFaceGrid unifGridFace; - typedef tri::FaceTmark MarkerFace; - MarkerFace markerFunctor(&m); - vcg::face::PointDistanceBaseFunctor PDistFunct; + typedef GridStaticPtr MetroMeshFaceGrid; + MetroMeshFaceGrid unifGridFace; + typedef tri::FaceTmark MarkerFace; + MarkerFace markerFunctor(&m); + vcg::face::PointDistanceBaseFunctor PDistFunct; tri::UpdateFlags::FaceClearV(m); - unifGridFace.Set(m.face.begin(),m.face.end()); + unifGridFace.Set(m.face.begin(), m.face.end()); - int faceFound; - int K = 20; - Point3m startPt; - float maxDist = m.bbox.Diag()/20; - vector splitVertVec; + int faceFound; + int K = 20; + Point3m startPt; + float maxDist = m.bbox.Diag() / 20; + vector splitVertVec; vector splitFaceVec; - vector splitEdgeVec; - for(CMeshO::VertexIterator vi=m.vert.begin();vi!=m.vert.end();++vi) - if((*vi).IsB()) - { - cb((int(tri::Index(m,*vi)) * 100) / m.vn,"Snapping vertices"); + vector splitEdgeVec; + for (CMeshO::VertexIterator vi = m.vert.begin(); vi != m.vert.end(); ++vi) + if ((*vi).IsB()) { + cb((int(tri::Index(m, *vi)) * 100) / m.vn, "Snapping vertices"); vector faceVec; - vector distVec; - vector pointVec; - Point3m u; - startPt = (*vi).P(); - faceFound = unifGridFace.GetKClosest(PDistFunct,markerFunctor, K, startPt,maxDist, faceVec, distVec, pointVec); + vector distVec; + vector pointVec; + Point3m u; + startPt = (*vi).P(); + faceFound = unifGridFace.GetKClosest( + PDistFunct, markerFunctor, K, startPt, maxDist, faceVec, distVec, pointVec); CMeshO::FacePointer bestFace = 0; - float localThr, bestDist = std::numeric_limits::max(); - Point3m bestPoint; - int bestEdge; + float localThr, bestDist = std::numeric_limits::max(); + Point3m bestPoint; + int bestEdge; // qDebug("Found %i face for vertex %i",faceFound,vi-m.vert.begin()); - for(int i=0;icN(),pointVec[i],u); - // qDebug(" face %i face for vertex %5.3f %5.3f %5.3f dist %5.3f (%c %c %c)",fp-&*m.face.begin(),u[0],u[1],u[2],distVec[i],IsBorder(*fp,0)?'b':' ',IsBorder(*fp,1)?'b':' ',IsBorder(*fp,2)?'b':' '); - for(int j=0;j<3;++j) - { - if(IsBorder(*fp,j) && !fp->IsV()) - { - if( u[(j+0)%3] > epsilonBig && - u[(j+1)%3] > epsilonBig && - u[(j+2)%3] < epsilonSmall ) - { - if(distVec[i] < bestDist) - { - bestDist=distVec[i]; - //bestPoint=pointVec[i]; - bestPoint=(*vi).cP(); - bestFace=fp; - bestEdge=j; + for (int i = 0; i < faceFound; ++i) { + const float epsilonSmall = float(1e-5); + const float epsilonBig = float(1e-2); + CMeshO::FacePointer fp = faceVec[i]; + InterpolationParameters(*fp, fp->cN(), pointVec[i], u); + // qDebug(" face %i face for vertex %5.3f %5.3f %5.3f dist %5.3f (%c %c + // %c)",fp-&*m.face.begin(),u[0],u[1],u[2],distVec[i],IsBorder(*fp,0)?'b':' + // ',IsBorder(*fp,1)?'b':' ',IsBorder(*fp,2)?'b':' '); + for (int j = 0; j < 3; ++j) { + if (IsBorder(*fp, j) && !fp->IsV()) { + if (u[(j + 0) % 3] > epsilonBig && u[(j + 1) % 3] > epsilonBig && + u[(j + 2) % 3] < epsilonSmall) { + if (distVec[i] < bestDist) { + bestDist = distVec[i]; + // bestPoint=pointVec[i]; + bestPoint = (*vi).cP(); + bestFace = fp; + bestEdge = j; } } } } } // end for each faceFound - if(bestFace) - { - localThr = threshold*Distance(bestFace->P0(bestEdge),bestFace->P1(bestEdge)); - if(bestDist < localThr && !bestFace->IsV()) - { + if (bestFace) { + localThr = threshold * Distance(bestFace->P0(bestEdge), bestFace->P1(bestEdge)); + if (bestDist < localThr && !bestFace->IsV()) { bestFace->SetV(); - (*vi).C()= Color4b::Blue; - //bestFace->C()=Color4b::LightBlue; + (*vi).C() = Color4b::Blue; + // bestFace->C()=Color4b::LightBlue; (*vi).SetS(); splitVertVec.push_back(bestPoint); splitEdgeVec.push_back(bestEdge); @@ -546,8 +660,8 @@ int SnapVertexBorder(CMeshO &m, Scalarm threshold, vcg::CallBackPos * cb) } } // end for all border vertices tri::Allocator::PointerUpdater pu; - CMeshO::VertexIterator firstVert = tri::Allocator::AddVertices(m,splitVertVec.size()); - CMeshO::FaceIterator firstface = tri::Allocator::AddFaces(m,splitVertVec.size(),pu); + CMeshO::VertexIterator firstVert = tri::Allocator::AddVertices(m, splitVertVec.size()); + CMeshO::FaceIterator firstface = tri::Allocator::AddFaces(m, splitVertVec.size(), pu); // // ^ ^ // / \ / | \ . @@ -558,11 +672,10 @@ int SnapVertexBorder(CMeshO &m, Scalarm threshold, vcg::CallBackPos * cb) // V0 ------------------V2 V0 -------fv---------V2 // i - for(size_t i=0;iP() = splitVertVec[i]; - int eInd = splitEdgeVec[i]; - CMeshO::FacePointer fp = splitFaceVec[i]; + for (size_t i = 0; i < splitVertVec.size(); ++i) { + firstVert->P() = splitVertVec[i]; + int eInd = splitEdgeVec[i]; + CMeshO::FacePointer fp = splitFaceVec[i]; pu.Update(fp); firstface->V(0) = &*firstVert; firstface->V(1) = fp->V2(eInd); @@ -578,7 +691,6 @@ int SnapVertexBorder(CMeshO &m, Scalarm threshold, vcg::CallBackPos * cb) return int(splitVertVec.size()); } - // // ^----------------- // / | \ / @@ -590,51 +702,43 @@ int SnapVertexBorder(CMeshO &m, Scalarm threshold, vcg::CallBackPos * cb) // i // -int DeleteCollinearBorder(CMeshO &m, float threshold) +int DeleteCollinearBorder(CMeshO& m, float threshold) { - int total=0; + int total = 0; CMeshO::FaceIterator fi; - for(fi=m.face.begin();fi!=m.face.end();++fi) - { - if(!(*fi).IsD()) - { - for(int i=0;i<3;++i) - { - if(face::IsBorder(*fi,i) && !face::IsBorder(*fi,(i+1)%3)) - { - CMeshO::VertexPointer V0= (*fi).V0(i); - CMeshO::VertexPointer V1= (*fi).V1(i); - CMeshO::VertexPointer V2=0; - CMeshO::FacePointer fadj = (*fi).FFp((i+1)%3); - int adjBordInd = (*fi).FFi((i+1)%3); - if(fadj->V1(adjBordInd) == V1) + for (fi = m.face.begin(); fi != m.face.end(); ++fi) { + if (!(*fi).IsD()) { + for (int i = 0; i < 3; ++i) { + if (face::IsBorder(*fi, i) && !face::IsBorder(*fi, (i + 1) % 3)) { + CMeshO::VertexPointer V0 = (*fi).V0(i); + CMeshO::VertexPointer V1 = (*fi).V1(i); + CMeshO::VertexPointer V2 = 0; + CMeshO::FacePointer fadj = (*fi).FFp((i + 1) % 3); + int adjBordInd = (*fi).FFi((i + 1) % 3); + if (fadj->V1(adjBordInd) == V1) V2 = fadj->V2(adjBordInd); else continue; // non coerent face ordering. - if(face::IsBorder(*fadj,(adjBordInd+1)%3)) - { + if (face::IsBorder(*fadj, (adjBordInd + 1) % 3)) { // the colinearity test; - Point3m pp; + Point3m pp; CMeshO::ScalarType dist; - SegmentPointDistance(Segment3m(V0->cP(),V2->cP()),V1->cP(),pp,dist); - if(dist* threshold < Distance(V0->cP(),V2->cP()) ) - { - (*fi).V1(i)=V2; - if(face::IsBorder(*fadj,(adjBordInd+2)%3)) - { - (*fi).FFp((i+1)%3)=&*fi; - (*fi).FFi((i+1)%3)=(i+1)%3; + SegmentPointDistance(Segment3m(V0->cP(), V2->cP()), V1->cP(), pp, dist); + if (dist * threshold < Distance(V0->cP(), V2->cP())) { + (*fi).V1(i) = V2; + if (face::IsBorder(*fadj, (adjBordInd + 2) % 3)) { + (*fi).FFp((i + 1) % 3) = &*fi; + (*fi).FFi((i + 1) % 3) = (i + 1) % 3; } - else - { - CMeshO::FacePointer fj = fadj->FFp((adjBordInd+2)%3); - int ij = fadj->FFi((adjBordInd+2)%3); - (*fi).FFp((i+1)%3)= fj; - (*fi).FFi((i+1)%3)= ij; - fj->FFp(ij)=&*fi; - fj->FFi(ij)=(i+1)%3; + else { + CMeshO::FacePointer fj = fadj->FFp((adjBordInd + 2) % 3); + int ij = fadj->FFi((adjBordInd + 2) % 3); + (*fi).FFp((i + 1) % 3) = fj; + (*fi).FFi((i + 1) % 3) = ij; + fj->FFp(ij) = &*fi; + fj->FFi(ij) = (i + 1) % 3; } - tri::Allocator::DeleteFace(m,*fadj); + tri::Allocator::DeleteFace(m, *fadj); total++; } } diff --git a/src/meshlabplugins/filter_clean/cleanfilter.h b/src/meshlabplugins/filter_clean/cleanfilter.h index e6374e0a9..2e05d9303 100644 --- a/src/meshlabplugins/filter_clean/cleanfilter.h +++ b/src/meshlabplugins/filter_clean/cleanfilter.h @@ -1,25 +1,25 @@ -/**************************************************************************** -* MeshLab o o * -* A versatile mesh processing toolbox o o * -* _ O _ * -* Copyright(C) 2005 \/)\/ * -* 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. * -* * -****************************************************************************/ +/***************************************************************************** + * 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 __CLEAN_FILTER_H__ #define __CLEAN_FILTER_H__ @@ -33,30 +33,25 @@ class CleanFilter : public QObject, public FilterPlugin MESHLAB_PLUGIN_IID_EXPORTER(FILTER_PLUGIN_IID) Q_INTERFACES(FilterPlugin) - public: - /* naming convention : - - FP -> Filter Plugin - - name of the plugin separated by _ - */ - enum { - FP_BALL_PIVOTING, - FP_REMOVE_ISOLATED_COMPLEXITY, - FP_REMOVE_ISOLATED_DIAMETER, - FP_REMOVE_WRT_Q, - FP_REMOVE_TVERTEX_FLIP, - FP_SNAP_MISMATCHED_BORDER, - FP_REMOVE_TVERTEX_COLLAPSE, - FP_REMOVE_FOLD_FACE, - FP_REMOVE_DUPLICATE_FACE, - FP_REMOVE_NON_MANIF_EDGE, - FP_REMOVE_NON_MANIF_EDGE_SPLIT, - FP_REMOVE_NON_MANIF_VERT, - FP_REMOVE_UNREFERENCED_VERTEX, - FP_REMOVE_DUPLICATED_VERTEX, - FP_REMOVE_FACE_ZERO_AREA, - FP_MERGE_CLOSE_VERTEX, - FP_MERGE_WEDGE_TEX - } ; +public: + enum { + FP_BALL_PIVOTING, + FP_REMOVE_ISOLATED_COMPLEXITY, + FP_REMOVE_ISOLATED_DIAMETER, + FP_REMOVE_WRT_Q, + FP_REMOVE_TVERTEX, + FP_SNAP_MISMATCHED_BORDER, + FP_REMOVE_FOLD_FACE, + FP_REMOVE_DUPLICATE_FACE, + FP_REMOVE_NON_MANIF_EDGE, + FP_REMOVE_NON_MANIF_EDGE_SPLIT, + FP_REMOVE_NON_MANIF_VERT, + FP_REMOVE_UNREFERENCED_VERTEX, + FP_REMOVE_DUPLICATED_VERTEX, + FP_REMOVE_FACE_ZERO_AREA, + FP_MERGE_CLOSE_VERTEX, + FP_MERGE_WEDGE_TEX + }; CleanFilter(); ~CleanFilter(); @@ -65,18 +60,18 @@ class CleanFilter : public QObject, public FilterPlugin QString filterName(ActionIDType filter) const; QString filterInfo(ActionIDType filter) const; - FilterClass getClass(const QAction*) const; - int getRequirements(const QAction*); - int postCondition(const QAction* ) const; - int getPreConditions(const QAction *) const { return MeshModel::MM_NONE; } - RichParameterList initParameterList(const QAction*, const MeshDocument &/*m*/); - std::map applyFilter(const QAction* action, const RichParameterList & /*parent*/, MeshDocument &md, unsigned int& postConditionMask, vcg::CallBackPos * cb); - FilterArity filterArity(const QAction *) const {return SINGLE_MESH;} + FilterClass getClass(const QAction*) const; + int getRequirements(const QAction*); + int postCondition(const QAction*) const; + int getPreConditions(const QAction*) const { return MeshModel::MM_NONE; } + RichParameterList initParameterList(const QAction*, const MeshDocument& /*m*/); + std::map applyFilter( + const QAction* action, + const RichParameterList& /*parent*/, + MeshDocument& md, + unsigned int& postConditionMask, + vcg::CallBackPos* cb); + FilterArity filterArity(const QAction*) const { return SINGLE_MESH; } }; - - - - - #endif From f4a9b270e35effdb0d1fb03263d7b9bef282e395 Mon Sep 17 00:00:00 2001 From: alemuntoni Date: Wed, 22 Sep 2021 16:09:21 +0200 Subject: [PATCH 03/10] unique repair non manifold edges filter --- .../filter_clean/cleanfilter.cpp | 65 ++++++++++--------- src/meshlabplugins/filter_clean/cleanfilter.h | 3 +- 2 files changed, 34 insertions(+), 34 deletions(-) diff --git a/src/meshlabplugins/filter_clean/cleanfilter.cpp b/src/meshlabplugins/filter_clean/cleanfilter.cpp index cf9930a9b..d7ddaeebe 100644 --- a/src/meshlabplugins/filter_clean/cleanfilter.cpp +++ b/src/meshlabplugins/filter_clean/cleanfilter.cpp @@ -46,8 +46,7 @@ CleanFilter::CleanFilter() FP_SNAP_MISMATCHED_BORDER, FP_REMOVE_DUPLICATE_FACE, FP_REMOVE_FOLD_FACE, - FP_REMOVE_NON_MANIF_EDGE, - FP_REMOVE_NON_MANIF_EDGE_SPLIT, + FP_REPAIR_NON_MANIF_EDGE, FP_REMOVE_NON_MANIF_VERT, FP_REMOVE_UNREFERENCED_VERTEX, FP_REMOVE_DUPLICATED_VERTEX, @@ -85,9 +84,7 @@ QString CleanFilter::filterName(ActionIDType filter) const case FP_MERGE_WEDGE_TEX: return QString("Merge Wedge Texture Coord"); case FP_REMOVE_DUPLICATE_FACE: return QString("Remove Duplicate Faces"); case FP_REMOVE_FOLD_FACE: return QString("Remove Isolated Folded Faces by Edge Flip"); - case FP_REMOVE_NON_MANIF_EDGE: return QString("Repair non Manifold Edges by removing faces"); - case FP_REMOVE_NON_MANIF_EDGE_SPLIT: - return QString("Repair non Manifold Edges by splitting vertices"); + case FP_REPAIR_NON_MANIF_EDGE: return QString("Repair non Manifold Edges"); case FP_REMOVE_NON_MANIF_VERT: return QString("Repair non Manifold Vertices by splitting"); case FP_REMOVE_UNREFERENCED_VERTEX: return QString("Remove Unreferenced Vertices"); case FP_REMOVE_DUPLICATED_VERTEX: return QString("Remove Duplicate Vertices"); @@ -153,14 +150,11 @@ QString CleanFilter::filterInfo(ActionIDType filterId) const "Delete all the single folded faces. A face is considered folded if its normal is " "opposite to all the adjacent faces. It is removed by flipping it against the face f " "adjacent along the edge e such that the vertex opposite to e fall inside f"); - case FP_REMOVE_NON_MANIF_EDGE: + case FP_REPAIR_NON_MANIF_EDGE: return QString( - "For each non Manifold edge it iteratively deletes the smallest area face until it " - "becomes 2-Manifold."); - case FP_REMOVE_NON_MANIF_EDGE_SPLIT: - return QString( - "Remove all non manifold edges splitting vertices. Each non manifold edges chain will " - "become a border"); + "Remove non-manifold edges by removing faces (for each non Manifold edge it " + "iteratively deletes the smallest area face until it becomes 2-Manifold) or by " + "splitting vertices (each non manifold edges chain will become a border)."); case FP_REMOVE_NON_MANIF_VERT: return QString("Split non Manifold vertices until it becomes 2-Manifold."); case FP_REMOVE_UNREFERENCED_VERTEX: @@ -188,8 +182,7 @@ CleanFilter::FilterClass CleanFilter::getClass(const QAction* a) const case FP_MERGE_CLOSE_VERTEX: case FP_REMOVE_DUPLICATE_FACE: case FP_SNAP_MISMATCHED_BORDER: - case FP_REMOVE_NON_MANIF_EDGE: - case FP_REMOVE_NON_MANIF_EDGE_SPLIT: + case FP_REPAIR_NON_MANIF_EDGE: case FP_REMOVE_NON_MANIF_VERT: case FP_REMOVE_FACE_ZERO_AREA: case FP_REMOVE_UNREFERENCED_VERTEX: @@ -210,8 +203,7 @@ int CleanFilter::getRequirements(const QAction* action) case FP_REMOVE_ISOLATED_COMPLEXITY: case FP_REMOVE_ISOLATED_DIAMETER: return MeshModel::MM_FACEFACETOPO | MeshModel::MM_FACEMARK; case FP_REMOVE_TVERTEX: return MeshModel::MM_FACEFACETOPO | MeshModel::MM_VERTMARK; - case FP_REMOVE_NON_MANIF_EDGE: return MeshModel::MM_FACEFACETOPO | MeshModel::MM_VERTMARK; - case FP_REMOVE_NON_MANIF_EDGE_SPLIT: return MeshModel::MM_FACEFACETOPO | MeshModel::MM_VERTMARK; + case FP_REPAIR_NON_MANIF_EDGE: return MeshModel::MM_FACEFACETOPO | MeshModel::MM_VERTMARK; case FP_REMOVE_NON_MANIF_VERT: return MeshModel::MM_FACEFACETOPO | MeshModel::MM_VERTMARK; case FP_SNAP_MISMATCHED_BORDER: return MeshModel::MM_FACEFACETOPO | MeshModel::MM_VERTMARK | MeshModel::MM_FACEMARK; @@ -240,12 +232,11 @@ int CleanFilter::postCondition(const QAction* action) const case FP_MERGE_WEDGE_TEX: case FP_REMOVE_DUPLICATE_FACE: case FP_REMOVE_FOLD_FACE: - case FP_REMOVE_NON_MANIF_EDGE: + case FP_REPAIR_NON_MANIF_EDGE: case FP_REMOVE_NON_MANIF_VERT: case FP_REMOVE_UNREFERENCED_VERTEX: case FP_REMOVE_DUPLICATED_VERTEX: - case FP_REMOVE_FACE_ZERO_AREA: - case FP_REMOVE_NON_MANIF_EDGE_SPLIT: return MeshModel::MM_GEOMETRY_AND_TOPOLOGY_CHANGE; + case FP_REMOVE_FACE_ZERO_AREA: return MeshModel::MM_GEOMETRY_AND_TOPOLOGY_CHANGE; } return MeshModel::MM_ALL; } @@ -386,6 +377,14 @@ RichParameterList CleanFilter::initParameterList(const QAction* action, const Me "is 0.5 the new vertex is half away toward the barycenter of the face. Reasonable " "values are in the [0 .. 0.1] range.")); break; + case FP_REPAIR_NON_MANIF_EDGE: + parlst.addParam(RichEnum( + "method", + 0, + {"Remove Faces", "Split Vertices"}, + "Method", + "Selects wether to remove non manifold edges by removing faces or by splitting " + "vertices.")); default: break; // do not add any parameter for the other filters } return parlst; @@ -526,19 +525,21 @@ std::map CleanFilter::applyFilter( m.updateBoxAndNormals(); } break; - case FP_REMOVE_NON_MANIF_EDGE: { - int total = tri::Clean::RemoveNonManifoldFace(m.cm); - log("Successfully removed %d non-manifold faces", total); - m.updateBoxAndNormals(); - } break; - - case FP_REMOVE_NON_MANIF_EDGE_SPLIT: { - int total = tri::Clean::SplitManifoldComponents(m.cm); - log("Successfully split the mesh into %d edge manifold components", total); - m.updateBoxAndNormals(); - if (m.hasDataMask(MeshModel::MM_WEDGTEXCOORD)) - postConditionMask = - MeshModel::MM_GEOMETRY_AND_TOPOLOGY_CHANGE | MeshModel::MM_WEDGTEXCOORD; + case FP_REPAIR_NON_MANIF_EDGE: { + int total = 0; + if (par.getEnum("method") == 0) { // removing faces + total = tri::Clean::RemoveNonManifoldFace(m.cm); + log("Successfully removed %d non-manifold faces", total); + m.updateBoxAndNormals(); + } + else { // splitting vertices + total = tri::Clean::SplitManifoldComponents(m.cm); + log("Successfully split the mesh into %d edge manifold components", total); + m.updateBoxAndNormals(); + if (m.hasDataMask(MeshModel::MM_WEDGTEXCOORD)) + postConditionMask = + MeshModel::MM_GEOMETRY_AND_TOPOLOGY_CHANGE | MeshModel::MM_WEDGTEXCOORD; + } } break; case FP_REMOVE_NON_MANIF_VERT: { diff --git a/src/meshlabplugins/filter_clean/cleanfilter.h b/src/meshlabplugins/filter_clean/cleanfilter.h index 2e05d9303..396a3382c 100644 --- a/src/meshlabplugins/filter_clean/cleanfilter.h +++ b/src/meshlabplugins/filter_clean/cleanfilter.h @@ -43,8 +43,7 @@ public: FP_SNAP_MISMATCHED_BORDER, FP_REMOVE_FOLD_FACE, FP_REMOVE_DUPLICATE_FACE, - FP_REMOVE_NON_MANIF_EDGE, - FP_REMOVE_NON_MANIF_EDGE_SPLIT, + FP_REPAIR_NON_MANIF_EDGE, FP_REMOVE_NON_MANIF_VERT, FP_REMOVE_UNREFERENCED_VERTEX, FP_REMOVE_DUPLICATED_VERTEX, From c9c48d2ec7ee8aa1c9bbef8059546e95cbc46479 Mon Sep 17 00:00:00 2001 From: alemuntoni Date: Wed, 22 Sep 2021 16:39:40 +0200 Subject: [PATCH 04/10] remove "change the current layer" filter --- .../filter_layer/filter_layer.cpp | 782 ++++++++++-------- .../filter_layer/filter_layer.h | 66 +- 2 files changed, 459 insertions(+), 389 deletions(-) diff --git a/src/meshlabplugins/filter_layer/filter_layer.cpp b/src/meshlabplugins/filter_layer/filter_layer.cpp index d50f1893b..4151dbcfb 100644 --- a/src/meshlabplugins/filter_layer/filter_layer.cpp +++ b/src/meshlabplugins/filter_layer/filter_layer.cpp @@ -1,25 +1,25 @@ -/**************************************************************************** -* MeshLab o o * -* A versatile mesh processing toolbox o o * -* _ O _ * -* Copyright(C) 2005 \/)\/ * -* 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. * -* * -****************************************************************************/ +/***************************************************************************** + * 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 #include @@ -27,12 +27,10 @@ #include "filter_layer.h" -#include -#include #include +#include #include - - +#include using namespace std; using namespace vcg; @@ -53,12 +51,10 @@ FilterLayerPlugin::FilterLayerPlugin() FP_RENAME_MESH, FP_RENAME_RASTER, FP_DUPLICATE, - FP_SELECTCURRENT, FP_EXPORT_CAMERAS, - FP_IMPORT_CAMERAS - }; + FP_IMPORT_CAMERAS}; - for(ActionIDType tt: types()) { + for (ActionIDType tt : types()) { QAction* act = new QAction(filterName(tt), this); actionList.push_back(act); } @@ -72,23 +68,22 @@ QString FilterLayerPlugin::pluginName() const // ST() return the very short string describing each filtering action QString FilterLayerPlugin::filterName(ActionIDType filterId) const { - switch(filterId) { - case FP_SPLITSELECTEDFACES : return QString("Move selected faces to another layer"); - case FP_SPLITSELECTEDVERTICES : return QString("Move selected vertices to another layer") ; - case FP_SPLITCONNECTED : return QString("Split in Connected Components"); - case FP_DUPLICATE : return QString("Duplicate Current layer"); - case FP_DELETE_MESH : return QString("Delete Current Mesh"); - case FP_DELETE_NON_VISIBLE_MESH : return QString("Delete all non visible Mesh Layers"); - case FP_DELETE_RASTER : return QString("Delete Current Raster"); - case FP_DELETE_NON_SELECTED_RASTER : return QString("Delete all Non Selected Rasters"); - case FP_FLATTEN : return QString("Flatten Visible Layers"); - case FP_RENAME_MESH : return QString("Rename Current Mesh"); - case FP_RENAME_RASTER : return QString("Rename Current Raster"); - case FP_SELECTCURRENT : return QString("Change the current layer"); - case FP_MESH_VISIBILITY : return QString("Change Visibility of layer(s)"); - case FP_EXPORT_CAMERAS: return QString("Export active rasters cameras to file"); - case FP_IMPORT_CAMERAS: return QString("Import cameras for active rasters from file"); - default : assert(0); + switch (filterId) { + case FP_SPLITSELECTEDFACES: return QString("Move selected faces to another layer"); + case FP_SPLITSELECTEDVERTICES: return QString("Move selected vertices to another layer"); + case FP_SPLITCONNECTED: return QString("Split in Connected Components"); + case FP_DUPLICATE: return QString("Duplicate Current layer"); + case FP_DELETE_MESH: return QString("Delete Current Mesh"); + case FP_DELETE_NON_VISIBLE_MESH: return QString("Delete all non visible Mesh Layers"); + case FP_DELETE_RASTER: return QString("Delete Current Raster"); + case FP_DELETE_NON_SELECTED_RASTER: return QString("Delete all Non Selected Rasters"); + case FP_FLATTEN: return QString("Flatten Visible Layers"); + case FP_RENAME_MESH: return QString("Rename Current Mesh"); + case FP_RENAME_RASTER: return QString("Rename Current Raster"); + case FP_MESH_VISIBILITY: return QString("Change Visibility of layer(s)"); + case FP_EXPORT_CAMERAS: return QString("Export active rasters cameras to file"); + case FP_IMPORT_CAMERAS: return QString("Import cameras for active rasters from file"); + default: assert(0); } return NULL; } @@ -96,88 +91,135 @@ QString FilterLayerPlugin::filterName(ActionIDType filterId) const // Info() return the longer string describing each filtering action QString FilterLayerPlugin::filterInfo(ActionIDType filterId) const { - switch(filterId) { - case FP_SPLITSELECTEDFACES : return QString("Selected faces are moved (or duplicated) in a new layer. Warning! per-vertex and per-face user defined attributes will not be transferred."); - case FP_SPLITSELECTEDVERTICES : return QString("Selected vertices are moved (or duplicated) in a new layer. Warning! per-vertex user defined attributes will not be transferred."); - case FP_DELETE_MESH : return QString("The current mesh layer is deleted"); - case FP_DELETE_NON_VISIBLE_MESH : return QString("All the non visible mesh layers are deleted"); - case FP_DELETE_RASTER : return QString("The current raster layer is deleted"); - case FP_DELETE_NON_SELECTED_RASTER : return QString("All non selected raster layers are deleted"); - case FP_SPLITCONNECTED: return QString("Split current Layer into many layers, one for each connected components"); - case FP_DUPLICATE : return QString("Create a new layer containing the same model as the current one"); - case FP_FLATTEN : return QString("Flatten all or only the visible layers into a single new mesh.
Transformations are preserved. Existing layers can be optionally deleted"); - case FP_RENAME_MESH : return QString("Explicitly change the label shown for a given mesh"); - case FP_RENAME_RASTER : return QString("Explicitly change the label shown for a given raster"); - case FP_SELECTCURRENT : return QString("Change the current layer to a chosen one"); - case FP_MESH_VISIBILITY : return QString("Make layer(s) visible/invisible. Useful for scripting."); - case FP_EXPORT_CAMERAS: return QString("Export active cameras to file, in the .out or Agisoft .xml formats"); - case FP_IMPORT_CAMERAS: return QString("Import cameras for active rasters from .out or Agisoft .xml formats"); - default : assert(0); + switch (filterId) { + case FP_SPLITSELECTEDFACES: + return QString( + "Selected faces are moved (or duplicated) in a new layer. Warning! per-vertex and " + "per-face user defined attributes will not be transferred."); + case FP_SPLITSELECTEDVERTICES: + return QString( + "Selected vertices are moved (or duplicated) in a new layer. Warning! per-vertex user " + "defined attributes will not be transferred."); + case FP_DELETE_MESH: return QString("The current mesh layer is deleted"); + case FP_DELETE_NON_VISIBLE_MESH: return QString("All the non visible mesh layers are deleted"); + case FP_DELETE_RASTER: return QString("The current raster layer is deleted"); + case FP_DELETE_NON_SELECTED_RASTER: + return QString("All non selected raster layers are deleted"); + case FP_SPLITCONNECTED: + return QString("Split current Layer into many layers, one for each connected components"); + case FP_DUPLICATE: + return QString("Create a new layer containing the same model as the current one"); + case FP_FLATTEN: + return QString( + "Flatten all or only the visible layers into a single new mesh.
Transformations " + "are preserved. Existing layers can be optionally deleted"); + case FP_RENAME_MESH: return QString("Explicitly change the label shown for a given mesh"); + case FP_RENAME_RASTER: return QString("Explicitly change the label shown for a given raster"); + case FP_MESH_VISIBILITY: + return QString("Make layer(s) visible/invisible. Useful for scripting."); + case FP_EXPORT_CAMERAS: + return QString("Export active cameras to file, in the .out or Agisoft .xml formats"); + case FP_IMPORT_CAMERAS: + return QString("Import cameras for active rasters from .out or Agisoft .xml formats"); + default: assert(0); } return NULL; } // This function define the needed parameters for each filter. -RichParameterList FilterLayerPlugin::initParameterList(const QAction *action, const MeshDocument &md) +RichParameterList +FilterLayerPlugin::initParameterList(const QAction* action, const MeshDocument& md) { - RichParameterList parlst; - const MeshModel *mm=md.mm(); - const RasterModel *rm=md.rm(); - switch(ID(action)) - { + RichParameterList parlst; + const MeshModel* mm = md.mm(); + const RasterModel* rm = md.rm(); + switch (ID(action)) { case FP_SPLITSELECTEDVERTICES: - case FP_SPLITSELECTEDFACES : - { - parlst.addParam(RichBool ("DeleteOriginal", - true, - "Delete original selection", - "Deletes the original selected faces/vertices, thus splitting the mesh among layers. \n\n" - "if false, the selected faces/vertices are duplicated in the new layer")); - } + case FP_SPLITSELECTEDFACES: { + parlst.addParam(RichBool( + "DeleteOriginal", + true, + "Delete original selection", + "Deletes the original selected faces/vertices, thus splitting the mesh among layers." + "\n\nif false, the selected faces/vertices are duplicated in the new layer.")); + } break; + case FP_FLATTEN: + parlst.addParam(RichBool( + "MergeVisible", + true, + "Merge Only Visible Layers", + "If true, flatten only visible layers, otherwise, all layers are used.")); + parlst.addParam(RichBool( + "DeleteLayer", + true, + "Delete Layers ", + "Delete all the layers used as source in flattening.
If all layers are visible " + "only a single layer will remain after the invocation of this filter.")); + parlst.addParam(RichBool( + "MergeVertices", + true, + "Merge duplicate vertices", + "Merge the vertices that are duplicated among different layers. \n\n" + "Very useful when the layers are spliced portions of a single big mesh.")); + parlst.addParam(RichBool( + "AlsoUnreferenced", + true, + "Keep unreferenced vertices", + "Do not discard unreferenced vertices from source layers\n\n" + "Necessary for point-cloud layers.")); break; - case FP_FLATTEN : - parlst.addParam(RichBool ("MergeVisible", true, "Merge Only Visible Layers", - "If true, flatten only visible layers, otherwise, all layers are used")); - parlst.addParam(RichBool ("DeleteLayer", true, "Delete Layers ", - "Delete all the layers used as source in flattening.
If all layers are visible only a single layer will remain after the invocation of this filter")); - parlst.addParam(RichBool ("MergeVertices", true, "Merge duplicate vertices", - "Merge the vertices that are duplicated among different layers. \n\n" - "Very useful when the layers are spliced portions of a single big mesh.")); - parlst.addParam(RichBool ("AlsoUnreferenced", true, "Keep unreferenced vertices", - "Do not discard unreferenced vertices from source layers\n\n" - "Necessary for point-cloud layers")); + case FP_RENAME_MESH: + parlst.addParam(RichString("newName", mm->label(), "New Label", "New Label for the mesh.")); break; - case FP_RENAME_MESH : - parlst.addParam(RichString ("newName", - mm->label(), - "New Label", - "New Label for the mesh")); + case FP_RENAME_RASTER: + parlst.addParam( + RichString("newName", rm ? rm->label() : "", "New Label", "New Label for the raster.")); break; - case FP_RENAME_RASTER : - parlst.addParam(RichString ("newName", - rm?rm->label():"", - "New Label", - "New Label for the raster")); - break; - case FP_SELECTCURRENT : - parlst.addParam(RichMesh ("layer",md.mm()->id(),&md, "Layer Name", - "The name of the current layer")); - break; - case FP_MESH_VISIBILITY : - parlst.addParam(RichMesh ("layer",md.mm()->id(),&md, "Layer Name", "The name of the layer that has to change visibility. If second parameter is not empty, this parameter is ignored")); - parlst.addParam(RichString("lName", "", "Substring match", "Apply visibility to all layers with name substring matching the entered string. If not empty, the first parameter is ignored.")); - parlst.addParam(RichBool ("isMeshVisible", true, "Visible", "It makes the selected layer(s) visible or invisible.")); + case FP_MESH_VISIBILITY: + parlst.addParam(RichMesh( + "layer", + md.mm()->id(), + &md, + "Layer Name", + "The name of the layer that has to change visibility. If second parameter is not " + "empty, this parameter is ignored.")); + parlst.addParam(RichString( + "lName", + "", + "Substring match", + "Apply visibility to all layers with name substring matching the entered string. If " + "not empty, the first parameter is ignored.")); + parlst.addParam(RichBool( + "isMeshVisible", + true, + "Visible", + "It makes the selected layer(s) visible or invisible.")); break; case FP_EXPORT_CAMERAS: - parlst.addParam(RichEnum("ExportFile", 0, QStringList("Bundler .out") << "Agisoft xml", "Output format", "Choose the output format, The filter enables to export the cameras to both Bundler and Agisoft Photoscan.")); - parlst.addParam(RichString("newName", - "cameras", - "Export file name (the right extension will be added at the end)", - "Name of the output file, it will be saved in the same folder as the project file")); + parlst.addParam(RichEnum( + "ExportFile", + 0, + QStringList("Bundler .out") << "Agisoft xml", + "Output format", + "Choose the output format, The filter enables to export the cameras to both Bundler " + "and Agisoft Photoscan.")); + parlst.addParam(RichString( + "newName", + "cameras", + "Export file name (the right extension will be added at the end)", + "Name of the output file, it will be saved in the same folder as the project file.")); break; case FP_IMPORT_CAMERAS: - parlst.addParam(RichOpenFile("ImportFile", "", QStringList("All Project Files (*.out *.xml);;Bundler Output (*.out);;Agisoft xml (*.xml)"),"Choose the camera file to be imported", "It's possible to import both Bundler .out and Agisoft .xml files. In both cases, distortion parameters won't be imported. In the case of Agisoft, it's necessary to undistort the images before exporting the xml file")); + parlst.addParam(RichOpenFile( + "ImportFile", + "", + QStringList( + "All Project Files (*.out *.xml);;Bundler Output (*.out);;Agisoft xml (*.xml)"), + "Choose the camera file to be imported", + "It's possible to import both Bundler .out and Agisoft .xml files. In both cases, " + "distortion parameters won't be imported. In the case of Agisoft, it's necessary to " + "undistort the images before exporting the xml file.")); break; default: break; // do not add any parameter for the other filters } @@ -186,60 +228,50 @@ RichParameterList FilterLayerPlugin::initParameterList(const QAction *action, co // Core Function doing the actual mesh processing. std::map FilterLayerPlugin::applyFilter( - const QAction *filter, - const RichParameterList & par, - MeshDocument &md, - unsigned int& /*postConditionMask*/, - vcg::CallBackPos *cb) + const QAction* filter, + const RichParameterList& par, + MeshDocument& md, + unsigned int& /*postConditionMask*/, + vcg::CallBackPos* cb) { - CMeshO::FaceIterator fi; - int numFacesSel,numVertSel; + int numFacesSel, numVertSel; - switch(ID(filter)) - { - case FP_RENAME_MESH: md.mm()->setLabel(par.getString("newName")); break; + switch (ID(filter)) { + case FP_RENAME_MESH: md.mm()->setLabel(par.getString("newName")); break; - case FP_RENAME_RASTER: - { - if (md.rm()) - { + case FP_RENAME_RASTER: { + if (md.rm()) { md.rm()->setLabel(par.getString("newName")); } - else - { + else { throw MLException("Error: Call to Rename Current Raster with no valid raster."); } } break; - case FP_SELECTCURRENT: md.setCurrent(md.getMesh(par.getMeshId("layer"))); break; - - case FP_MESH_VISIBILITY: - { + case FP_MESH_VISIBILITY: { QString match = par.getString("lName"); if (match == "") { - MeshModel *mm = md.getMesh(par.getMeshId("layer")); + MeshModel* mm = md.getMesh(par.getMeshId("layer")); if (mm) md.setVisible(mm->id(), par.getBool("isMeshVisible")); } else { - for(const MeshModel& mmp: md.meshIterator()) { + for (const MeshModel& mmp : md.meshIterator()) { if (mmp.label().contains(match)) md.setVisible(mmp.id(), par.getBool("isMeshVisible")); } } } break; - case FP_DELETE_MESH: - { + case FP_DELETE_MESH: { if (md.mm()) md.delMesh(md.mm()->id()); } break; - case FP_DELETE_NON_VISIBLE_MESH: - { - for(auto it = md.meshBegin(); it != md.meshEnd();) { - if (!it->isVisible()){ + case FP_DELETE_NON_VISIBLE_MESH: { + for (auto it = md.meshBegin(); it != md.meshEnd();) { + if (!it->isVisible()) { it = md.eraseMesh(it); } else { @@ -248,11 +280,13 @@ std::map FilterLayerPlugin::applyFilter( } } break; - case FP_DELETE_RASTER : if(md.rm()) md.delRaster(md.rm()->id()); break; + case FP_DELETE_RASTER: + if (md.rm()) + md.delRaster(md.rm()->id()); + break; - case FP_DELETE_NON_SELECTED_RASTER: - { - for(auto it = md.rasterBegin(); it != md.rasterEnd();) { + case FP_DELETE_NON_SELECTED_RASTER: { + for (auto it = md.rasterBegin(); it != md.rasterEnd();) { if (!it->isVisible()) { it = md.eraseRaster(it); } @@ -262,39 +296,44 @@ std::map FilterLayerPlugin::applyFilter( } } break; - case FP_SPLITSELECTEDVERTICES : - { + case FP_SPLITSELECTEDVERTICES: { MeshModel* currentModel = md.mm(); - MeshModel* destModel = md.addNewMesh("","SelectedVerticesSubset",true); + MeshModel* destModel = md.addNewMesh("", "SelectedVerticesSubset", true); destModel->updateDataMask(currentModel); - numVertSel = (int)tri::UpdateSelection::VertexCount(currentModel->cm); + numVertSel = (int) tri::UpdateSelection::VertexCount(currentModel->cm); tri::Append::Mesh(destModel->cm, currentModel->cm, true); - for (const std::string& tex: destModel->cm.textures) { + for (const std::string& tex : destModel->cm.textures) { destModel->addTexture(tex, currentModel->getTexture(tex)); } - if(par.getBool("DeleteOriginal")) // delete original vert/faces - { + if (par.getBool("DeleteOriginal")) { // delete original vert/faces CMeshO::VertexIterator vi; - int delfaces = (int)tri::UpdateSelection::FaceFromVertexLoose(currentModel->cm); - for (CMeshO::FaceIterator fi = currentModel->cm.face.begin(); fi != currentModel->cm.face.end(); ++fi) - if(!(*fi).IsD() && (*fi).IsS() ) + int delfaces = + (int) tri::UpdateSelection::FaceFromVertexLoose(currentModel->cm); + for (CMeshO::FaceIterator fi = currentModel->cm.face.begin(); + fi != currentModel->cm.face.end(); + ++fi) { + if (!(*fi).IsD() && (*fi).IsS()) tri::Allocator::DeleteFace(currentModel->cm, *fi); - for (vi = currentModel->cm.vert.begin(); vi != currentModel->cm.vert.end(); ++vi) - if(!(*vi).IsD() && (*vi).IsS() ) + } + for (vi = currentModel->cm.vert.begin(); vi != currentModel->cm.vert.end(); ++vi) { + if (!(*vi).IsD() && (*vi).IsS()) tri::Allocator::DeleteVertex(currentModel->cm, *vi); + } tri::UpdateSelection::VertexClear(currentModel->cm); currentModel->clearDataMask(MeshModel::MM_FACEFACETOPO); - log("Moved %i vertices to layer %i, deleted %i faces", numVertSel, currentModel->id(), delfaces); + log("Moved %i vertices to layer %i, deleted %i faces", + numVertSel, + currentModel->id(), + delfaces); } - else // keep original faces - { + else { // keep original faces log("Copied %i vertices to layer %i", numVertSel, currentModel->id()); } vcg::tri::UpdateFlags::VertexClear(destModel->cm, CMeshO::VertexType::SELECTED); @@ -305,45 +344,48 @@ std::map FilterLayerPlugin::applyFilter( destModel->updateDataMask(currentModel); } break; - case FP_SPLITSELECTEDFACES : - { - MeshModel *currentModel = md.mm(); + case FP_SPLITSELECTEDFACES: { + MeshModel* currentModel = md.mm(); - MeshModel *destModel = md.addNewMesh("", "SelectedFacesSubset", true); + MeshModel* destModel = md.addNewMesh("", "SelectedFacesSubset", true); destModel->updateDataMask(currentModel); // select all points involved tri::UpdateSelection::VertexFromFaceLoose(currentModel->cm); - numFacesSel = (int)tri::UpdateSelection::FaceCount(currentModel->cm); - numVertSel = (int)tri::UpdateSelection::VertexCount(currentModel->cm); + numFacesSel = (int) tri::UpdateSelection::FaceCount(currentModel->cm); + numVertSel = (int) tri::UpdateSelection::VertexCount(currentModel->cm); tri::Append::Mesh(destModel->cm, currentModel->cm, true); - for (const std::string& tex: destModel->cm.textures) { + for (const std::string& tex : destModel->cm.textures) { destModel->addTexture(tex, currentModel->getTexture(tex)); } - if(par.getBool("DeleteOriginal")) // delete original faces - { + if (par.getBool("DeleteOriginal")) { // delete original faces CMeshO::VertexIterator vi; CMeshO::FaceIterator fi; tri::UpdateSelection::VertexClear(currentModel->cm); tri::UpdateSelection::VertexFromFaceStrict(currentModel->cm); for (fi = currentModel->cm.face.begin(); fi != currentModel->cm.face.end(); ++fi) - if(!(*fi).IsD() && (*fi).IsS() ) + if (!(*fi).IsD() && (*fi).IsS()) tri::Allocator::DeleteFace(currentModel->cm, *fi); for (vi = currentModel->cm.vert.begin(); vi != currentModel->cm.vert.end(); ++vi) - if(!(*vi).IsD() && (*vi).IsS() ) + if (!(*vi).IsD() && (*vi).IsS()) tri::Allocator::DeleteVertex(currentModel->cm, *vi); tri::UpdateSelection::VertexClear(currentModel->cm); tri::UpdateSelection::FaceClear(currentModel->cm); currentModel->clearDataMask(MeshModel::MM_FACEFACETOPO); - log("Moved %i faces and %i vertices to layer %i", numFacesSel, numVertSel, currentModel->id()); + log("Moved %i faces and %i vertices to layer %i", + numFacesSel, + numVertSel, + currentModel->id()); } - else // keep original faces - { - log("Copied %i faces and %i vertices to layer %i", numFacesSel, numVertSel, currentModel->id()); + else { // keep original faces + log("Copied %i faces and %i vertices to layer %i", + numFacesSel, + numVertSel, + currentModel->id()); } vcg::tri::UpdateFlags::VertexClear(destModel->cm, CMeshO::VertexType::SELECTED); vcg::tri::UpdateFlags::FaceClear(destModel->cm, CMeshO::FaceType::SELECTED); @@ -354,15 +396,17 @@ std::map FilterLayerPlugin::applyFilter( destModel->updateDataMask(currentModel); } break; - case FP_DUPLICATE : - { - MeshModel *currentModel = md.mm(); // source = current - QString newName = currentModel->label() + "_copy"; - MeshModel *destModel = md.addNewMesh("", newName, true); // After Adding a mesh to a MeshDocument the new mesh is the current one + case FP_DUPLICATE: { + MeshModel* currentModel = md.mm(); // source = current + QString newName = currentModel->label() + "_copy"; + MeshModel* destModel = md.addNewMesh( + "", + newName, + true); // After Adding a mesh to a MeshDocument the new mesh is the current one destModel->updateDataMask(currentModel); tri::Append::Mesh(destModel->cm, currentModel->cm); - for (const std::string& tex: destModel->cm.textures) { + for (const std::string& tex : destModel->cm.textures) { destModel->addTexture(tex, currentModel->getTexture(tex)); } @@ -373,78 +417,75 @@ std::map FilterLayerPlugin::applyFilter( destModel->cm.Tr = currentModel->cm.Tr; } break; - case FP_FLATTEN : - { - bool deleteLayer = par.getBool("DeleteLayer"); - bool mergeVisible = par.getBool("MergeVisible"); - bool mergeVertices = par.getBool("MergeVertices"); + case FP_FLATTEN: { + bool deleteLayer = par.getBool("DeleteLayer"); + bool mergeVisible = par.getBool("MergeVisible"); + bool mergeVertices = par.getBool("MergeVertices"); bool alsoUnreferenced = par.getBool("AlsoUnreferenced"); - MeshModel *destModel = md.addNewMesh("", "Merged Mesh", true); + MeshModel* destModel = md.addNewMesh("", "Merged Mesh", true); std::list toBeDeletedList; - unsigned int cnt=0; - for(MeshModel& mmp: md.meshIterator()) { + unsigned int cnt = 0; + for (MeshModel& mmp : md.meshIterator()) { ++cnt; - if(mmp.isVisible() || !mergeVisible) { + if (mmp.isVisible() || !mergeVisible) { if (mmp.id() != destModel->id()) { - cb(cnt*100/md.meshNumber(), "Merging layers..."); + cb(cnt * 100 / md.meshNumber(), "Merging layers..."); tri::UpdatePosition::Matrix(mmp.cm, mmp.cm.Tr, true); toBeDeletedList.push_back(mmp.id()); - if(!alsoUnreferenced) { + if (!alsoUnreferenced) { vcg::tri::Clean::RemoveUnreferencedVertex(mmp.cm); } destModel->updateDataMask(&mmp); tri::Append::Mesh(destModel->cm, mmp.cm); - for (const std::string& txt : mmp.cm.textures){ + for (const std::string& txt : mmp.cm.textures) { destModel->addTexture(txt, mmp.getTexture(txt)); } - tri::UpdatePosition::Matrix(mmp.cm,Inverse(mmp.cm.Tr),true); + tri::UpdatePosition::Matrix(mmp.cm, Inverse(mmp.cm.Tr), true); } } } - if( deleteLayer ) { - log( "Deleted %d merged layers", toBeDeletedList.size()); + if (deleteLayer) { + log("Deleted %d merged layers", toBeDeletedList.size()); for (unsigned int id : toBeDeletedList) md.delMesh(id); md.setCurrent(destModel); // setting again newly created model as current } - - if( mergeVertices ) { + + if (mergeVertices) { int delvert = tri::Clean::RemoveDuplicateVertex(destModel->cm); - log( "Removed %d duplicated vertices", delvert); + log("Removed %d duplicated vertices", delvert); } destModel->updateBoxAndNormals(); - log("Merged all the layers to single mesh of %i vertices",md.mm()->cm.vn); + log("Merged all the layers to single mesh of %i vertices", md.mm()->cm.vn); } break; - case FP_SPLITCONNECTED : - { - MeshModel *currentModel = md.mm(); - CMeshO &cm = md.mm()->cm; + case FP_SPLITCONNECTED: { + MeshModel* currentModel = md.mm(); + CMeshO& cm = md.mm()->cm; md.mm()->updateDataMask(MeshModel::MM_FACEFACETOPO); - std::vector< std::pair > connectedCompVec; + std::vector> connectedCompVec; int numCC = tri::Clean::ConnectedComponents(cm, connectedCompVec); - log("Found %i Connected Components",numCC); - - for(size_t i=0; i::FaceClear(cm); connectedCompVec[i].second->SetS(); - tri::UpdateSelection::FaceConnectedFF(cm/*,true*/); + tri::UpdateSelection::FaceConnectedFF(cm /*,true*/); tri::UpdateSelection::VertexClear(cm); tri::UpdateSelection::VertexFromFaceLoose(cm); - MeshModel *destModel= md.addNewMesh("",QString("CC %1").arg(i), true); + MeshModel* destModel = md.addNewMesh("", QString("CC %1").arg(i), true); destModel->updateDataMask(currentModel); tri::Append::Mesh(destModel->cm, cm, true); - for (const std::string& txt : cm.textures){ + for (const std::string& txt : cm.textures) { destModel->addTexture(txt, md.mm()->getTexture(txt)); } @@ -454,20 +495,18 @@ std::map FilterLayerPlugin::applyFilter( } } break; - case FP_EXPORT_CAMERAS: - { - int output = par.getEnum("ExportFile"); - QString name = par.getString("newName"); + case FP_EXPORT_CAMERAS: { + int output = par.getEnum("ExportFile"); + QString name = par.getString("newName"); - if (output ==0) - { + if (output == 0) { FILE* outfile = NULL; - - name=name.append(".out"); + + name = name.append(".out"); outfile = fopen(name.toStdString().c_str(), "wb"); - if (outfile == NULL){ - throw MLException("Impossible to open file " + name); + if (outfile == NULL) { + throw MLException("Impossible to open file " + name); } int active = 0; @@ -481,7 +520,12 @@ std::map FilterLayerPlugin::applyFilter( for (const RasterModel& rm : md.rasterIterator()) { if (rm.isVisible()) { - fprintf(outfile, "%f %d %d\n", rm.shot.Intrinsics.FocalMm / rm.shot.Intrinsics.PixelSizeMm[0], 0, 0); + fprintf( + outfile, + "%f %d %d\n", + rm.shot.Intrinsics.FocalMm / rm.shot.Intrinsics.PixelSizeMm[0], + 0, + 0); Matrix44m mat = rm.shot.Extrinsics.Rot(); @@ -494,22 +538,19 @@ std::map FilterLayerPlugin::applyFilter( fprintf(outfile, "%f %f %f\n", Rt[0][1], Rt[1][1], Rt[2][1]); fprintf(outfile, "%f %f %f\n", Rt[0][2], Rt[1][2], Rt[2][2]); fprintf(outfile, "%f %f %f\n", -pos[0], -pos[1], -pos[2]); - } - } - fprintf(outfile, "%d %d %d\n", 0, 0,0); + fprintf(outfile, "%d %d %d\n", 0, 0, 0); fclose(outfile); - } - else if (output==1) { + else if (output == 1) { name = name.append(".xml"); - + QFileInfo fi(name); - QDir tmpDir = QDir::current(); + QDir tmpDir = QDir::current(); QDir::setCurrent(fi.absoluteDir().absolutePath()); - //QDomDocument doc("AgisoftXML"); + // QDomDocument doc("AgisoftXML"); QFile file(name); file.open(QIODevice::WriteOnly); @@ -522,29 +563,31 @@ std::map FilterLayerPlugin::applyFilter( xmlWriter.writeStartElement("chunk"); xmlWriter.writeStartElement("sensors"); - + unsigned int i = 0; for (const RasterModel& rm : md.rasterIterator()) { if (rm.isVisible()) { float focal, pixelX, pixelY; if (rm.shot.Intrinsics.FocalMm > 1000) { - focal = rm.shot.Intrinsics.FocalMm / 500; + focal = rm.shot.Intrinsics.FocalMm / 500; pixelX = rm.shot.Intrinsics.PixelSizeMm[0] / 500; pixelY = rm.shot.Intrinsics.PixelSizeMm[1] / 500; } else { - focal = rm.shot.Intrinsics.FocalMm; + focal = rm.shot.Intrinsics.FocalMm; pixelX = rm.shot.Intrinsics.PixelSizeMm[0]; pixelY = rm.shot.Intrinsics.PixelSizeMm[1]; } xmlWriter.writeStartElement("sensor"); xmlWriter.writeAttribute("id", QString::number(i)); - xmlWriter.writeAttribute("label", "unknown"+QString::number(i)); + xmlWriter.writeAttribute("label", "unknown" + QString::number(i)); xmlWriter.writeAttribute("type", "frame"); xmlWriter.writeStartElement("resolution"); - xmlWriter.writeAttribute("width", QString::number(rm.shot.Intrinsics.ViewportPx[0])); - xmlWriter.writeAttribute("height", QString::number(rm.shot.Intrinsics.ViewportPx[1])); + xmlWriter.writeAttribute( + "width", QString::number(rm.shot.Intrinsics.ViewportPx[0])); + xmlWriter.writeAttribute( + "height", QString::number(rm.shot.Intrinsics.ViewportPx[1])); xmlWriter.writeEndElement(); xmlWriter.writeStartElement("property"); xmlWriter.writeAttribute("name", "pixel_width"); @@ -566,13 +609,23 @@ std::map FilterLayerPlugin::applyFilter( xmlWriter.writeAttribute("type", "frame"); xmlWriter.writeAttribute("class", "adjusted"); xmlWriter.writeStartElement("resolution"); - xmlWriter.writeAttribute("width", QString::number(rm.shot.Intrinsics.ViewportPx[0])); - xmlWriter.writeAttribute("height", QString::number(rm.shot.Intrinsics.ViewportPx[1])); + xmlWriter.writeAttribute( + "width", QString::number(rm.shot.Intrinsics.ViewportPx[0])); + xmlWriter.writeAttribute( + "height", QString::number(rm.shot.Intrinsics.ViewportPx[1])); xmlWriter.writeEndElement(); - xmlWriter.writeTextElement("fx", QString::number(rm.shot.Intrinsics.FocalMm / rm.shot.Intrinsics.PixelSizeMm[0])); - xmlWriter.writeTextElement("fy", QString::number(rm.shot.Intrinsics.FocalMm / rm.shot.Intrinsics.PixelSizeMm[1])); - xmlWriter.writeTextElement("cx", QString::number(rm.shot.Intrinsics.CenterPx[0])); - xmlWriter.writeTextElement("cy", QString::number(rm.shot.Intrinsics.CenterPx[1])); + xmlWriter.writeTextElement( + "fx", + QString::number( + rm.shot.Intrinsics.FocalMm / rm.shot.Intrinsics.PixelSizeMm[0])); + xmlWriter.writeTextElement( + "fy", + QString::number( + rm.shot.Intrinsics.FocalMm / rm.shot.Intrinsics.PixelSizeMm[1])); + xmlWriter.writeTextElement( + "cx", QString::number(rm.shot.Intrinsics.CenterPx[0])); + xmlWriter.writeTextElement( + "cy", QString::number(rm.shot.Intrinsics.CenterPx[1])); xmlWriter.writeTextElement("k1", "0"); xmlWriter.writeTextElement("k2", "0"); xmlWriter.writeTextElement("p1", "0"); @@ -592,9 +645,9 @@ std::map FilterLayerPlugin::applyFilter( xmlWriter.writeAttribute("label", rm.currentPlane->shortName()); xmlWriter.writeAttribute("sensor_id", QString::number(i)); xmlWriter.writeAttribute("enabled", "true"); - Matrix44m mat = rm.shot.Extrinsics.Rot(); - Point3f pos = rm.shot.Extrinsics.Tra(); - QString transform= QString::number(mat[0][0]); + Matrix44m mat = rm.shot.Extrinsics.Rot(); + Point3f pos = rm.shot.Extrinsics.Tra(); + QString transform = QString::number(mat[0][0]); transform.append(" " + QString::number(-mat[1][0])); transform.append(" " + QString::number(-mat[2][0])); transform.append(" " + QString::number(pos[0])); @@ -610,7 +663,7 @@ std::map FilterLayerPlugin::applyFilter( transform.append(" 0"); transform.append(" 0"); transform.append(" 1"); - + xmlWriter.writeTextElement("transform", transform); xmlWriter.writeEndElement(); } @@ -624,19 +677,16 @@ std::map FilterLayerPlugin::applyFilter( } } break; - case FP_IMPORT_CAMERAS: - { + case FP_IMPORT_CAMERAS: { QString fileName = par.getOpenFileName("ImportFile"); - if (fileName.isEmpty()) - { + if (fileName.isEmpty()) { throw MLException("No file to open"); } QFileInfo fi(fileName); - - if ((fi.suffix().toLower() == "out")) - { - unsigned int num_cams, num_points; - FILE *fp = fopen(qUtf8Printable(fileName), "r"); + + if ((fi.suffix().toLower() == "out")) { + unsigned int num_cams, num_points; + FILE* fp = fopen(qUtf8Printable(fileName), "r"); if (!fp) { throw MLException("Impossible to open file " + fileName); } @@ -645,13 +695,16 @@ std::map FilterLayerPlugin::applyFilter( char line[100]; fgets(line, 100, fp); - if (line[0] == '\0') throw MLException("Error while parsing " + fileName); + if (line[0] == '\0') + throw MLException("Error while parsing " + fileName); line[18] = '\0'; - if (0 != strcmp("# Bundle file v0.3", line)) throw MLException("Error while parsing " + fileName); + if (0 != strcmp("# Bundle file v0.3", line)) + throw MLException("Error while parsing " + fileName); fgets(line, 100, fp); - if (line[0] == '\0') throw MLException("Error while parsing " + fileName); + if (line[0] == '\0') + throw MLException("Error while parsing " + fileName); sscanf(line, "%d %d", &num_cams, &num_points); - + ///// Check if the number of active rasters and cameras is the same unsigned active = 0; for (RasterModel& rm : md.rasterIterator()) { @@ -660,28 +713,43 @@ std::map FilterLayerPlugin::applyFilter( } if (active != num_cams) { - throw MLException("Wait! The number of active rasters and the number of cams in the Bundler file is not the same!"); + throw MLException( + "Wait! The number of active rasters and the number of cams in the Bundler file " + "is not the same!"); } //// Import cameras unsigned int i = 0; for (RasterModel& rm : md.rasterIterator()) { if (rm.isVisible()) { - float f, k1, k2; - float R[16] = { 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,1 }; + float f, k1, k2; + float R[16] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1}; vcg::Point3f t; - fgets(line, 100, fp);; if (line[0] == '\0') throw MLException("Error while parsing " + fileName);; + fgets(line, 100, fp); + if (line[0] == '\0') + throw MLException("Error while parsing " + fileName); sscanf(line, "%f %f %f", &f, &k1, &k2); - fgets(line, 100, fp);; if (line[0] == '\0') throw MLException("Error while parsing " + fileName);; - sscanf(line, "%f %f %f", &(R[0]), &(R[1]), &(R[2])); R[3] = 0; - fgets(line, 100, fp);; if (line[0] == '\0') throw MLException("Error while parsing " + fileName);; - sscanf(line, "%f %f %f", &(R[4]), &(R[5]), &(R[6])); R[7] = 0; - fgets(line, 100, fp);; if (line[0] == '\0') throw MLException("Error while parsing " + fileName);; - sscanf(line, "%f %f %f", &(R[8]), &(R[9]), &(R[10])); R[11] = 0; + fgets(line, 100, fp); + if (line[0] == '\0') + throw MLException("Error while parsing " + fileName); + sscanf(line, "%f %f %f", &(R[0]), &(R[1]), &(R[2])); + R[3] = 0; + fgets(line, 100, fp); + if (line[0] == '\0') + throw MLException("Error while parsing " + fileName); + sscanf(line, "%f %f %f", &(R[4]), &(R[5]), &(R[6])); + R[7] = 0; + fgets(line, 100, fp); + if (line[0] == '\0') + throw MLException("Error while parsing " + fileName); + sscanf(line, "%f %f %f", &(R[8]), &(R[9]), &(R[10])); + R[11] = 0; - fgets(line, 100, fp);; if (line[0] == '\0') throw MLException("Error while parsing " + fileName);; + fgets(line, 100, fp); + if (line[0] == '\0') + throw MLException("Error while parsing " + fileName); sscanf(line, "%f %f %f", &(t[0]), &(t[1]), &(t[2])); Matrix44f matF(R); @@ -697,25 +765,28 @@ std::map FilterLayerPlugin::applyFilter( rm.shot.Extrinsics.SetRot(mat); rm.shot.Intrinsics.FocalMm = f; - rm.shot.Intrinsics.k[0] = 0.0;//k1; To be uncommented when distortion is taken into account reliably - rm.shot.Intrinsics.k[1] = 0.0;//k2; + rm.shot.Intrinsics.k[0] = + 0.0; // k1; To be uncommented when distortion is taken into account reliably + rm.shot.Intrinsics.k[1] = 0.0; // k2; rm.shot.Intrinsics.PixelSizeMm = vcg::Point2f(1, 1); - QSize size; + QSize size; QImageReader sizeImg(rm.currentPlane->fullPathFileName); - size = sizeImg.size(); + size = sizeImg.size(); rm.shot.Intrinsics.ViewportPx = vcg::Point2i(size.width(), size.height()); - rm.shot.Intrinsics.CenterPx[0] = (int)((double)rm.shot.Intrinsics.ViewportPx[0] / 2.0f); - rm.shot.Intrinsics.CenterPx[1] = (int)((double)rm.shot.Intrinsics.ViewportPx[1] / 2.0f); + rm.shot.Intrinsics.CenterPx[0] = + (int) ((double) rm.shot.Intrinsics.ViewportPx[0] / 2.0f); + rm.shot.Intrinsics.CenterPx[1] = + (int) ((double) rm.shot.Intrinsics.ViewportPx[1] / 2.0f); } ++i; } } else if ((fi.suffix().toLower() == "xml")) { QDomDocument doc; - QFile file(fileName); + QFile file(fileName); if (!file.open(QIODevice::ReadOnly) || !doc.setContent(&file)) - throw MLException("Error while opening " + fileName);; - std::vector shots; + throw MLException("Error while opening " + fileName); + std::vector shots; ////// Read and store sensors list QDomNodeList sensors = doc.elementsByTagName("sensor"); @@ -726,50 +797,52 @@ std::map FilterLayerPlugin::applyFilter( shots.resize(sensors.size()); for (int i = 0; i < sensors.size(); i++) { - QDomNode n = sensors.item(i); - int id = n.attributes().namedItem("id").nodeValue().toInt(); + QDomNode n = sensors.item(i); + int id = n.attributes().namedItem("id").nodeValue().toInt(); QDomNode node = n.firstChild(); - //Devices + // Devices while (!node.isNull()) { if (QString::compare(node.nodeName(), "calibration") == 0) { QDomNode node1 = node.firstChild(); - //Devices + // Devices while (!node1.isNull()) { if (QString::compare(node1.nodeName(), "resolution") == 0) { - int width = node1.attributes().namedItem("width").nodeValue().toInt(); - int height = node1.attributes().namedItem("height").nodeValue().toInt(); + int width = + node1.attributes().namedItem("width").nodeValue().toInt(); + int height = + node1.attributes().namedItem("height").nodeValue().toInt(); shots[id].Intrinsics.ViewportPx[0] = width; shots[id].Intrinsics.ViewportPx[1] = height; - shots[id].Intrinsics.CenterPx[0] = (float)width / 2.0f; - shots[id].Intrinsics.CenterPx[1] = (float)height / 2.0f; - //Log("Width %f, Height %f", shots[id].Intrinsics.CenterPx[0], shots[id].Intrinsics.CenterPx[1]); + shots[id].Intrinsics.CenterPx[0] = (float) width / 2.0f; + shots[id].Intrinsics.CenterPx[1] = (float) height / 2.0f; + // Log("Width %f, Height %f", shots[id].Intrinsics.CenterPx[0], + // shots[id].Intrinsics.CenterPx[1]); } else if (QString::compare(node1.nodeName(), "fx") == 0) { float fx = node1.toElement().text().toFloat(); if (fx > 100) { - fx = fx / 100; - shots[id].Intrinsics.FocalMm = fx; + fx = fx / 100; + shots[id].Intrinsics.FocalMm = fx; shots[id].Intrinsics.PixelSizeMm[0] = 0.01f; shots[id].Intrinsics.PixelSizeMm[1] = 0.01f; } else { - shots[id].Intrinsics.FocalMm = fx; + shots[id].Intrinsics.FocalMm = fx; shots[id].Intrinsics.PixelSizeMm[0] = 1; shots[id].Intrinsics.PixelSizeMm[1] = 1; } - //Log("Focal %f", fx); + // Log("Focal %f", fx); } else if (QString::compare(node1.nodeName(), "k1") == 0) { float k1 = node1.toElement().text().toFloat(); if (k1 != 0.0f) { - log("Warning! Distortion parameters won't be imported! Please undistort the images in Photoscan before!"); // text + log("Warning! Distortion parameters won't be imported! Please " + "undistort the images in Photoscan before!"); // text } - } node1 = node1.nextSibling(); } - } node = node.nextSibling(); } @@ -784,9 +857,9 @@ std::map FilterLayerPlugin::applyFilter( for (int i = 0; i < cameras.size(); i++) { QDomNode n = cameras.item(i); - //int id = n.attributes().namedItem("id").nodeValue().toInt(); - int sensor_id = n.attributes().namedItem("sensor_id").nodeValue().toInt(); - QString name = n.attributes().namedItem("label").nodeValue(); + // int id = n.attributes().namedItem("id").nodeValue().toInt(); + int sensor_id = n.attributes().namedItem("sensor_id").nodeValue().toInt(); + QString name = n.attributes().namedItem("label").nodeValue(); RasterModel* rasterId = nullptr; for (RasterModel& rm : md.rasterIterator()) { @@ -797,33 +870,40 @@ std::map FilterLayerPlugin::applyFilter( } QDomNode node = n.firstChild(); - + while (!node.isNull() && rasterId != nullptr) { if (QString::compare(node.nodeName(), "transform") == 0) { rasterId->shot.Intrinsics.FocalMm = shots[sensor_id].Intrinsics.FocalMm; - rasterId->shot.Intrinsics.ViewportPx[0] = shots[sensor_id].Intrinsics.ViewportPx[0]; - rasterId->shot.Intrinsics.ViewportPx[1] = shots[sensor_id].Intrinsics.ViewportPx[1]; - rasterId->shot.Intrinsics.CenterPx[0] = shots[sensor_id].Intrinsics.CenterPx[0]; - rasterId->shot.Intrinsics.CenterPx[1] = shots[sensor_id].Intrinsics.CenterPx[1]; - rasterId->shot.Intrinsics.PixelSizeMm[0] = shots[sensor_id].Intrinsics.PixelSizeMm[0]; - rasterId->shot.Intrinsics.PixelSizeMm[1] = shots[sensor_id].Intrinsics.PixelSizeMm[1]; + rasterId->shot.Intrinsics.ViewportPx[0] = + shots[sensor_id].Intrinsics.ViewportPx[0]; + rasterId->shot.Intrinsics.ViewportPx[1] = + shots[sensor_id].Intrinsics.ViewportPx[1]; + rasterId->shot.Intrinsics.CenterPx[0] = + shots[sensor_id].Intrinsics.CenterPx[0]; + rasterId->shot.Intrinsics.CenterPx[1] = + shots[sensor_id].Intrinsics.CenterPx[1]; + rasterId->shot.Intrinsics.PixelSizeMm[0] = + shots[sensor_id].Intrinsics.PixelSizeMm[0]; + rasterId->shot.Intrinsics.PixelSizeMm[1] = + shots[sensor_id].Intrinsics.PixelSizeMm[1]; - QStringList values = node.toElement().text().split(" ", QString::SkipEmptyParts); + QStringList values = + node.toElement().text().split(" ", QString::SkipEmptyParts); Matrix44m mat = rasterId->shot.Extrinsics.Rot(); - Point3f pos = rasterId->shot.Extrinsics.Tra(); - + Point3f pos = rasterId->shot.Extrinsics.Tra(); + mat[0][0] = values[0].toFloat(); mat[1][0] = -values[1].toFloat(); mat[2][0] = -values[2].toFloat(); - pos[0] = values[3].toFloat(); + pos[0] = values[3].toFloat(); mat[0][1] = values[4].toFloat(); mat[1][1] = -values[5].toFloat(); mat[2][1] = -values[6].toFloat(); - pos[1] = values[7].toFloat(); + pos[1] = values[7].toFloat(); mat[0][2] = values[8].toFloat(); mat[1][2] = -values[9].toFloat(); mat[2][2] = -values[10].toFloat(); - pos[2] = values[11].toFloat(); + pos[2] = values[11].toFloat(); rasterId->shot.Extrinsics.SetRot(mat); rasterId->shot.Extrinsics.SetTra(pos); } @@ -836,70 +916,60 @@ std::map FilterLayerPlugin::applyFilter( throw MLException("Unknown file type"); } } break; - default: - wrongActionCalled(filter); + default: wrongActionCalled(filter); } // end case return std::map(); } -FilterLayerPlugin::FilterClass FilterLayerPlugin::getClass(const QAction *a) const +FilterLayerPlugin::FilterClass FilterLayerPlugin::getClass(const QAction* a) const { - switch(ID(a)) - { - case FP_RENAME_MESH : - case FP_SPLITSELECTEDFACES : + switch (ID(a)) { + case FP_RENAME_MESH: + case FP_SPLITSELECTEDFACES: case FP_SPLITSELECTEDVERTICES: - case FP_DUPLICATE : - case FP_FLATTEN : - case FP_SELECTCURRENT : - case FP_MESH_VISIBILITY : - case FP_SPLITCONNECTED : - case FP_DELETE_MESH : - case FP_DELETE_NON_VISIBLE_MESH : return FilterPlugin::Layer; - case FP_RENAME_RASTER : - case FP_DELETE_RASTER : - case FP_DELETE_NON_SELECTED_RASTER : - case FP_EXPORT_CAMERAS: return FilterPlugin::RasterLayer; - case FP_IMPORT_CAMERAS: return FilterClass(FilterPlugin::Camera + FilterPlugin::RasterLayer); - default : assert(0); + case FP_DUPLICATE: + case FP_FLATTEN: + case FP_MESH_VISIBILITY: + case FP_SPLITCONNECTED: + case FP_DELETE_MESH: + case FP_DELETE_NON_VISIBLE_MESH: return FilterPlugin::Layer; + case FP_RENAME_RASTER: + case FP_DELETE_RASTER: + case FP_DELETE_NON_SELECTED_RASTER: + case FP_EXPORT_CAMERAS: return FilterPlugin::RasterLayer; + case FP_IMPORT_CAMERAS: return FilterClass(FilterPlugin::Camera + FilterPlugin::RasterLayer); + default: assert(0); } return FilterPlugin::Generic; } FilterPlugin::FilterArity FilterLayerPlugin::filterArity(const QAction* filter) const { - switch(ID(filter)) - { - case FP_RENAME_MESH : + switch (ID(filter)) { + case FP_RENAME_MESH: case FP_MESH_VISIBILITY: - case FP_SPLITSELECTEDFACES : + case FP_SPLITSELECTEDFACES: case FP_SPLITSELECTEDVERTICES: - case FP_DUPLICATE : - case FP_SELECTCURRENT : - case FP_SPLITCONNECTED : - case FP_DELETE_MESH : - return FilterPlugin::SINGLE_MESH; - case FP_RENAME_RASTER : - case FP_DELETE_RASTER : - case FP_DELETE_NON_SELECTED_RASTER : + case FP_DUPLICATE: + case FP_SPLITCONNECTED: + case FP_DELETE_MESH: return FilterPlugin::SINGLE_MESH; + case FP_RENAME_RASTER: + case FP_DELETE_RASTER: + case FP_DELETE_NON_SELECTED_RASTER: case FP_EXPORT_CAMERAS: - case FP_IMPORT_CAMERAS: - return FilterPlugin::NONE; - case FP_FLATTEN : - case FP_DELETE_NON_VISIBLE_MESH : - return FilterPlugin::VARIABLE; + case FP_IMPORT_CAMERAS: return FilterPlugin::NONE; + case FP_FLATTEN: + case FP_DELETE_NON_VISIBLE_MESH: return FilterPlugin::VARIABLE; } return FilterPlugin::NONE; } int FilterLayerPlugin::postCondition(const QAction* filter) const { - switch (ID(filter)) - { + switch (ID(filter)) { case FP_RENAME_MESH: case FP_DUPLICATE: - case FP_SELECTCURRENT: case FP_DELETE_MESH: case FP_DELETE_NON_VISIBLE_MESH: case FP_FLATTEN: @@ -909,12 +979,12 @@ int FilterLayerPlugin::postCondition(const QAction* filter) const case FP_EXPORT_CAMERAS: case FP_IMPORT_CAMERAS: case FP_SPLITCONNECTED: - case FP_MESH_VISIBILITY: return MeshModel::MM_NONE; + case FP_MESH_VISIBILITY: return MeshModel::MM_NONE; case FP_SPLITSELECTEDFACES: - case FP_SPLITSELECTEDVERTICES: return MeshModel::MM_GEOMETRY_AND_TOPOLOGY_CHANGE; + case FP_SPLITSELECTEDVERTICES: return MeshModel::MM_GEOMETRY_AND_TOPOLOGY_CHANGE; - default: assert(0); + default: assert(0); } return FilterPlugin::Generic; } diff --git a/src/meshlabplugins/filter_layer/filter_layer.h b/src/meshlabplugins/filter_layer/filter_layer.h index 17e1ef666..29c5d1ffa 100644 --- a/src/meshlabplugins/filter_layer/filter_layer.h +++ b/src/meshlabplugins/filter_layer/filter_layer.h @@ -1,25 +1,25 @@ -/**************************************************************************** -* MeshLab o o * -* A versatile mesh processing toolbox o o * -* _ O _ * -* Copyright(C) 2005 \/)\/ * -* 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. * -* * -****************************************************************************/ +/***************************************************************************** + * 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 FILTER_SPLITTER_H #define FILTER_SPLITTER_H @@ -48,24 +48,24 @@ public: FP_DELETE_NON_VISIBLE_MESH, FP_DELETE_RASTER, FP_DELETE_NON_SELECTED_RASTER, - FP_SELECTCURRENT, FP_EXPORT_CAMERAS, FP_IMPORT_CAMERAS }; FilterLayerPlugin(); - QString pluginName() const; - QString filterName(ActionIDType filter) const; - QString filterInfo(ActionIDType filter) const; - FilterClass getClass(const QAction*) const; - RichParameterList initParameterList(const QAction*, const MeshDocument &/*m*/); + QString pluginName() const; + QString filterName(ActionIDType filter) const; + QString filterInfo(ActionIDType filter) const; + FilterClass getClass(const QAction*) const; + RichParameterList initParameterList(const QAction*, const MeshDocument& /*m*/); std::map applyFilter( - const QAction* action, - const RichParameterList & parameters, - MeshDocument &md, - unsigned int& postConditionMask, - vcg::CallBackPos * cb); int postCondition(const QAction *filter) const; + const QAction* action, + const RichParameterList& parameters, + MeshDocument& md, + unsigned int& postConditionMask, + vcg::CallBackPos* cb); + int postCondition(const QAction* filter) const; FilterArity filterArity(const QAction*) const; }; From 76fa9700c08e89b78f0899af2ee4a0610c61a7c8 Mon Sep 17 00:00:00 2001 From: alemuntoni Date: Wed, 22 Sep 2021 17:30:36 +0200 Subject: [PATCH 05/10] remove "select folded faces" filter --- .../filter_select/meshselect.cpp | 23 +------------------ src/meshlabplugins/filter_select/meshselect.h | 1 - 2 files changed, 1 insertion(+), 23 deletions(-) diff --git a/src/meshlabplugins/filter_select/meshselect.cpp b/src/meshlabplugins/filter_select/meshselect.cpp index 65ebe9a79..0f9d1db33 100644 --- a/src/meshlabplugins/filter_select/meshselect.cpp +++ b/src/meshlabplugins/filter_select/meshselect.cpp @@ -64,7 +64,6 @@ SelectionFilterPlugin::SelectionFilterPlugin() CP_SELECT_NON_MANIFOLD_VERTEX, FP_SELECT_FACES_BY_EDGE, FP_SELECT_BY_COLOR, - FP_SELECT_FOLD_FACE, FP_SELECT_OUTLIER }; @@ -150,7 +149,6 @@ QString SelectionFilterPlugin::filterName(ActionIDType filter) const case CP_SELECT_NON_MANIFOLD_FACE : return tr("Select non Manifold Edges"); case CP_SELECT_NON_MANIFOLD_VERTEX : return tr("Select non Manifold Vertices"); case FP_SELECT_FACES_BY_EDGE: return tr("Select Faces with edges longer than..."); - case FP_SELECT_FOLD_FACE : return tr("Select Folded Faces"); case FP_SELECT_OUTLIER: return tr("Select Outliers"); } assert(0); @@ -184,8 +182,7 @@ QString SelectionFilterPlugin::filterInfo(ActionIDType filterId) const case CP_SELECT_TEXBORDER : return tr("Colorize only border edges."); case CP_SELECT_NON_MANIFOLD_FACE: return tr("Select the faces and the vertices incident on non manifold edges (e.g. edges where more than two faces are incident); note that this function select the components that are related to non manifold edges. The case of non manifold vertices is specifically managed by the pertinent filter."); case CP_SELECT_NON_MANIFOLD_VERTEX: return tr("Select the non manifold vertices that do not belong to non manifold edges. For example two cones connected by their apex. Vertices incident on non manifold edges are ignored."); - case FP_SELECT_FOLD_FACE: return tr("Select the folded faces created by the Quadric Edge Collapse decimation. The face is selected if the angle between the face normal and the normal of the best fitting plane of the neighbor vertices is above the selected threshold."); - case FP_SELECT_OUTLIER: return tr("Select the vertex classified as outlier using Local Outlier Propabilty measure described in:
'LoOP: Local Outlier Probabilities' Kriegel et al.
CIKM 2009"); + case FP_SELECT_OUTLIER: return tr("Select the vertex classified as outlier using Local Outlier Propabilty measure described in:
'LoOP: Local Outlier Probabilities' Kriegel et al.
CIKM 2009"); } assert(0); return QString("Unknown filter"); @@ -286,11 +283,6 @@ RichParameterList SelectionFilterPlugin::initParameterList(const QAction *action parlst.addParam(RichBool("InvVerts", defV, "Invert Vertices", "If true the filter will invert the set of selected vertices.")); } break; - case FP_SELECT_FOLD_FACE: - { - parlst.addParam(RichDynamicFloat("AngleThreshold", 160.0f, 90.0f, 180.0f, tr("Angle Threshold"), tr("Angle between the face and the best fitting plane of the neighbours vertices. If it is above the threshold the face is selected."))); - } break; - case FP_SELECT_OUTLIER: { parlst.addParam(RichDynamicFloat("PropThreshold", 0.8, 0.0, 1.0, tr("Probability"), tr("Threshold to select the vertex. The vertex is selected if the LoOP value is above the threshold."))); @@ -631,14 +623,6 @@ std::map SelectionFilterPlugin::applyFilter( log( "Selected %d faces with and edge longer than %f",selFaceNum,threshold); } break; - case FP_SELECT_FOLD_FACE: - { - Scalarm angle = math::ToRad(par.getDynamicFloat("AngleThreshold")); - m.updateDataMask(MeshModel::MM_VERTFACETOPO); - tri::Clean::SelectFoldedFaceFromOneRingFaces(m.cm, cos(angle)); - m.clearDataMask(MeshModel::MM_VERTFACETOPO); - } break; - case FP_SELECT_OUTLIER: { Scalarm threshold = par.getDynamicFloat("PropThreshold"); @@ -683,7 +667,6 @@ FilterPlugin::FilterClass SelectionFilterPlugin::getClass(const QAction *action) case FP_SELECT_BORDER: case FP_SELECT_INVERT: case FP_SELECT_FACES_BY_EDGE: - case FP_SELECT_FOLD_FACE: case FP_SELECT_OUTLIER: case FP_SELECT_BY_COLOR: case CP_SELECT_NON_MANIFOLD_VERTEX: @@ -703,8 +686,6 @@ FilterPlugin::FilterClass SelectionFilterPlugin::getClass(const QAction *action) case CP_SELECT_TEXBORDER: return MeshModel::MM_FACEFACETOPO; case CP_SELFINTERSECT_SELECT: return MeshModel::MM_FACEMARK | MeshModel::MM_FACEFACETOPO; - case FP_SELECT_FOLD_FACE: return MeshModel::MM_VERTFACETOPO; - default: return MeshModel::MM_NONE; } } @@ -731,7 +712,6 @@ int SelectionFilterPlugin::postCondition(const QAction *action) const case CP_SELECT_NON_MANIFOLD_VERTEX : case FP_SELECT_FACES_BY_EDGE : case FP_SELECT_UGLY : - case FP_SELECT_FOLD_FACE : case FP_SELECT_OUTLIER : return MeshModel::MM_VERTFLAGSELECT | MeshModel::MM_FACEFLAGSELECT; case FP_SELECT_DELETE_VERT : case FP_SELECT_DELETE_ALL_FACE : @@ -753,7 +733,6 @@ int SelectionFilterPlugin::getPreConditions(const QAction * action) const case FP_SELECT_BORDER: case FP_SELECT_ERODE: case FP_SELECT_DILATE: - case FP_SELECT_FOLD_FACE: case FP_SELECT_CONNECTED: return MeshModel::MM_FACENUMBER; case FP_SELECT_BY_COLOR: return MeshModel::MM_VERTCOLOR; case FP_SELECT_BY_VERT_QUALITY: return MeshModel::MM_VERTQUALITY; diff --git a/src/meshlabplugins/filter_select/meshselect.h b/src/meshlabplugins/filter_select/meshselect.h index 5b9611cd3..210ca9ce1 100644 --- a/src/meshlabplugins/filter_select/meshselect.h +++ b/src/meshlabplugins/filter_select/meshselect.h @@ -63,7 +63,6 @@ public: CP_SELECT_NON_MANIFOLD_FACE, CP_SELECT_NON_MANIFOLD_VERTEX, FP_SELECT_FACES_BY_EDGE, - FP_SELECT_FOLD_FACE, FP_SELECT_OUTLIER } ; From 3b015fefb6f8e5233faa43489be8f3206fe35888 Mon Sep 17 00:00:00 2001 From: alemuntoni Date: Thu, 23 Sep 2021 15:09:25 +0200 Subject: [PATCH 06/10] remove "vertex color noise" filter --- src/CMakeLists.txt | 1 - .../plugins_unsupported}/filter_sample_dyn/CMakeLists.txt | 0 .../plugins_unsupported}/filter_sample_dyn/filter_sample_dyn.cpp | 0 .../plugins_unsupported}/filter_sample_dyn/filter_sample_dyn.h | 0 4 files changed, 1 deletion(-) rename {src/meshlabplugins => unsupported/plugins_unsupported}/filter_sample_dyn/CMakeLists.txt (100%) rename {src/meshlabplugins => unsupported/plugins_unsupported}/filter_sample_dyn/filter_sample_dyn.cpp (100%) rename {src/meshlabplugins => unsupported/plugins_unsupported}/filter_sample_dyn/filter_sample_dyn.h (100%) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 558f6f87d..278e3dba9 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -152,7 +152,6 @@ if(NOT DEFINED MESHLAB_PLUGINS) # it may be already defined in parent directory # Filter plugins meshlabplugins/filter_sample - meshlabplugins/filter_sample_dyn meshlabplugins/filter_createiso meshlabplugins/filter_geodesic meshlabplugins/filter_sample_gpu diff --git a/src/meshlabplugins/filter_sample_dyn/CMakeLists.txt b/unsupported/plugins_unsupported/filter_sample_dyn/CMakeLists.txt similarity index 100% rename from src/meshlabplugins/filter_sample_dyn/CMakeLists.txt rename to unsupported/plugins_unsupported/filter_sample_dyn/CMakeLists.txt diff --git a/src/meshlabplugins/filter_sample_dyn/filter_sample_dyn.cpp b/unsupported/plugins_unsupported/filter_sample_dyn/filter_sample_dyn.cpp similarity index 100% rename from src/meshlabplugins/filter_sample_dyn/filter_sample_dyn.cpp rename to unsupported/plugins_unsupported/filter_sample_dyn/filter_sample_dyn.cpp diff --git a/src/meshlabplugins/filter_sample_dyn/filter_sample_dyn.h b/unsupported/plugins_unsupported/filter_sample_dyn/filter_sample_dyn.h similarity index 100% rename from src/meshlabplugins/filter_sample_dyn/filter_sample_dyn.h rename to unsupported/plugins_unsupported/filter_sample_dyn/filter_sample_dyn.h From bdb382459046482f5ce858de2df5d68305096a03 Mon Sep 17 00:00:00 2001 From: alemuntoni Date: Thu, 7 Oct 2021 14:52:48 +0200 Subject: [PATCH 07/10] refactor directional geom preserv filter, and add two more filters to add custom point attributes --- src/meshlab/layerDialog.cpp | 63 +- .../filter_func/filter_func.cpp | 2015 ++++++++++------- src/meshlabplugins/filter_func/filter_func.h | 145 +- .../filter_func/filter_refine.h | 1 + .../filter_unsharp/filter_unsharp.cpp | 1447 +++++++----- .../filter_unsharp/filter_unsharp.h | 93 +- 6 files changed, 2218 insertions(+), 1546 deletions(-) diff --git a/src/meshlab/layerDialog.cpp b/src/meshlab/layerDialog.cpp index a9d94bf29..f551a1a4a 100644 --- a/src/meshlab/layerDialog.cpp +++ b/src/meshlab/layerDialog.cpp @@ -740,47 +740,47 @@ void LayerDialog::adaptLayout(QTreeWidgetItem * item) //Add default annotations for each mesh about faces and vertices number void LayerDialog::addDefaultNotes(QTreeWidgetItem * parent, MeshModel *meshModel) { - QTreeWidgetItem *fileItem = new QTreeWidgetItem(); + QTreeWidgetItem* fileItem = new QTreeWidgetItem(); fileItem->setText(1, QString("File")); - if(!meshModel->fullName().isEmpty()) + if (!meshModel->fullName().isEmpty()) fileItem->setText(2, meshModel->shortName()); parent->addChild(fileItem); updateColumnNumber(fileItem); - QTreeWidgetItem *vertItem = new QTreeWidgetItem(); + QTreeWidgetItem* vertItem = new QTreeWidgetItem(); vertItem->setText(1, QString("Vertices")); vertItem->setText(2, QString::number(meshModel->cm.vn)); parent->addChild(vertItem); updateColumnNumber(vertItem); - if(meshModel->cm.en>0){ - QTreeWidgetItem *edgeItem = new QTreeWidgetItem(); + if (meshModel->cm.en > 0) { + QTreeWidgetItem* edgeItem = new QTreeWidgetItem(); edgeItem->setText(1, QString("Edges")); edgeItem->setText(2, QString::number(meshModel->cm.en)); parent->addChild(edgeItem); updateColumnNumber(edgeItem); } - QTreeWidgetItem *faceItem = new QTreeWidgetItem(); + QTreeWidgetItem* faceItem = new QTreeWidgetItem(); faceItem->setText(1, QString("Faces")); faceItem->setText(2, QString::number(meshModel->cm.fn)); parent->addChild(faceItem); updateColumnNumber(faceItem); std::vector vertScalarNames; - vcg::tri::Allocator::GetAllPerVertexAttribute< Scalarm >(meshModel->cm,vertScalarNames); + vcg::tri::Allocator::GetAllPerVertexAttribute(meshModel->cm, vertScalarNames); std::vector vertPointNames; - vcg::tri::Allocator::GetAllPerVertexAttribute< Point3m >(meshModel->cm,vertPointNames); + vcg::tri::Allocator::GetAllPerVertexAttribute(meshModel->cm, vertPointNames); std::vector faceScalarNames; - vcg::tri::Allocator::GetAllPerFaceAttribute< Scalarm >(meshModel->cm,faceScalarNames); + vcg::tri::Allocator::GetAllPerFaceAttribute(meshModel->cm, faceScalarNames); std::vector facePointNames; - vcg::tri::Allocator::GetAllPerFaceAttribute< Point3m >(meshModel->cm,facePointNames); + vcg::tri::Allocator::GetAllPerFaceAttribute(meshModel->cm, facePointNames); unsigned int totAttributes = vertScalarNames.size() + vertPointNames.size() + - faceScalarNames.size() + facePointNames.size(); - if (totAttributes > 0){ - QTreeWidgetItem *vertItem = new QTreeWidgetItem(); - QFont f; + faceScalarNames.size() + facePointNames.size(); + if (totAttributes > 0) { + QTreeWidgetItem* vertItem = new QTreeWidgetItem(); + QFont f; f.setBold(true); vertItem->setFont(1, f); vertItem->setText(1, QString("Custom Attrs:")); @@ -788,41 +788,41 @@ void LayerDialog::addDefaultNotes(QTreeWidgetItem * parent, MeshModel *meshModel updateColumnNumber(vertItem); } - for(const std::string& name: vertScalarNames) { - QTreeWidgetItem *vertItem = new QTreeWidgetItem(); + for (const std::string& name : vertScalarNames) { + QTreeWidgetItem* vertItem = new QTreeWidgetItem(); vertItem->setText(2, QString("Vert (scalar):")); vertItem->setText(3, QString(name.c_str())); parent->addChild(vertItem); updateColumnNumber(vertItem); } - for(const std::string& name: vertPointNames) { - QTreeWidgetItem *vertItem = new QTreeWidgetItem(); - vertItem->setText(2, QString("Vert (vec3):")); + for (const std::string& name : vertPointNames) { + QTreeWidgetItem* vertItem = new QTreeWidgetItem(); + vertItem->setText(2, QString("Vert (point):")); vertItem->setText(3, QString(name.c_str())); parent->addChild(vertItem); updateColumnNumber(vertItem); } - for(const std::string& name: faceScalarNames) { - QTreeWidgetItem *vertItem = new QTreeWidgetItem(); + for (const std::string& name : faceScalarNames) { + QTreeWidgetItem* vertItem = new QTreeWidgetItem(); vertItem->setText(2, QString("Face (scalar):")); vertItem->setText(3, QString(name.c_str())); parent->addChild(vertItem); updateColumnNumber(vertItem); } - for(const std::string& name: facePointNames) { - QTreeWidgetItem *vertItem = new QTreeWidgetItem(); - vertItem->setText(2, QString("Face (vec3):")); + for (const std::string& name : facePointNames) { + QTreeWidgetItem* vertItem = new QTreeWidgetItem(); + vertItem->setText(2, QString("Face (point):")); vertItem->setText(3, QString(name.c_str())); parent->addChild(vertItem); updateColumnNumber(vertItem); } - if (meshModel->cm.textures.size() > 0){ - QTreeWidgetItem *vertItem = new QTreeWidgetItem(); - QFont f; + if (meshModel->cm.textures.size() > 0) { + QTreeWidgetItem* vertItem = new QTreeWidgetItem(); + QFont f; f.setBold(true); vertItem->setFont(1, f); vertItem->setText(1, QString("Textures:")); @@ -830,16 +830,15 @@ void LayerDialog::addDefaultNotes(QTreeWidgetItem * parent, MeshModel *meshModel updateColumnNumber(vertItem); } - for(const std::string& name: meshModel->cm.textures) { - QTreeWidgetItem *vertItem = new QTreeWidgetItem(); + for (const std::string& name : meshModel->cm.textures) { + QTreeWidgetItem* vertItem = new QTreeWidgetItem(); vertItem->setText(2, QString(name.c_str())); - const QImage& img = meshModel->getTexture(name); - QString size = QString::number(img.width()) + "x" + QString::number(img.height()); + const QImage& img = meshModel->getTexture(name); + QString size = QString::number(img.width()) + "x" + QString::number(img.height()); vertItem->setText(3, QString(size)); parent->addChild(vertItem); updateColumnNumber(vertItem); } - } //Add, if necessary, columns to the treeWidget. diff --git a/src/meshlabplugins/filter_func/filter_func.cpp b/src/meshlabplugins/filter_func/filter_func.cpp index 4c716de29..6d9f30a6f 100644 --- a/src/meshlabplugins/filter_func/filter_func.cpp +++ b/src/meshlabplugins/filter_func/filter_func.cpp @@ -1,25 +1,25 @@ -/**************************************************************************** -* MeshLab o o * -* A versatile mesh processing toolbox o o * -* _ O _ * -* Copyright(C) 2005 \/)\/ * -* 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. * -* * -****************************************************************************/ +/***************************************************************************** + * 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_func.h" #include @@ -47,14 +47,15 @@ FilterFunctionPlugin::FilterFunctionPlugin() FF_VERT_QUALITY, FF_VERT_NORMAL, FF_FACE_QUALITY, - FF_DEF_VERT_ATTRIB, - FF_DEF_FACE_ATTRIB, + FF_DEF_VERT_SCALAR_ATTRIB, + FF_DEF_FACE_SCALAR_ATTRIB, + FF_DEF_VERT_POINT_ATTRIB, + FF_DEF_FACE_POINT_ATTRIB, FF_GRID, FF_ISOSURFACE, - FF_REFINE - }; - - for(ActionIDType tt: types()) + FF_REFINE}; + + for (ActionIDType tt : types()) actionList.push_back(new QAction(filterName(tt), this)); } @@ -70,303 +71,562 @@ QString FilterFunctionPlugin::pluginName() const // short string describing each filtering action QString FilterFunctionPlugin::filterName(ActionIDType filterId) const { - switch(filterId) { - case FF_VERT_SELECTION: return QString("Conditional Vertex Selection"); - case FF_FACE_SELECTION: return QString("Conditional Face Selection"); - case FF_GEOM_FUNC: return QString("Per Vertex Geometric Function"); - case FF_FACE_COLOR: return QString("Per Face Color Function"); - case FF_FACE_QUALITY: return QString("Per Face Quality Function"); - case FF_VERT_COLOR: return QString("Per Vertex Color Function"); - case FF_VERT_QUALITY: return QString("Per Vertex Quality Function"); - case FF_VERT_TEXTURE_FUNC: return QString("Per Vertex Texture Function"); + switch (filterId) { + case FF_VERT_SELECTION: return QString("Conditional Vertex Selection"); + case FF_FACE_SELECTION: return QString("Conditional Face Selection"); + case FF_GEOM_FUNC: return QString("Per Vertex Geometric Function"); + case FF_FACE_COLOR: return QString("Per Face Color Function"); + case FF_FACE_QUALITY: return QString("Per Face Quality Function"); + case FF_VERT_COLOR: return QString("Per Vertex Color Function"); + case FF_VERT_QUALITY: return QString("Per Vertex Quality Function"); + case FF_VERT_TEXTURE_FUNC: return QString("Per Vertex Texture Function"); case FF_WEDGE_TEXTURE_FUNC: return QString("Per Wedge Texture Function"); - case FF_VERT_NORMAL: return QString("Per Vertex Normal Function"); - case FF_DEF_VERT_ATTRIB: return QString("Define New Per Vertex Attribute"); - case FF_DEF_FACE_ATTRIB: return QString("Define New Per Face Attribute"); - case FF_GRID: return QString("Grid Generator"); - case FF_REFINE: return QString("Refine User-Defined"); - case FF_ISOSURFACE: return QString("Implicit Surface"); - + case FF_VERT_NORMAL: return QString("Per Vertex Normal Function"); + case FF_DEF_VERT_SCALAR_ATTRIB: return QString("Define New Per Vertex Custom Scalar Attribute"); + case FF_DEF_FACE_SCALAR_ATTRIB: return QString("Define New Per Face Custom Scalar Attribute"); + case FF_DEF_VERT_POINT_ATTRIB: return QString("Define New Per Vertex Custom Point Attribute"); + case FF_DEF_FACE_POINT_ATTRIB: return QString("Define New Per Face Custom Point Attribute"); + case FF_GRID: return QString("Grid Generator"); + case FF_REFINE: return QString("Refine User-Defined"); + case FF_ISOSURFACE: return QString("Implicit Surface"); + default: assert(0); } return QString("error!"); } -const QString PossibleOperators("
It's possible to use parenthesis (), and predefined operators:
" - "&& (logic and), || (logic or), <, <=, >, >=, != (not equal), == (equal), _?_:_ (c/c++ ternary operator)

"); +const QString PossibleOperators( + "
It's possible to use parenthesis (), and predefined operators:
" + "&& (logic and), || (logic or), <, <=, >, >=, " + "!= (not equal), == (equal), _?_:_ (c/c++ ternary operator)

"); -const QString PerVertexAttributeString( "It's possible to use the following per-vertex variables in the expression:
" - "x,y,z (position), nx,ny,nz (normal), r,g,b,a (color), q (quality), " - "rad (radius), vi (vertex index), vtu,vtv,ti (texture coords and texture index), vsel (is the vertex selected? 1 yes, 0 no) " - "and all custom vertex attributes already defined by user.
"); +const QString PerVertexAttributeString( + "It's possible to use the following per-vertex variables in the expression:
" + "x,y,z (position), nx,ny,nz (normal), r,g,b,a (color), q " + "(quality), " + "rad (radius), vi (vertex index), vtu,vtv,ti (texture coords and texture " + "index), vsel (is the vertex selected? 1 yes, 0 no) " + "and all custom vertex attributes already defined by user.
"); -const QString PerFaceAttributeString("It's possible to use the following per-face variables, or variables associated to the three vertex of every face:
" - "x0,y0,z0 for the first vertex position, x1,y1,z1 for the second vertex position, x2,y2,z2 for the third vertex position, " - "nx0,ny0,nz0 nx1,ny1,nz1 nx2,ny2,nz2 for vertex normals, r0,g0,b0,a0 r1,g1,b1,a1 r2,g2,b2,a2 for vertex colors, vi0, vi1, vi2 for vertex indices, " - "q0,q1,q2 for vertex quality, wtu0,wtv0 wtu1,wtv1 wtu2,wtv2 for per-wedge texture coords, ti for face texture index, vsel0,vsel1,vsel2 for vertex selection (1 yes, 0 no) " - "fi for face index, fr,fg,fb,fa for face color, fq for face quality, fnx,fny,fnz for face normal, fsel face selection (1 yes, 0 no).
"); +const QString PerFaceAttributeString( + "It's possible to use the following per-face variables, or variables associated to the three " + "vertex of every face:
" + "x0,y0,z0 for the first vertex position, x1,y1,z1 for the second vertex " + "position, x2,y2,z2 for the third vertex position, " + "nx0,ny0,nz0 nx1,ny1,nz1 nx2,ny2,nz2 for vertex normals, r0,g0,b0,a0 r1,g1,b1,a1 " + "r2,g2,b2,a2 for vertex colors, vi0, vi1, vi2 for vertex indices, " + "q0,q1,q2 for vertex quality, wtu0,wtv0 wtu1,wtv1 wtu2,wtv2 for per-wedge " + "texture coords, ti for face texture index, vsel0,vsel1,vsel2 for vertex " + "selection (1 yes, 0 no) " + "fi for face index, fr,fg,fb,fa for face color, fq for face quality, " + "fnx,fny,fnz for face normal, fsel face selection (1 yes, 0 no).
"); // long string describing each filtering action QString FilterFunctionPlugin::filterInfo(ActionIDType filterId) const { - switch(filterId) { - case FF_VERT_SELECTION : return tr( "Boolean function using muparser lib to perform vertex selection over current mesh.
") - + PossibleOperators + PerVertexAttributeString; - - case FF_FACE_SELECTION : return tr( "Boolean function using muparser lib to perform faces selection over current mesh.
") - + PossibleOperators + PerFaceAttributeString; - - case FF_GEOM_FUNC : return tr( "Geometric function using muparser lib to generate new Coord
" - "You can change x,y,z for every vertex according to the function specified.
") + PerVertexAttributeString; - - case FF_FACE_COLOR : return tr( "Color function using muparser lib to generate new RGBA color for every face
" - "Red, Green, Blue and Alpha channels may be defined specifying a function in their respective fields.
") + PerFaceAttributeString; - - case FF_VERT_COLOR : return tr( "Color function using muparser lib to generate new RGBA color for every vertex
" - "Red, Green, Blue and Alpha channels may be defined specifying a function in their respective fields.
") + PerVertexAttributeString; - - case FF_VERT_QUALITY: return tr("Quality function using muparser to generate new Quality for every vertex
") + PerVertexAttributeString; - - case FF_VERT_TEXTURE_FUNC: return tr("Texture function using muparser to generate new texture coords for every vertex
") + PerVertexAttributeString; - - case FF_VERT_NORMAL: return tr("Normal function using muparser to generate new Normal for every vertex
") + PerVertexAttributeString; - - case FF_FACE_QUALITY : return tr("Quality function using muparser to generate new Quality for every face
" - "Insert three function each one for quality of the three vertex of a face
") +PerFaceAttributeString; - - case FF_WEDGE_TEXTURE_FUNC : return tr("Texture function using muparser to generate new per wedge tex coords for every face
" - "Insert six functions each u v for each one of the three vertex of a face
") +PerFaceAttributeString; - - case FF_DEF_VERT_ATTRIB : return tr("Add a new Per-Vertex scalar attribute to current mesh and fill it with the defined function.
" - "The name specified below can be used in other filter function") +PerVertexAttributeString; - - case FF_DEF_FACE_ATTRIB : return tr("Add a new Per-Face attribute to current mesh.
" - "You can specify custom name and a function to generate attribute's value
" - "It's possible to use per-face variables in the expression:
") +PerFaceAttributeString+ - tr("The attribute name specified below can be used in other filter function"); - - case FF_GRID : return tr("Generate a new 2D Grid mesh with number of vertices on X and Y axis specified by user with absolute length/height.
" - "It's possible to center Grid on origin."); - - case FF_ISOSURFACE : return tr("Generate a new mesh that corresponds to the 0 valued isosurface defined by the scalar field generated by the given expression"); - - case FF_REFINE : return tr("Refine current mesh with user defined parameters.
" - "Specify a Boolean Function needed to select which edges will be cut for refinement purpose.
" - "Each edge is identified with first and second vertex.
" - "Arguments accepted are first and second vertex attributes:
") + PossibleOperators + PerFaceAttributeString; - - default : assert(0); + switch (filterId) { + case FF_VERT_SELECTION: + return tr("Boolean function using muparser lib to perform vertex selection over current " + "mesh.
") + + PossibleOperators + PerVertexAttributeString; + + case FF_FACE_SELECTION: + return tr("Boolean function using muparser lib to perform faces selection over current " + "mesh.
") + + PossibleOperators + PerFaceAttributeString; + + case FF_GEOM_FUNC: + return tr("Geometric function using muparser lib to generate new Coord
" + "You can change x,y,z for every vertex according to the function " + "specified.
") + + PerVertexAttributeString; + + case FF_FACE_COLOR: + return tr("Color function using muparser lib to generate new RGBA color for every face
" + "Red, Green, Blue and Alpha channels may be defined specifying a function in " + "their respective fields.
") + + PerFaceAttributeString; + + case FF_VERT_COLOR: + return tr("Color function using muparser lib to generate new RGBA color for every " + "vertex
" + "Red, Green, Blue and Alpha channels may be defined specifying a function in " + "their respective fields.
") + + PerVertexAttributeString; + + case FF_VERT_QUALITY: + return tr("Quality function using muparser to generate new Quality for every vertex
") + + PerVertexAttributeString; + + case FF_VERT_TEXTURE_FUNC: + return tr("Texture function using muparser to generate new texture coords for every " + "vertex
") + + PerVertexAttributeString; + + case FF_VERT_NORMAL: + return tr("Normal function using muparser to generate new Normal for every vertex
") + + PerVertexAttributeString; + + case FF_FACE_QUALITY: + return tr("Quality function using muparser to generate new Quality for every face
" + "Insert three function each one for quality of the three vertex of a face
") + + PerFaceAttributeString; + + case FF_WEDGE_TEXTURE_FUNC: + return tr("Texture function using muparser to generate new per wedge tex coords for every " + "face
" + "Insert six functions each u v for each one of the three vertex of a face
") + + PerFaceAttributeString; + + case FF_DEF_VERT_SCALAR_ATTRIB: + return tr("Add a new Per-Vertex custom scalar attribute to current mesh and fill it with the " + "defined function.
" + "The name specified below can be used in other filter function") + + PerVertexAttributeString; + + case FF_DEF_FACE_SCALAR_ATTRIB: + return tr("Add a new Per-Face custom scalar attribute to current mesh.
" + "You can specify custom name and a function to generate attribute's values
" + "It's possible to use per-face variables in the expression:
") + + PerFaceAttributeString + + tr("The attribute name specified below can be used in other " + "filter function"); + + case FF_DEF_VERT_POINT_ATTRIB: + return tr("Add a new Per-Vertex custom point attribute to current mesh and fill it with the " + "defined function.
" + "The name specified below can be used in other filter function") + + PerVertexAttributeString; + + case FF_DEF_FACE_POINT_ATTRIB: + return tr("Add a new Per-Face custom point attribute to current mesh.
" + "You can specify custom name and a function to generate attribute's values
" + "It's possible to use per-face variables in the expression:
") + + PerFaceAttributeString + + tr("The attribute name specified below can be used in other " + "filter function"); + + case FF_GRID: + return tr( + "Generate a new 2D Grid mesh with number of vertices on X and Y axis specified by user " + "with absolute length/height.
" + "It's possible to center Grid on origin."); + + case FF_ISOSURFACE: + return tr( + "Generate a new mesh that corresponds to the 0 valued isosurface defined by the scalar " + "field generated by the given expression"); + + case FF_REFINE: + return tr("Refine current mesh with user defined parameters.
" + "Specify a Boolean Function needed to select which edges will be cut for " + "refinement purpose.
" + "Each edge is identified with first and second vertex.
" + "Arguments accepted are first and second vertex attributes:
") + + PossibleOperators + PerFaceAttributeString; + + default: assert(0); } return QString("filter not found!"); } -FilterFunctionPlugin::FilterClass FilterFunctionPlugin::getClass(const QAction *a) const +FilterFunctionPlugin::FilterClass FilterFunctionPlugin::getClass(const QAction* a) const { - switch(ID(a)) - { + switch (ID(a)) { case FF_FACE_SELECTION: case FF_VERT_SELECTION: return FilterPlugin::Selection; case FF_FACE_QUALITY: return FilterClass(Quality + FaceColoring); case FF_VERT_QUALITY: return FilterClass(Quality + VertexColoring); case FF_VERT_TEXTURE_FUNC: return FilterPlugin::Texture; - case FF_VERT_COLOR: return FilterPlugin::VertexColoring; - case FF_VERT_NORMAL: return FilterPlugin::Normal; + case FF_VERT_COLOR: return FilterPlugin::VertexColoring; + case FF_VERT_NORMAL: return FilterPlugin::Normal; case FF_FACE_COLOR: return FilterPlugin::FaceColoring; case FF_WEDGE_TEXTURE_FUNC: return FilterPlugin::Texture; case FF_ISOSURFACE: return FilterPlugin::MeshCreation; case FF_GRID: return FilterPlugin::MeshCreation; case FF_REFINE: return FilterPlugin::Remeshing; case FF_GEOM_FUNC: return FilterPlugin::Smoothing; - case FF_DEF_VERT_ATTRIB: return FilterPlugin::Layer; - case FF_DEF_FACE_ATTRIB: return FilterPlugin::Layer; - + case FF_DEF_VERT_SCALAR_ATTRIB: + case FF_DEF_FACE_SCALAR_ATTRIB: + case FF_DEF_VERT_POINT_ATTRIB: + case FF_DEF_FACE_POINT_ATTRIB: + return FilterPlugin::Layer; + default: return FilterPlugin::Generic; } } -int FilterFunctionPlugin::postCondition(const QAction *action) const +int FilterFunctionPlugin::postCondition(const QAction* action) const { - switch(ID(action)) - { + switch (ID(action)) { case FF_VERT_SELECTION: - case FF_FACE_SELECTION: - return MeshModel::MM_VERTFLAGSELECT | MeshModel::MM_FACEFLAGSELECT; - case FF_FACE_COLOR: - return MeshModel::MM_FACECOLOR; + case FF_FACE_SELECTION: return MeshModel::MM_VERTFLAGSELECT | MeshModel::MM_FACEFLAGSELECT; + case FF_FACE_COLOR: return MeshModel::MM_FACECOLOR; case FF_GEOM_FUNC: return MeshModel::MM_VERTCOORD + MeshModel::MM_VERTNORMAL + MeshModel::MM_FACENORMAL; - case FF_VERT_COLOR: - return MeshModel::MM_VERTCOLOR; - case FF_VERT_NORMAL: - return MeshModel::MM_VERTNORMAL; - case FF_VERT_TEXTURE_FUNC: - return MeshModel::MM_VERTTEXCOORD; - case FF_WEDGE_TEXTURE_FUNC: - return MeshModel::MM_WEDGTEXCOORD; - case FF_VERT_QUALITY: - return MeshModel::MM_VERTQUALITY + MeshModel::MM_VERTCOLOR; - case FF_FACE_QUALITY: - return MeshModel::MM_FACECOLOR + MeshModel::MM_FACEQUALITY; - - case FF_DEF_VERT_ATTRIB: - case FF_DEF_FACE_ATTRIB: - return MeshModel::MM_NONE; // none, because they do not change any existing data - - case FF_REFINE: - return MeshModel::MM_ALL; - + case FF_VERT_COLOR: return MeshModel::MM_VERTCOLOR; + case FF_VERT_NORMAL: return MeshModel::MM_VERTNORMAL; + case FF_VERT_TEXTURE_FUNC: return MeshModel::MM_VERTTEXCOORD; + case FF_WEDGE_TEXTURE_FUNC: return MeshModel::MM_WEDGTEXCOORD; + case FF_VERT_QUALITY: return MeshModel::MM_VERTQUALITY + MeshModel::MM_VERTCOLOR; + case FF_FACE_QUALITY: return MeshModel::MM_FACECOLOR + MeshModel::MM_FACEQUALITY; + + case FF_DEF_VERT_SCALAR_ATTRIB: + case FF_DEF_FACE_SCALAR_ATTRIB: + case FF_DEF_VERT_POINT_ATTRIB: + case FF_DEF_FACE_POINT_ATTRIB: + return MeshModel::MM_NONE; // none, because they do not change any existing data + + case FF_REFINE: return MeshModel::MM_ALL; + case FF_GRID: case FF_ISOSURFACE: - return MeshModel::MM_NONE; // none, because they create a new layer, without affecting old one + return MeshModel::MM_NONE; // none, because they create a new layer, without affecting old + // one } - + return MeshModel::MM_NONE; } -int FilterFunctionPlugin::getRequirements(const QAction *action) +int FilterFunctionPlugin::getRequirements(const QAction* action) { - switch(ID(action)) - { - case FF_VERT_SELECTION : - case FF_GEOM_FUNC : - case FF_VERT_COLOR : - case FF_VERT_NORMAL : - case FF_VERT_QUALITY : - case FF_VERT_TEXTURE_FUNC : - case FF_DEF_VERT_ATTRIB : - case FF_GRID : - case FF_ISOSURFACE : - case FF_DEF_FACE_ATTRIB : - case FF_FACE_SELECTION : return 0; + switch (ID(action)) { + case FF_VERT_SELECTION: + case FF_GEOM_FUNC: + case FF_VERT_COLOR: + case FF_VERT_NORMAL: + case FF_VERT_QUALITY: + case FF_VERT_TEXTURE_FUNC: + case FF_DEF_VERT_SCALAR_ATTRIB: + case FF_DEF_FACE_SCALAR_ATTRIB: + case FF_DEF_VERT_POINT_ATTRIB: + case FF_DEF_FACE_POINT_ATTRIB: + case FF_GRID: + case FF_ISOSURFACE: + case FF_FACE_SELECTION: return 0; case FF_WEDGE_TEXTURE_FUNC: return MeshModel::MM_WEDGTEXCOORD; - case FF_FACE_QUALITY : return MeshModel::MM_FACECOLOR | MeshModel::MM_FACEQUALITY; - case FF_FACE_COLOR : return MeshModel::MM_FACECOLOR; - case FF_REFINE : return MeshModel::MM_FACEFACETOPO | MeshModel::MM_VERTMARK; + case FF_FACE_QUALITY: return MeshModel::MM_FACECOLOR | MeshModel::MM_FACEQUALITY; + case FF_FACE_COLOR: return MeshModel::MM_FACECOLOR; + case FF_REFINE: return MeshModel::MM_FACEFACETOPO | MeshModel::MM_VERTMARK; default: assert(0); } return 0; } -// This function define the needed parameters for each filter. Return true if the filter has some parameters -// it is called every time, so you can set the default value of parameters according to the mesh -// For each parameter you need to define, +// This function define the needed parameters for each filter. Return true if the filter has some +// parameters it is called every time, so you can set the default value of parameters according to +// the mesh For each parameter you need to define, // - the name of the parameter, // - the string shown in the dialog // - the default value -// - a possibly long string describing the meaning of that parameter (shown as a popup help in the dialog) -RichParameterList FilterFunctionPlugin::initParameterList(const QAction *action,const MeshModel &) +// - a possibly long string describing the meaning of that parameter (shown as a popup help in the +// dialog) +RichParameterList FilterFunctionPlugin::initParameterList(const QAction* action, const MeshModel&) { RichParameterList parlst; - switch(ID(action)) { - - case FF_VERT_SELECTION : - parlst.addParam(RichString("condSelect","(q < 0)", "boolean function", - "type a boolean function that will be evaluated in order to select a subset of vertices
" - "example: (y > 0) and (ny > 0)")); + switch (ID(action)) { + case FF_VERT_SELECTION: + parlst.addParam(RichString( + "condSelect", + "(q < 0)", + "boolean function", + "type a boolean function that will be evaluated in order to select a subset of " + "vertices
" + "example: (y > 0) and (ny > 0)")); break; - - case FF_FACE_SELECTION : - parlst.addParam(RichString("condSelect","(fi == 0)", "boolean function", - "type a boolean function that will be evaluated in order to select a subset of faces
")); + + case FF_FACE_SELECTION: + parlst.addParam(RichString( + "condSelect", + "(fi == 0)", + "boolean function", + "type a boolean function that will be evaluated in order to select a subset of " + "faces
")); break; - + case FF_GEOM_FUNC: - parlst.addParam(RichString("x", "x", "func x = ", "insert function to generate new coord for x")); - parlst.addParam(RichString("y", "y", "func y = ", "insert function to generate new coord for y")); - parlst.addParam(RichString("z", "sin(x+y)", "func z = ", "insert function to generate new coord for z")); - parlst.addParam(RichBool("onselected", false, "only on selection", "if checked, only affects selected vertices")); + parlst.addParam( + RichString("x", "x", "func x = ", "insert function to generate new coord for x")); + parlst.addParam( + RichString("y", "y", "func y = ", "insert function to generate new coord for y")); + parlst.addParam(RichString( + "z", "sin(x+y)", "func z = ", "insert function to generate new coord for z")); + parlst.addParam(RichBool( + "onselected", + false, + "only on selection", + "if checked, only affects selected vertices")); break; - + case FF_VERT_NORMAL: - parlst.addParam(RichString("x", "-nx", "func nx = ", "insert function to generate new x for the normal")); - parlst.addParam(RichString("y", "-ny", "func ny = ", "insert function to generate new y for the normal")); - parlst.addParam(RichString("z", "-nz", "func nz = ", "insert function to generate new z for the normal")); - parlst.addParam(RichBool("onselected", false, "only on selection", "if checked, only affects selected vertices")); + parlst.addParam(RichString( + "x", "-nx", "func nx = ", "insert function to generate new x for the normal")); + parlst.addParam(RichString( + "y", "-ny", "func ny = ", "insert function to generate new y for the normal")); + parlst.addParam(RichString( + "z", "-nz", "func nz = ", "insert function to generate new z for the normal")); + parlst.addParam(RichBool( + "onselected", + false, + "only on selection", + "if checked, only affects selected vertices")); break; - + case FF_VERT_COLOR: - parlst.addParam(RichString("x", "255", "func r = ", "function to generate Red component. Expected Range 0-255")); - parlst.addParam(RichString("y", "255", "func g = ", "function to generate Green component. Expected Range 0-255")); - parlst.addParam(RichString("z", "0", "func b = ", "function to generate Blue component. Expected Range 0-255")); - parlst.addParam(RichString("a", "255", "func alpha = ", "function to generate Alpha component. Expected Range 0-255")); - parlst.addParam(RichBool("onselected", false, "only on selection", "if checked, only affects selected vertices")); + parlst.addParam(RichString( + "x", "255", "func r = ", "function to generate Red component. Expected Range 0-255")); + parlst.addParam(RichString( + "y", "255", "func g = ", "function to generate Green component. Expected Range 0-255")); + parlst.addParam(RichString( + "z", "0", "func b = ", "function to generate Blue component. Expected Range 0-255")); + parlst.addParam(RichString( + "a", + "255", + "func alpha = ", + "function to generate Alpha component. Expected Range 0-255")); + parlst.addParam(RichBool( + "onselected", + false, + "only on selection", + "if checked, only affects selected vertices")); break; - + case FF_VERT_TEXTURE_FUNC: - parlst.addParam(RichString("u", "x", "func u = ", "function to generate u texture coord. Expected Range 0-1")); - parlst.addParam(RichString("v", "y", "func v = ", "function to generate v texture coord. Expected Range 0-1")); - parlst.addParam(RichBool("onselected", false, "only on selection", "if checked, only affects selected vertices")); + parlst.addParam(RichString( + "u", "x", "func u = ", "function to generate u texture coord. Expected Range 0-1")); + parlst.addParam(RichString( + "v", "y", "func v = ", "function to generate v texture coord. Expected Range 0-1")); + parlst.addParam(RichBool( + "onselected", + false, + "only on selection", + "if checked, only affects selected vertices")); break; - + case FF_VERT_QUALITY: - parlst.addParam(RichString("q", "vi", "func q = ", "function to generate new Quality for every vertex")); - parlst.addParam(RichBool("normalize", false, "normalize", "if checked normalize all quality values in range [0..1]")); - parlst.addParam(RichBool("map", false, "map into color", "if checked map quality generated values into per-vertex color")); - parlst.addParam(RichBool("onselected", false, "only on selection", "if checked, only affects selected vertices")); + parlst.addParam(RichString( + "q", "vi", "func q = ", "function to generate new Quality for every vertex")); + parlst.addParam(RichBool( + "normalize", + false, + "normalize", + "if checked normalize all quality values in range [0..1]")); + parlst.addParam(RichBool( + "map", + false, + "map into color", + "if checked map quality generated values into per-vertex color")); + parlst.addParam(RichBool( + "onselected", + false, + "only on selection", + "if checked, only affects selected vertices")); break; - + case FF_FACE_COLOR: - parlst.addParam(RichString("r", "255", "func r = ", "function to generate Red component. Expected Range 0-255")); - parlst.addParam(RichString("g", "0", "func g = ", "function to generate Green component. Expected Range 0-255")); - parlst.addParam(RichString("b", "255", "func b = ", "function to generate Blue component. Expected Range 0-255")); - parlst.addParam(RichString("a", "255", "func alpha = ", "function to generate Alpha component. Expected Range 0-255")); - parlst.addParam(RichBool("onselected", false, "only on selection", "if checked, only affects selected faces")); + parlst.addParam(RichString( + "r", "255", "func r = ", "function to generate Red component. Expected Range 0-255")); + parlst.addParam(RichString( + "g", "0", "func g = ", "function to generate Green component. Expected Range 0-255")); + parlst.addParam(RichString( + "b", "255", "func b = ", "function to generate Blue component. Expected Range 0-255")); + parlst.addParam(RichString( + "a", + "255", + "func alpha = ", + "function to generate Alpha component. Expected Range 0-255")); + parlst.addParam(RichBool( + "onselected", false, "only on selection", "if checked, only affects selected faces")); break; - + case FF_FACE_QUALITY: - parlst.addParam(RichString("q", "x0+y0+z0", "func q0 = ", "function to generate new Quality foreach face")); - parlst.addParam(RichBool("normalize", false, "normalize", "if checked normalize all quality values in range [0..1]")); - parlst.addParam(RichBool("map", false, "map into color", "if checked map quality generated values into per-vertex color")); - parlst.addParam(RichBool("onselected", false, "only on selection", "if checked, only affects selected faces")); + parlst.addParam(RichString( + "q", "x0+y0+z0", "func q0 = ", "function to generate new Quality foreach face")); + parlst.addParam(RichBool( + "normalize", + false, + "normalize", + "if checked normalize all quality values in range [0..1]")); + parlst.addParam(RichBool( + "map", + false, + "map into color", + "if checked map quality generated values into per-vertex color")); + parlst.addParam(RichBool( + "onselected", false, "only on selection", "if checked, only affects selected faces")); break; - + case FF_WEDGE_TEXTURE_FUNC: - parlst.addParam(RichString("u0","x0", "func u0 = ", "function to generate u texture coord. of wedge 0. Expected Range 0-1")); - parlst.addParam(RichString("v0","y0", "func v0 = ", "function to generate v texture coord. of wedge 0. Expected Range 0-1")); - parlst.addParam(RichString("u1","x1", "func u1 = ", "function to generate u texture coord. of wedge 1. Expected Range 0-1")); - parlst.addParam(RichString("v1","y1", "func v1 = ", "function to generate v texture coord. of wedge 1. Expected Range 0-1")); - parlst.addParam(RichString("u2","x2", "func u2 = ", "function to generate u texture coord. of wedge 2. Expected Range 0-1")); - parlst.addParam(RichString("v2","y2", "func v2 = ", "function to generate v texture coord. of wedge 2. Expected Range 0-1")); - parlst.addParam(RichBool("onselected", false, "only on selection", "if checked, only affects selected faces")); + parlst.addParam(RichString( + "u0", + "x0", + "func u0 = ", + "function to generate u texture coord. of wedge 0. Expected Range 0-1")); + parlst.addParam(RichString( + "v0", + "y0", + "func v0 = ", + "function to generate v texture coord. of wedge 0. Expected Range 0-1")); + parlst.addParam(RichString( + "u1", + "x1", + "func u1 = ", + "function to generate u texture coord. of wedge 1. Expected Range 0-1")); + parlst.addParam(RichString( + "v1", + "y1", + "func v1 = ", + "function to generate v texture coord. of wedge 1. Expected Range 0-1")); + parlst.addParam(RichString( + "u2", + "x2", + "func u2 = ", + "function to generate u texture coord. of wedge 2. Expected Range 0-1")); + parlst.addParam(RichString( + "v2", + "y2", + "func v2 = ", + "function to generate v texture coord. of wedge 2. Expected Range 0-1")); + parlst.addParam(RichBool( + "onselected", false, "only on selection", "if checked, only affects selected faces")); break; - - case FF_DEF_VERT_ATTRIB: - parlst.addParam(RichString("name","Radiosity","Name", "the name of new attribute. you can access attribute in other filters through this name")); - parlst.addParam(RichString("expr","x","Function =", "function to calculate custom attribute value for each vertex")); + + case FF_DEF_VERT_SCALAR_ATTRIB: + parlst.addParam(RichString( + "name", + "Custom Attr Name", + "Name", + "the name of new attribute. you can access attribute in other filters through this " + "name")); + parlst.addParam(RichString( + "expr", + "x", + "Scalar function =", + "function to calculate custom scalar attribute value for each vertex")); break; - - case FF_DEF_FACE_ATTRIB: - parlst.addParam(RichString("name","Radiosity","Name", "the name of new attribute. you can access attribute in other filters through this name")); - parlst.addParam(RichString("expr","fi","Function =", "function to calculate custom attribute value for each face")); + + case FF_DEF_FACE_SCALAR_ATTRIB: + parlst.addParam(RichString( + "name", + "Custom Attr Name", + "Name", + "the name of new attribute. you can access attribute in other filters through this " + "name")); + parlst.addParam(RichString( + "expr", + "fi", + "Scalar function =", + "function to calculate custom scalar attribute value for each face")); break; - - case FF_GRID : - parlst.addParam(RichInt("numVertX", 10, "num vertices on x", "number of vertices on x. it must be positive")); - parlst.addParam(RichInt("numVertY", 10, "num vertices on y", "number of vertices on y. it must be positive")); + + case FF_DEF_VERT_POINT_ATTRIB: + parlst.addParam(RichString( + "name", + "Custom Attr Name", + "Name", + "the name of new attribute. you can access attribute in other filters through this " + "name")); + parlst.addParam(RichString( + "x_expr", + "x", + "x coord function =", + "function to calculate custom x coord of the point attribute value for each vertex")); + parlst.addParam(RichString( + "y_expr", + "y", + "y coord function =", + "function to calculate custom y coord of the point attribute value for each vertex")); + parlst.addParam(RichString( + "z_expr", + "z", + "z coord function =", + "function to calculate custom z coord of the point attribute value for each vertex")); + break; + + case FF_DEF_FACE_POINT_ATTRIB: + parlst.addParam(RichString( + "name", + "Custom Attr Name", + "Name", + "the name of new attribute. you can access attribute in other filters through this " + "name")); + parlst.addParam(RichString( + "x_expr", + "x0", + "x coord function =", + "function to calculate custom x coord of the point attribute value for each face")); + parlst.addParam(RichString( + "y_expr", + "y0", + "y coord function =", + "function to calculate custom y coord of the point attribute value for each face")); + parlst.addParam(RichString( + "z_expr", + "z0", + "z coord function =", + "function to calculate custom z coord of the point attribute value for each face")); + break; + + case FF_GRID: + parlst.addParam(RichInt( + "numVertX", 10, "num vertices on x", "number of vertices on x. it must be positive")); + parlst.addParam(RichInt( + "numVertY", 10, "num vertices on y", "number of vertices on y. it must be positive")); parlst.addParam(RichFloat("absScaleX", 0.3f, "x scale", "absolute scale on x (float)")); parlst.addParam(RichFloat("absScaleY", 0.3f, "y scale", "absolute scale on y (float)")); - parlst.addParam(RichBool("center",false,"centered on origin", "center grid generated by filter on origin.
" - "Grid is first generated and than moved into origin (using muparser lib to perform fast calc on every vertex)")); + parlst.addParam(RichBool( + "center", + false, + "centered on origin", + "center grid generated by filter on origin.
" + "Grid is first generated and than moved into origin (using muparser lib to perform " + "fast calc on every vertex)")); break; - case FF_ISOSURFACE : - parlst.addParam(RichFloat("voxelSize", 0.05f, "Size of Voxel", "Size of the voxel that is used by for the grid where the field is sampled. Smaller this value, higher precision, but higher processing times.")); + case FF_ISOSURFACE: + parlst.addParam(RichFloat( + "voxelSize", + 0.05f, + "Size of Voxel", + "Size of the voxel that is used by for the grid where the field is sampled. Smaller " + "this value, higher precision, but higher processing times.")); parlst.addParam(RichFloat("minX", -1.0f, "Min X", "Range where the field is sampled")); parlst.addParam(RichFloat("minY", -1.0f, "Min Y", "Range where the field is sampled")); parlst.addParam(RichFloat("minZ", -1.0f, "Min Z", "Range where the field is sampled")); parlst.addParam(RichFloat("maxX", 1.0f, "Max X", "Range where the field is sampled")); parlst.addParam(RichFloat("maxY", 1.0f, "Max Y", "Range where the field is sampled")); parlst.addParam(RichFloat("maxZ", 1.0f, "Max Z", "Range where the field is sampled")); - parlst.addParam(RichString("expr","x*x+y*y+z*z-0.5","Function =", "This expression is evaluated for each voxel of the grid. The surface passing through the zero valued points of this field is then extracted using marching cube.")); - + parlst.addParam(RichString( + "expr", + "x*x+y*y+z*z-0.5", + "Function =", + "This expression is evaluated for each voxel of the grid. The surface passing through " + "the zero valued points of this field is then extracted using marching cube.")); + break; - - case FF_REFINE : - parlst.addParam(RichString("condSelect","(q0 >= 0 && q1 >= 0)","boolean function","type a boolean function that will be evaluated on every edge")); - parlst.addParam(RichString("x","(x0+x1)/2","x =","function to generate x coord of new vertex in [x0,x1].
For example (x0+x1)/2")); - parlst.addParam(RichString("y","(y0+y1)/2","y =","function to generate x coord of new vertex in [y0,y1].
For example (y0+y1)/2")); - parlst.addParam(RichString("z","(z0+z1)/2","z =","function to generate x coord of new vertex in [z0,z1].
For example (z0+z1)/2")); + + case FF_REFINE: + parlst.addParam(RichString( + "condSelect", + "(q0 >= 0 && q1 >= 0)", + "boolean function", + "type a boolean function that will be evaluated on every edge")); + parlst.addParam(RichString( + "x", + "(x0+x1)/2", + "x =", + "function to generate x coord of new vertex in [x0,x1].
For example (x0+x1)/2")); + parlst.addParam(RichString( + "y", + "(y0+y1)/2", + "y =", + "function to generate x coord of new vertex in [y0,y1].
For example (y0+y1)/2")); + parlst.addParam(RichString( + "z", + "(z0+z1)/2", + "z =", + "function to generate x coord of new vertex in [z0,z1].
For example (z0+z1)/2")); break; - + default: break; // do not add any parameter for the other filters } return parlst; @@ -374,169 +634,193 @@ RichParameterList FilterFunctionPlugin::initParameterList(const QAction *action, // The Real Core Function doing the actual mesh processing. std::map FilterFunctionPlugin::applyFilter( - const QAction *filter, - const RichParameterList & par, - MeshDocument &md, - unsigned int& /*postConditionMask*/, - vcg::CallBackPos *cb) + const QAction* filter, + const RichParameterList& par, + MeshDocument& md, + unsigned int& /*postConditionMask*/, + vcg::CallBackPos* cb) { errorMsg = ""; - if(this->getClass(filter) == FilterPlugin::MeshCreation) - md.addNewMesh("",this->filterName(ID(filter))); - MeshModel &m=*(md.mm()); + if (this->getClass(filter) == FilterPlugin::MeshCreation) + md.addNewMesh("", this->filterName(ID(filter))); + MeshModel& m = *(md.mm()); Q_UNUSED(cb); - switch(ID(filter)) { - case FF_VERT_SELECTION : - { - std::string expr = par.getString("condSelect").toStdString(); - auto wexpr = conversion::fromStringToWString(expr); - + switch (ID(filter)) { + case FF_VERT_SELECTION: { + std::string expr = par.getString("condSelect").toStdString(); + auto wexpr = conversion::fromStringToWString(expr); + // muparser initialization and explicitly define parser variables Parser p; - setPerVertexVariables(p,m.cm); - + setPerVertexVariables(p, m.cm); + // set expression inserted by user as string (required by muparser) p.SetExpr(wexpr); - - int numvert = 0; - time_t start = clock(); - + + int numvert = 0; + time_t start = clock(); + // every parser variables is related to vertex coord and attributes. CMeshO::VertexIterator vi; - for(vi = m.cm.vert.begin(); vi != m.cm.vert.end(); ++vi)if(!(*vi).IsD()) - { - setAttributes(vi,m.cm); - - bool selected = false; - - // use parser to evaluate boolean function specified above - // in case of fail, error dialog contains details of parser's error - try { - selected = p.Eval(); - } catch(Parser::exception_type &e) { - throw MLException(conversion::fromWStringToString(e.GetMsg()).c_str()); + for (vi = m.cm.vert.begin(); vi != m.cm.vert.end(); ++vi) + if (!(*vi).IsD()) { + setAttributes(vi, m.cm); + + bool selected = false; + + // use parser to evaluate boolean function specified above + // in case of fail, error dialog contains details of parser's error + try { + selected = p.Eval(); + } + catch (Parser::exception_type& e) { + throw MLException(conversion::fromWStringToString(e.GetMsg()).c_str()); + } + + // set vertex as selected or clear selection + if (selected) { + (*vi).SetS(); + numvert++; + } + else + (*vi).ClearS(); } - - // set vertex as selected or clear selection - if(selected) { - (*vi).SetS(); - numvert++; - } else (*vi).ClearS(); - } - + // if succeeded log stream contains number of vertices and time elapsed - log( "selected %d vertices in %.2f sec.", numvert, (clock() - start) / (float) CLOCKS_PER_SEC); - } - break; - - case FF_FACE_SELECTION : - { + log("selected %d vertices in %.2f sec.", + numvert, + (clock() - start) / (float) CLOCKS_PER_SEC); + } break; + + case FF_FACE_SELECTION: { QString select = par.getString("condSelect"); - + // muparser initialization and explicitly define parser variables Parser p; - setPerFaceVariables(p,m.cm); - + setPerFaceVariables(p, m.cm); + // set expression inserted by user as string (required by muparser) p.SetExpr(conversion::fromStringToWString(select.toStdString())); - - int numface = 0; - time_t start = clock(); + + int numface = 0; + time_t start = clock(); // every parser variables is related to face attributes. CMeshO::FaceIterator fi; - for(fi = m.cm.face.begin(); fi != m.cm.face.end(); ++fi)if(!(*fi).IsD()) - { - setAttributes(fi,m.cm); - - bool selected = false; - - // use parser to evaluate boolean function specified above - // in case of fail, error dialog contains details of parser's error - try { - selected = p.Eval(); - } catch(Parser::exception_type &e) { - throw MLException(conversion::fromWStringToString(e.GetMsg()).c_str()); + for (fi = m.cm.face.begin(); fi != m.cm.face.end(); ++fi) + if (!(*fi).IsD()) { + setAttributes(fi, m.cm); + + bool selected = false; + + // use parser to evaluate boolean function specified above + // in case of fail, error dialog contains details of parser's error + try { + selected = p.Eval(); + } + catch (Parser::exception_type& e) { + throw MLException(conversion::fromWStringToString(e.GetMsg()).c_str()); + } + + // set face as selected or clear selection + if (selected) { + (*fi).SetS(); + numface++; + } + else + (*fi).ClearS(); } - - // set face as selected or clear selection - if(selected) { - (*fi).SetS(); - numface++; - } else (*fi).ClearS(); - } // if succeeded log stream contains number of vertices and time elapsed - log( "selected %d faces in %.2f sec.", numface, (clock() - start) / (float) CLOCKS_PER_SEC); + log("selected %d faces in %.2f sec.", numface, (clock() - start) / (float) CLOCKS_PER_SEC); - } - break; - - case FF_GEOM_FUNC : + } break; + + case FF_GEOM_FUNC: case FF_VERT_COLOR: - case FF_VERT_NORMAL: - { - std::string func_x,func_y,func_z,func_a; + case FF_VERT_NORMAL: { + std::string func_x, func_y, func_z, func_a; // FF_VERT_COLOR : x = r, y = g, z = b // FF_VERT_NORMAL : x = r, y = g, z = b func_x = par.getString("x").toStdString(); func_y = par.getString("y").toStdString(); func_z = par.getString("z").toStdString(); - if(ID(filter) == FF_VERT_COLOR) func_a = par.getString("a").toStdString(); - + if (ID(filter) == FF_VERT_COLOR) + func_a = par.getString("a").toStdString(); + bool onSelected = par.getBool("onselected"); - + if (onSelected && m.cm.svn == 0 && m.cm.sfn == 0) // if no selection at all, fail { log("Cannot apply only on selection: there is no selection"); throw MLException("Cannot apply only on selection: there is no selection"); } - if (onSelected && (m.cm.svn == 0 && m.cm.sfn > 0)) // if no vert selected, but some faces selected, use their vertices + if (onSelected && + (m.cm.svn == 0 && + m.cm.sfn > 0)) // if no vert selected, but some faces selected, use their vertices { tri::UpdateSelection::VertexClear(m.cm); tri::UpdateSelection::VertexFromFaceLoose(m.cm); } - + // muparser initialization and explicitly define parser variables // function for x,y and z must use different parser and variables - Parser p1,p2,p3,p4; - - setPerVertexVariables(p1,m.cm); - setPerVertexVariables(p2,m.cm); - setPerVertexVariables(p3,m.cm); - setPerVertexVariables(p4,m.cm); - + Parser p1, p2, p3, p4; + + setPerVertexVariables(p1, m.cm); + setPerVertexVariables(p2, m.cm); + setPerVertexVariables(p3, m.cm); + setPerVertexVariables(p4, m.cm); + p1.SetExpr(conversion::fromStringToWString(func_x)); p2.SetExpr(conversion::fromStringToWString(func_y)); p3.SetExpr(conversion::fromStringToWString(func_z)); p4.SetExpr(conversion::fromStringToWString(func_a)); - - double newx=0,newy=0,newz=0,newa=255; + + double newx = 0, newy = 0, newz = 0, newa = 255; QString errorMsg = ""; - + time_t start = clock(); - + // every parser variables is related to vertex coord and attributes. CMeshO::VertexIterator vi; - for(vi = m.cm.vert.begin(); vi != m.cm.vert.end(); ++vi) - if(!(*vi).IsD()) - if ((!onSelected) || ((*vi).IsS())) - { - setAttributes(vi,m.cm); - + for (vi = m.cm.vert.begin(); vi != m.cm.vert.end(); ++vi) + if (!(*vi).IsD()) + if ((!onSelected) || ((*vi).IsS())) { + setAttributes(vi, m.cm); + // every function is evaluated by different parser. // errorMessage dialog contains errors for func x, func y and func z - try { newx = p1.Eval(); } catch(Parser::exception_type &e) { showParserError("1st func : ",e); } - try { newy = p2.Eval(); } catch(Parser::exception_type &e) { showParserError("2nd func : ",e); } - try { newz = p3.Eval(); } catch(Parser::exception_type &e) { showParserError("3rd func : ",e); } - if(ID(filter) == FF_VERT_COLOR) - { - try { newa = p4.Eval(); } catch(Parser::exception_type &e) { showParserError("4th func : ",e); } + try { + newx = p1.Eval(); } - if(errorMsg != "") + catch (Parser::exception_type& e) { + showParserError("1st func : ", e); + } + try { + newy = p2.Eval(); + } + catch (Parser::exception_type& e) { + showParserError("2nd func : ", e); + } + try { + newz = p3.Eval(); + } + catch (Parser::exception_type& e) { + showParserError("3rd func : ", e); + } + if (ID(filter) == FF_VERT_COLOR) { + try { + newa = p4.Eval(); + } + catch (Parser::exception_type& e) { + showParserError("4th func : ", e); + } + } + if (errorMsg != "") throw MLException(errorMsg); - - if (ID(filter) == FF_GEOM_FUNC) // set new vertex coord for this iteration + + if (ID(filter) == FF_GEOM_FUNC) // set new vertex coord for this iteration (*vi).P() = Point3m(newx, newy, newz); if (ID(filter) == FF_VERT_NORMAL) // set new color for this iteration (*vi).N() = Point3m(newx, newy, newz); @@ -545,101 +829,104 @@ std::map FilterFunctionPlugin::applyFilter( (*vi).C() = Color4b(newx, newy, newz, newa); m.updateDataMask(MeshModel::MM_VERTCOLOR); } - } - - if(ID(filter) == FF_GEOM_FUNC) { + + if (ID(filter) == FF_GEOM_FUNC) { // update bounding box, normalize normals tri::UpdateNormal::PerVertexNormalizedPerFace(m.cm); tri::UpdateNormal::NormalizePerFace(m.cm); tri::UpdateBounding::Box(m.cm); } - + // if succeeded log stream contains number of vertices processed and time elapsed - log( "%d vertices processed in %.2f sec.", m.cm.vn, (clock() - start) / (float) CLOCKS_PER_SEC); - } - break; - - case FF_VERT_QUALITY: - { - std::string func_q = par.getString("q").toStdString(); - bool onSelected = par.getBool("onselected"); - + log("%d vertices processed in %.2f sec.", + m.cm.vn, + (clock() - start) / (float) CLOCKS_PER_SEC); + } break; + + case FF_VERT_QUALITY: { + std::string func_q = par.getString("q").toStdString(); + bool onSelected = par.getBool("onselected"); + if (onSelected && m.cm.svn == 0 && m.cm.sfn == 0) // if no selection at all, fail { log("Cannot apply only on selection: there is no selection"); throw MLException("Cannot apply only on selection: there is no selection"); } - if (onSelected && (m.cm.svn == 0 && m.cm.sfn > 0)) // if no vert selected, but some faces selected, use their vertices + if (onSelected && + (m.cm.svn == 0 && + m.cm.sfn > 0)) // if no vert selected, but some faces selected, use their vertices { tri::UpdateSelection::VertexClear(m.cm); tri::UpdateSelection::VertexFromFaceLoose(m.cm); } - + m.updateDataMask(MeshModel::MM_VERTQUALITY); - + // muparser initialization and define custom variables Parser p; - setPerVertexVariables(p,m.cm); - + setPerVertexVariables(p, m.cm); + // set expression to calc with parser p.SetExpr(conversion::fromStringToWString(func_q)); - + // every parser variables is related to vertex coord and attributes. - time_t start = clock(); + time_t start = clock(); CMeshO::VertexIterator vi; - for(vi = m.cm.vert.begin(); vi != m.cm.vert.end(); ++vi) - if(!(*vi).IsD()) - if ((!onSelected) || ((*vi).IsS())) - { - setAttributes(vi,m.cm); - + for (vi = m.cm.vert.begin(); vi != m.cm.vert.end(); ++vi) + if (!(*vi).IsD()) + if ((!onSelected) || ((*vi).IsS())) { + setAttributes(vi, m.cm); + // use parser to evaluate function specified above // in case of fail, errorMessage dialog contains details of parser's error try { (*vi).Q() = p.Eval(); - } catch(Parser::exception_type &e) { + } + catch (Parser::exception_type& e) { throw MLException(conversion::fromWStringToString(e.GetMsg()).c_str()); } } - + // normalize quality with values in [0..1] - if(par.getBool("normalize")) tri::UpdateQuality::VertexNormalize(m.cm); - + if (par.getBool("normalize")) + tri::UpdateQuality::VertexNormalize(m.cm); + // map quality into per-vertex color - if(par.getBool("map")) - { + if (par.getBool("map")) { tri::UpdateColor::PerVertexQualityRamp(m.cm); m.updateDataMask(MeshModel::MM_VERTCOLOR); } // if succeeded log stream contains number of vertices and time elapsed - log( "%d vertices processed in %.2f sec.", m.cm.vn, (clock() - start) / (float) CLOCKS_PER_SEC); - } - break; - case FF_VERT_TEXTURE_FUNC: - { - std::string func_u = par.getString("u").toStdString(); - std::string func_v = par.getString("v").toStdString(); - bool onSelected = par.getBool("onselected"); - + log("%d vertices processed in %.2f sec.", + m.cm.vn, + (clock() - start) / (float) CLOCKS_PER_SEC); + } break; + case FF_VERT_TEXTURE_FUNC: { + std::string func_u = par.getString("u").toStdString(); + std::string func_v = par.getString("v").toStdString(); + bool onSelected = par.getBool("onselected"); + if (onSelected && m.cm.svn == 0 && m.cm.sfn == 0) // if no selection at all, fail { log("Cannot apply only on selection: there is no selection"); throw MLException("Cannot apply only on selection: there is no selection"); } - if (onSelected && (m.cm.svn == 0 && m.cm.sfn > 0)) // if no vert selected, but some faces selected, use their vertices + if (onSelected && + (m.cm.svn == 0 && + m.cm.sfn > 0)) // if no vert selected, but some faces selected, use their vertices { tri::UpdateSelection::VertexClear(m.cm); tri::UpdateSelection::VertexFromFaceLoose(m.cm); } - + m.updateDataMask(MeshModel::MM_VERTTEXCOORD); - + // muparser initialization and define custom variables - Parser pu,pv; - setPerVertexVariables(pu,m.cm); - setPerVertexVariables(pv,m.cm); - + Parser pu, pv; + setPerVertexVariables(pu, m.cm); + setPerVertexVariables(pv, m.cm); + // set expression to calc with parser #ifdef _UNICODE pu.SetExpr(conversion::fromStringToWString(func_u)); @@ -648,439 +935,548 @@ std::map FilterFunctionPlugin::applyFilter( pu.SetExpr(func_u); pv.SetExpr(func_v); #endif - + // every parser variables is related to vertex coord and attributes. - time_t start = clock(); + time_t start = clock(); CMeshO::VertexIterator vi; - for(vi = m.cm.vert.begin(); vi != m.cm.vert.end(); ++vi) - if(!(*vi).IsD()) - if ((!onSelected) || ((*vi).IsS())) - { - setAttributes(vi,m.cm); - + for (vi = m.cm.vert.begin(); vi != m.cm.vert.end(); ++vi) + if (!(*vi).IsD()) + if ((!onSelected) || ((*vi).IsS())) { + setAttributes(vi, m.cm); + // use parser to evaluate function specified above // in case of fail, errorMessage dialog contains details of parser's error try { (*vi).T().U() = pu.Eval(); (*vi).T().V() = pv.Eval(); - } catch(Parser::exception_type &e) { + } + catch (Parser::exception_type& e) { throw MLException(conversion::fromWStringToString(e.GetMsg()).c_str()); } } - - log( "%d vertices processed in %.2f sec.", m.cm.vn, (clock() - start) / (float) CLOCKS_PER_SEC); - } - break; - case FF_WEDGE_TEXTURE_FUNC: - { - std::string func_u0 = par.getString("u0").toStdString(); - std::string func_v0 = par.getString("v0").toStdString(); - std::string func_u1 = par.getString("u1").toStdString(); - std::string func_v1 = par.getString("v1").toStdString(); - std::string func_u2 = par.getString("u2").toStdString(); - std::string func_v2 = par.getString("v2").toStdString(); - bool onSelected = par.getBool("onselected"); - + + log("%d vertices processed in %.2f sec.", + m.cm.vn, + (clock() - start) / (float) CLOCKS_PER_SEC); + } break; + case FF_WEDGE_TEXTURE_FUNC: { + std::string func_u0 = par.getString("u0").toStdString(); + std::string func_v0 = par.getString("v0").toStdString(); + std::string func_u1 = par.getString("u1").toStdString(); + std::string func_v1 = par.getString("v1").toStdString(); + std::string func_u2 = par.getString("u2").toStdString(); + std::string func_v2 = par.getString("v2").toStdString(); + bool onSelected = par.getBool("onselected"); + if (onSelected && m.cm.sfn == 0) // if no selection, fail { log("Cannot apply only on selection: there is no selection"); throw MLException("Cannot apply only on selection: there is no selection"); } - + m.updateDataMask(MeshModel::MM_VERTTEXCOORD); - + // muparser initialization and define custom variables - Parser pu0,pv0,pu1,pv1,pu2,pv2; - setPerFaceVariables(pu0,m.cm); setPerFaceVariables(pv0,m.cm); - setPerFaceVariables(pu1,m.cm); setPerFaceVariables(pv1,m.cm); - setPerFaceVariables(pu2,m.cm); setPerFaceVariables(pv2,m.cm); - + Parser pu0, pv0, pu1, pv1, pu2, pv2; + setPerFaceVariables(pu0, m.cm); + setPerFaceVariables(pv0, m.cm); + setPerFaceVariables(pu1, m.cm); + setPerFaceVariables(pv1, m.cm); + setPerFaceVariables(pu2, m.cm); + setPerFaceVariables(pv2, m.cm); + // set expression to calc with parser - pu0.SetExpr(conversion::fromStringToWString(func_u0)); pv0.SetExpr(conversion::fromStringToWString(func_v0)); - pu1.SetExpr(conversion::fromStringToWString(func_u1)); pv1.SetExpr(conversion::fromStringToWString(func_v1)); - pu2.SetExpr(conversion::fromStringToWString(func_u2)); pv2.SetExpr(conversion::fromStringToWString(func_v2)); - + pu0.SetExpr(conversion::fromStringToWString(func_u0)); + pv0.SetExpr(conversion::fromStringToWString(func_v0)); + pu1.SetExpr(conversion::fromStringToWString(func_u1)); + pv1.SetExpr(conversion::fromStringToWString(func_v1)); + pu2.SetExpr(conversion::fromStringToWString(func_u2)); + pv2.SetExpr(conversion::fromStringToWString(func_v2)); + // every parser variables is related to vertex coord and attributes. time_t start = clock(); - for(CMeshO::FaceIterator fi = m.cm.face.begin(); fi != m.cm.face.end(); ++fi) - if(!(*fi).IsD()) - if ((!onSelected) || ((*fi).IsS())) - { - setAttributes(fi,m.cm); - + for (CMeshO::FaceIterator fi = m.cm.face.begin(); fi != m.cm.face.end(); ++fi) + if (!(*fi).IsD()) + if ((!onSelected) || ((*fi).IsS())) { + setAttributes(fi, m.cm); + // use parser to evaluate function specified above // in case of fail, errorMessage dialog contains details of parser's error try { - (*fi).WT(0).U() = pu0.Eval(); (*fi).WT(0).V() = pv0.Eval(); - (*fi).WT(1).U() = pu1.Eval(); (*fi).WT(1).V() = pv1.Eval(); - (*fi).WT(2).U() = pu2.Eval(); (*fi).WT(2).V() = pv2.Eval(); - } catch(Parser::exception_type &e) { + (*fi).WT(0).U() = pu0.Eval(); + (*fi).WT(0).V() = pv0.Eval(); + (*fi).WT(1).U() = pu1.Eval(); + (*fi).WT(1).V() = pv1.Eval(); + (*fi).WT(2).U() = pu2.Eval(); + (*fi).WT(2).V() = pv2.Eval(); + } + catch (Parser::exception_type& e) { throw MLException(conversion::fromWStringToString(e.GetMsg()).c_str()); } } - - log( "%d faces processed in %.2f sec.", m.cm.fn, (clock() - start) / (float) CLOCKS_PER_SEC); - } - break; - case FF_FACE_COLOR: - { - std::string func_r = par.getString("r").toStdString(); - std::string func_g = par.getString("g").toStdString(); - std::string func_b = par.getString("b").toStdString(); - std::string func_a = par.getString("a").toStdString(); - bool onSelected = par.getBool("onselected"); - + + log("%d faces processed in %.2f sec.", m.cm.fn, (clock() - start) / (float) CLOCKS_PER_SEC); + } break; + case FF_FACE_COLOR: { + std::string func_r = par.getString("r").toStdString(); + std::string func_g = par.getString("g").toStdString(); + std::string func_b = par.getString("b").toStdString(); + std::string func_a = par.getString("a").toStdString(); + bool onSelected = par.getBool("onselected"); + if (onSelected && m.cm.sfn == 0) // if no selection, fail { log("Cannot apply only on selection: there is no selection"); throw MLException("Cannot apply only on selection: there is no selection"); } - + m.updateDataMask(MeshModel::MM_FACECOLOR); - + // muparser initialization and explicitly define parser variables // every function must uses own parser and variables - Parser p1,p2,p3,p4; - - setPerFaceVariables(p1,m.cm); - setPerFaceVariables(p2,m.cm); - setPerFaceVariables(p3,m.cm); - setPerFaceVariables(p4,m.cm); - + Parser p1, p2, p3, p4; + + setPerFaceVariables(p1, m.cm); + setPerFaceVariables(p2, m.cm); + setPerFaceVariables(p3, m.cm); + setPerFaceVariables(p4, m.cm); + p1.SetExpr(conversion::fromStringToWString(func_r)); p2.SetExpr(conversion::fromStringToWString(func_g)); p3.SetExpr(conversion::fromStringToWString(func_b)); p4.SetExpr(conversion::fromStringToWString(func_a)); - + // RGB is related to every face CMeshO::FaceIterator fi; - double newr=0,newg=0,newb=0,newa=255; + double newr = 0, newg = 0, newb = 0, newa = 255; errorMsg = ""; - + time_t start = clock(); - + // every parser variables is related to face attributes. - for(fi = m.cm.face.begin(); fi != m.cm.face.end(); ++fi) - if(!(*fi).IsD()) - if ((!onSelected) || ((*fi).IsS())) - { - setAttributes(fi,m.cm); - + for (fi = m.cm.face.begin(); fi != m.cm.face.end(); ++fi) + if (!(*fi).IsD()) + if ((!onSelected) || ((*fi).IsS())) { + setAttributes(fi, m.cm); + // evaluate functions to generate new color // in case of fail, error dialog contains details of parser's error - try { newr = p1.Eval(); } catch(Parser::exception_type &e) { showParserError("func r: ",e); } - try { newg = p2.Eval(); } catch(Parser::exception_type &e) { showParserError("func g: ",e); } - try { newb = p3.Eval(); } catch(Parser::exception_type &e) { showParserError("func b: ",e); } - try { newa = p4.Eval(); } catch(Parser::exception_type &e) { showParserError("func a: ",e); } - - if(errorMsg != "") + try { + newr = p1.Eval(); + } + catch (Parser::exception_type& e) { + showParserError("func r: ", e); + } + try { + newg = p2.Eval(); + } + catch (Parser::exception_type& e) { + showParserError("func g: ", e); + } + try { + newb = p3.Eval(); + } + catch (Parser::exception_type& e) { + showParserError("func b: ", e); + } + try { + newa = p4.Eval(); + } + catch (Parser::exception_type& e) { + showParserError("func a: ", e); + } + + if (errorMsg != "") throw MLException(errorMsg); - + // set new color for this iteration - (*fi).C() = Color4b(newr,newg,newb,newa); + (*fi).C() = Color4b(newr, newg, newb, newa); } // if succeeded log stream contains number of vertices processed and time elapsed - log( "%d faces processed in %.2f sec.", m.cm.fn, (clock() - start) / (float) CLOCKS_PER_SEC); + log("%d faces processed in %.2f sec.", m.cm.fn, (clock() - start) / (float) CLOCKS_PER_SEC); + + } break; + + case FF_FACE_QUALITY: { + std::string func_q = par.getString("q").toStdString(); + bool onSelected = par.getBool("onselected"); - } - break; - - case FF_FACE_QUALITY: - { - std::string func_q = par.getString("q").toStdString(); - bool onSelected = par.getBool("onselected"); - if (onSelected && m.cm.sfn == 0) // if no selection, fail { log("Cannot apply only on selection: there is no selection"); throw MLException("Cannot apply only on selection: there is no selection"); } - + m.updateDataMask(MeshModel::MM_FACEQUALITY); - + // muparser initialization and define custom variables Parser pf; - setPerFaceVariables(pf,m.cm); - + setPerFaceVariables(pf, m.cm); + // set expression to calc with parser pf.SetExpr(conversion::fromStringToWString(func_q)); - + time_t start = clock(); - errorMsg = ""; - + errorMsg = ""; + // every parser variables is related to face attributes. CMeshO::FaceIterator fi; - for(fi = m.cm.face.begin(); fi != m.cm.face.end(); ++fi) - if(!(*fi).IsD()) - if ((!onSelected) || ((*fi).IsS())) - { - setAttributes(fi,m.cm); - + for (fi = m.cm.face.begin(); fi != m.cm.face.end(); ++fi) + if (!(*fi).IsD()) + if ((!onSelected) || ((*fi).IsS())) { + setAttributes(fi, m.cm); + // evaluate functions to generate new quality // in case of fail, error dialog contains details of parser's error - try { (*fi).Q() = pf.Eval(); } - catch(Parser::exception_type &e) { - showParserError("func q: ",e); + try { + (*fi).Q() = pf.Eval(); } - if(errorMsg != "") + catch (Parser::exception_type& e) { + showParserError("func q: ", e); + } + if (errorMsg != "") throw MLException(errorMsg); } - + // normalize quality with values in [0..1] - if(par.getBool("normalize")) tri::UpdateQuality::FaceNormalize(m.cm); - + if (par.getBool("normalize")) + tri::UpdateQuality::FaceNormalize(m.cm); + // map quality into per-vertex color - if(par.getBool("map")) - { + if (par.getBool("map")) { tri::UpdateColor::PerFaceQualityRamp(m.cm); m.updateDataMask(MeshModel::MM_FACECOLOR); } - - // if succeeded log stream contains number of faces processed and time elapsed - log( "%d faces processed in %.2f sec.", m.cm.fn, (clock() - start) / (float) CLOCKS_PER_SEC); - } - break; - - case FF_DEF_VERT_ATTRIB : - { + // if succeeded log stream contains number of faces processed and time elapsed + log("%d faces processed in %.2f sec.", m.cm.fn, (clock() - start) / (float) CLOCKS_PER_SEC); + + } break; + + case FF_DEF_VERT_SCALAR_ATTRIB: { std::string name = par.getString("name").toStdString(); std::string expr = par.getString("expr").toStdString(); - + // add per-vertex attribute with type float and name specified by user CMeshO::PerVertexAttributeHandle h; - if(tri::HasPerVertexAttribute(m.cm,name)) - { + if (tri::HasPerVertexAttribute(m.cm, name)) { h = tri::Allocator::FindPerVertexAttribute(m.cm, name); - if(!tri::Allocator::IsValidHandle(m.cm,h)) - { + if (!tri::Allocator::IsValidHandle(m.cm, h)) { throw MLException("attribute already exists with a different type"); } } else - h = tri::Allocator::AddPerVertexAttribute (m.cm,name); - - std::vector AllVertexAttribName; - tri::Allocator::GetAllPerVertexAttribute(m.cm,AllVertexAttribName); - qDebug("Now mesh has %lu vertex scalar attribute",AllVertexAttribName.size()); + h = tri::Allocator::AddPerVertexAttribute(m.cm, name); + Parser p; - setPerVertexVariables(p,m.cm); + setPerVertexVariables(p, m.cm); p.SetExpr(conversion::fromStringToWString(expr)); - + time_t start = clock(); - + // perform calculation of attribute's value with function specified by user CMeshO::VertexIterator vi; - for(vi = m.cm.vert.begin(); vi != m.cm.vert.end(); ++vi)if(!(*vi).IsD()) - { - setAttributes(vi,m.cm); - - // add new user-defined attribute - try { - h[vi] = p.Eval(); - } catch(Parser::exception_type &e) { - throw MLException(conversion::fromWStringToString(e.GetMsg()).c_str()); + for (vi = m.cm.vert.begin(); vi != m.cm.vert.end(); ++vi) + if (!(*vi).IsD()) { + setAttributes(vi, m.cm); + + // add new user-defined attribute + try { + h[vi] = p.Eval(); + } + catch (Parser::exception_type& e) { + throw MLException(conversion::fromWStringToString(e.GetMsg()).c_str()); + } } - } - + // add string, double and handler to vector. // vectors keep tracks of new attributes and let muparser use explicit variables // it's possible to use custom attributes in other filters v_attrNames.push_back(name); v_attrValue.push_back(0); v_handlers.push_back(h); - - // if succeeded log stream contains number of vertices processed and time elapsed - log( "%d vertices processed in %.2f sec.", m.cm.vn, (clock() - start) / (float) CLOCKS_PER_SEC); - } - break; - - case FF_DEF_FACE_ATTRIB : - { + // if succeeded log stream contains number of vertices processed and time elapsed + log("%d vertices processed in %.2f sec.", + m.cm.vn, + (clock() - start) / (float) CLOCKS_PER_SEC); + + } break; + + case FF_DEF_FACE_SCALAR_ATTRIB: { std::string name = par.getString("name").toStdString(); std::string expr = par.getString("expr").toStdString(); - + // add per-face attribute with type float and name specified by user // add per-vertex attribute with type float and name specified by user CMeshO::PerFaceAttributeHandle h; - if(tri::HasPerFaceAttribute(m.cm,name)) - { + if (tri::HasPerFaceAttribute(m.cm, name)) { h = tri::Allocator::FindPerFaceAttribute(m.cm, name); - if(!tri::Allocator::IsValidHandle(m.cm,h)) - { + if (!tri::Allocator::IsValidHandle(m.cm, h)) { throw MLException("attribute already exists with a different type"); } } else - h = tri::Allocator::AddPerFaceAttribute (m.cm,name); + h = tri::Allocator::AddPerFaceAttribute(m.cm, name); Parser p; - setPerFaceVariables(p,m.cm); + setPerFaceVariables(p, m.cm); p.SetExpr(conversion::fromStringToWString(expr)); - + time_t start = clock(); - + // every parser variables is related to face attributes. CMeshO::FaceIterator fi; - for(fi = m.cm.face.begin(); fi != m.cm.face.end(); ++fi)if(!(*fi).IsD()) - { - setAttributes(fi,m.cm); - - // add new user-defined attribute - try { - h[fi] = p.Eval(); - } catch(Parser::exception_type &e) { - throw MLException(conversion::fromWStringToString(e.GetMsg()).c_str()); + for (fi = m.cm.face.begin(); fi != m.cm.face.end(); ++fi) + if (!(*fi).IsD()) { + setAttributes(fi, m.cm); + + // add new user-defined attribute + try { + h[fi] = p.Eval(); + } + catch (Parser::exception_type& e) { + throw MLException(conversion::fromWStringToString(e.GetMsg()).c_str()); + } + } + + // if succeeded log stream contains number of vertices processed and time elapsed + log("%d faces processed in %.2f sec.", m.cm.fn, (clock() - start) / (float) CLOCKS_PER_SEC); + + } break; + + case FF_DEF_VERT_POINT_ATTRIB: { + std::string name = par.getString("name").toStdString(); + std::string x_expr = par.getString("x_expr").toStdString(); + std::string y_expr = par.getString("y_expr").toStdString(); + std::string z_expr = par.getString("z_expr").toStdString(); + + // add per-vertex attribute with type float and name specified by user + CMeshO::PerVertexAttributeHandle h; + if (tri::HasPerVertexAttribute(m.cm, name)) { + h = tri::Allocator::FindPerVertexAttribute(m.cm, name); + if (!tri::Allocator::IsValidHandle(m.cm, h)) { + throw MLException("attribute already exists with a different type"); } } - - // // add string, double and handler to vector. - // // vectors keep tracks of new attributes and let muparser use explicit variables - // // it's possible to use custom attributes in other filters - // f_attrNames.push_back(name); - // f_attrValue.push_back(0); - // fhandlers.push_back(h); - - // if succeeded log stream contains number of vertices processed and time elapsed - log( "%d faces processed in %.2f sec.", m.cm.fn, (clock() - start) / (float) CLOCKS_PER_SEC); + else + h = tri::Allocator::AddPerVertexAttribute(m.cm, name); - } - break; - - case FF_GRID : - { + Parser p_x, p_y, p_z; + setPerVertexVariables(p_x, m.cm); + setPerVertexVariables(p_y, m.cm); + setPerVertexVariables(p_z, m.cm); + p_x.SetExpr(conversion::fromStringToWString(x_expr)); + p_y.SetExpr(conversion::fromStringToWString(y_expr)); + p_z.SetExpr(conversion::fromStringToWString(z_expr)); + + time_t start = clock(); + + // perform calculation of attribute's value with function specified by user + CMeshO::VertexIterator vi; + for (vi = m.cm.vert.begin(); vi != m.cm.vert.end(); ++vi) + if (!(*vi).IsD()) { + setAttributes(vi, m.cm); + + try { + h[vi][0] = p_x.Eval(); + h[vi][1] = p_y.Eval(); + h[vi][2] = p_z.Eval(); + } + catch (Parser::exception_type& e) { + throw MLException(conversion::fromWStringToString(e.GetMsg()).c_str()); + } + } + + // add string, double and handler to vector. + // vectors keep tracks of new attributes and let muparser use explicit variables + // it's possible to use custom attributes in other filters + + //v_attrNames.push_back(name); + //v_attrValue.push_back(0); + //v_handlers.push_back(h); + + // if succeeded log stream contains number of vertices processed and time elapsed + log("%d vertices processed in %.2f sec.", + m.cm.vn, + (clock() - start) / (float) CLOCKS_PER_SEC); + + } break; + + case FF_DEF_FACE_POINT_ATTRIB: { + std::string name = par.getString("name").toStdString(); + std::string x_expr = par.getString("x_expr").toStdString(); + std::string y_expr = par.getString("y_expr").toStdString(); + std::string z_expr = par.getString("z_expr").toStdString(); + + // add per-face attribute with type float and name specified by user + // add per-vertex attribute with type float and name specified by user + CMeshO::PerFaceAttributeHandle h; + if (tri::HasPerFaceAttribute(m.cm, name)) { + h = tri::Allocator::FindPerFaceAttribute(m.cm, name); + if (!tri::Allocator::IsValidHandle(m.cm, h)) { + throw MLException("attribute already exists with a different type"); + } + } + else + h = tri::Allocator::AddPerFaceAttribute(m.cm, name); + Parser p_x, p_y, p_z; + setPerFaceVariables(p_x, m.cm); + setPerFaceVariables(p_y, m.cm); + setPerFaceVariables(p_z, m.cm); + p_x.SetExpr(conversion::fromStringToWString(x_expr)); + p_y.SetExpr(conversion::fromStringToWString(y_expr)); + p_z.SetExpr(conversion::fromStringToWString(z_expr)); + + time_t start = clock(); + + // every parser variables is related to face attributes. + CMeshO::FaceIterator fi; + for (fi = m.cm.face.begin(); fi != m.cm.face.end(); ++fi) + if (!(*fi).IsD()) { + setAttributes(fi, m.cm); + + // add new user-defined attribute + try { + h[fi][0] = p_x.Eval(); + h[fi][1] = p_y.Eval(); + h[fi][2] = p_z.Eval(); + } + catch (Parser::exception_type& e) { + throw MLException(conversion::fromWStringToString(e.GetMsg()).c_str()); + } + } + + // if succeeded log stream contains number of vertices processed and time elapsed + log("%d faces processed in %.2f sec.", m.cm.fn, (clock() - start) / (float) CLOCKS_PER_SEC); + + } break; + + case FF_GRID: { // obtain parameters to generate 2D Grid - int w = par.getInt("numVertX"); - int h = par.getInt("numVertY"); + int w = par.getInt("numVertX"); + int h = par.getInt("numVertY"); Scalarm wl = par.getFloat("absScaleX"); Scalarm hl = par.getFloat("absScaleY"); - - if(w <= 0 || h <= 0) { + + if (w <= 0 || h <= 0) { throw MLException("number of vertices must be positive"); } - + // use Grid function to generate Grid tri::Grid(m.cm, w, h, wl, hl); - + // if "centered on origin" is checked than move generated Grid in (0,0,0) - if(par.getBool("center")) - { + if (par.getBool("center")) { // move x and y - Scalarm halfw = Scalarm(w-1)/2; - Scalarm halfh = Scalarm(h-1)/2; - Scalarm wld = wl/Scalarm(w); - Scalarm hld = hl/Scalarm(h); - - for(auto vi = m.cm.vert.begin(); vi != m.cm.vert.end(); ++vi) - { + Scalarm halfw = Scalarm(w - 1) / 2; + Scalarm halfh = Scalarm(h - 1) / 2; + Scalarm wld = wl / Scalarm(w); + Scalarm hld = hl / Scalarm(h); + + for (auto vi = m.cm.vert.begin(); vi != m.cm.vert.end(); ++vi) { (*vi).P()[0] = (*vi).P()[0] - (wld * halfw); (*vi).P()[1] = (*vi).P()[1] - (hld * halfh); } } // update bounding box, normals // Matrix44m rot; rot.SetRotateDeg(180,Point3m(0,1,0)); - Matrix44m rot; rot.SetScale(-1,1,-1); - tri::UpdatePosition::Matrix(m.cm,rot,false); + Matrix44m rot; + rot.SetScale(-1, 1, -1); + tri::UpdatePosition::Matrix(m.cm, rot, false); m.updateBoxAndNormals(); - } - break; - case FF_ISOSURFACE : - { - SimpleVolume > volume; - - typedef vcg::tri::TrivialWalker > > MyWalker; - typedef vcg::tri::MarchingCubes MyMarchingCubes; - MyWalker walker; - + } break; + case FF_ISOSURFACE: { + SimpleVolume> volume; + + typedef vcg::tri::TrivialWalker>> MyWalker; + typedef vcg::tri::MarchingCubes MyMarchingCubes; + MyWalker walker; + Box3f RangeBBox; - RangeBBox.min[0]=par.getFloat("minX"); - RangeBBox.min[1]=par.getFloat("minY"); - RangeBBox.min[2]=par.getFloat("minZ"); - RangeBBox.max[0]=par.getFloat("maxX"); - RangeBBox.max[1]=par.getFloat("maxY"); - RangeBBox.max[2]=par.getFloat("maxZ"); - double step=par.getFloat("voxelSize"); - Point3i siz= Point3i::Construct((RangeBBox.max-RangeBBox.min)*(1.0/step)); - + RangeBBox.min[0] = par.getFloat("minX"); + RangeBBox.min[1] = par.getFloat("minY"); + RangeBBox.min[2] = par.getFloat("minZ"); + RangeBBox.max[0] = par.getFloat("maxX"); + RangeBBox.max[1] = par.getFloat("maxY"); + RangeBBox.max[2] = par.getFloat("maxZ"); + double step = par.getFloat("voxelSize"); + Point3i siz = Point3i::Construct((RangeBBox.max - RangeBBox.min) * (1.0 / step)); + Parser p; - double x,y,z; + double x, y, z; p.DefineVar(conversion::fromStringToWString("x"), &x); p.DefineVar(conversion::fromStringToWString("y"), &y); p.DefineVar(conversion::fromStringToWString("z"), &z); std::string expr = par.getString("expr").toStdString(); p.SetExpr(conversion::fromStringToWString(expr)); - log("Filling a Volume of %i %i %i",siz[0],siz[1],siz[2]); - volume.Init(siz,RangeBBox); - for(double i=0;i(m.cm, volume, mc, 0); // Matrix44m tr; tr.SetIdentity(); tr.SetTranslate(rbb.min[0],rbb.min[1],rbb.min[2]); // Matrix44m sc; sc.SetIdentity(); sc.SetScale(step,step,step); // tr=tr*sc; - + // tri::UpdatePosition::Matrix(m.cm,tr); tri::UpdateNormal::PerVertexNormalizedPerFace(m.cm); - tri::UpdateBounding::Box(m.cm); // updates bounding box - - } - break; - - case FF_REFINE : - { + tri::UpdateBounding::Box(m.cm); // updates bounding box + + } break; + + case FF_REFINE: { std::string condSelect = par.getString("condSelect").toStdString(); - + std::string expr1 = par.getString("x").toStdString(); std::string expr2 = par.getString("y").toStdString(); std::string expr3 = par.getString("z").toStdString(); - - bool errorMidPoint = false; - bool errorEdgePred = false; - std::string msg = ""; - + + bool errorMidPoint = false; + bool errorEdgePred = false; + std::string msg = ""; + // check parsing errors while creating two func obj // display error message - MidPointCustom mid = MidPointCustom(m.cm,expr1,expr2,expr3,errorMidPoint,msg); - CustomEdge edge = CustomEdge(condSelect,errorEdgePred,msg); - if(errorMidPoint || errorEdgePred) - { + MidPointCustom mid = + MidPointCustom(m.cm, expr1, expr2, expr3, errorMidPoint, msg); + CustomEdge edge = CustomEdge(condSelect, errorEdgePred, msg); + if (errorMidPoint || errorEdgePred) { throw MLException(msg.c_str()); } - + // Refine current mesh. // Only edge specified with CustomEdge pred are selected // and the new vertex is chosen with MidPointCustom created above - vcg::tri::RefineE, CustomEdge > - (m.cm, mid, edge, false, cb); + vcg::tri::RefineE, CustomEdge>( + m.cm, mid, edge, false, cb); m.updateBoxAndNormals(); - m.clearDataMask( MeshModel::MM_VERTMARK); - //vcg::tri::UpdateNormal::PerVertexNormalizedPerFace(m.cm); - } - break; - - default : - wrongActionCalled(filter); + m.clearDataMask(MeshModel::MM_VERTMARK); + // vcg::tri::UpdateNormal::PerVertexNormalizedPerFace(m.cm); + } break; + + default: wrongActionCalled(filter); } return std::map(); } // display parsing error in dialog -void FilterFunctionPlugin::showParserError(const QString &s, Parser::exception_type &e) +void FilterFunctionPlugin::showParserError(const QString& s, Parser::exception_type& e) { errorMsg += s; errorMsg += conversion::fromWStringToString(e.GetMsg()).c_str(); @@ -1088,160 +1484,165 @@ void FilterFunctionPlugin::showParserError(const QString &s, Parser::exception_t } // set per-vertex attributes associated to parser variables -void FilterFunctionPlugin::setAttributes(CMeshO::VertexIterator &vi, CMeshO &m) +void FilterFunctionPlugin::setAttributes(CMeshO::VertexIterator& vi, CMeshO& m) { x = (*vi).P()[0]; // coord x y = (*vi).P()[1]; // coord y z = (*vi).P()[2]; // coord z - + nx = (*vi).N()[0]; // normal coord x ny = (*vi).N()[1]; // normal coord y nz = (*vi).N()[2]; // normal coord z - - r = (*vi).C()[0]; // color R - g = (*vi).C()[1]; // color G - b = (*vi).C()[2]; // color B - a = (*vi).C()[3]; // color ALPHA - - q = (*vi).Q(); // quality - - vsel = ((*vi).IsS()) ? 1.0 : 0.0; //selection - - if(tri::HasPerVertexRadius(m)) rad = (*vi).R(); - else rad=0; - + + r = (*vi).C()[0]; // color R + g = (*vi).C()[1]; // color G + b = (*vi).C()[2]; // color B + a = (*vi).C()[3]; // color ALPHA + + q = (*vi).Q(); // quality + + vsel = ((*vi).IsS()) ? 1.0 : 0.0; // selection + + if (tri::HasPerVertexRadius(m)) + rad = (*vi).R(); + else + rad = 0; + v = vi - m.vert.begin(); // zero based index of current vertex - - if(tri::HasPerVertexTexCoord(m)) - { - vtu=(*vi).T().U(); - vtv=(*vi).T().V(); - ti = (*vi).T().N(); + + if (tri::HasPerVertexTexCoord(m)) { + vtu = (*vi).T().U(); + vtv = (*vi).T().V(); + ti = (*vi).T().N(); } - else { vtu=vtv=ti=0; } - + else { + vtu = vtv = ti = 0; + } + // if user-defined attributes exist (vector is not empty) // set variables to explicit value obtained through attribute's handler - for(int i = 0; i < (int) v_attrValue.size(); i++) + for (int i = 0; i < (int) v_attrValue.size(); i++) v_attrValue[i] = v_handlers[i][vi]; - - for(int i = 0; i < (int) v3_handlers.size(); i++) - { - v3_attrValue[i*3+0] = v3_handlers[i][vi].X(); - v3_attrValue[i*3+1] = v3_handlers[i][vi].Y(); - v3_attrValue[i*3+2] = v3_handlers[i][vi].Z(); + + for (int i = 0; i < (int) v3_handlers.size(); i++) { + v3_attrValue[i * 3 + 0] = v3_handlers[i][vi].X(); + v3_attrValue[i * 3 + 1] = v3_handlers[i][vi].Y(); + v3_attrValue[i * 3 + 2] = v3_handlers[i][vi].Z(); } } // set per-face attributes associated to parser variables -void FilterFunctionPlugin::setAttributes(CMeshO::FaceIterator &fi, CMeshO &m) +void FilterFunctionPlugin::setAttributes(CMeshO::FaceIterator& fi, CMeshO& m) { // set attributes for First vertex // coords, normal coords, quality x0 = (*fi).V(0)->P()[0]; y0 = (*fi).V(0)->P()[1]; z0 = (*fi).V(0)->P()[2]; - + nx0 = (*fi).V(0)->N()[0]; ny0 = (*fi).V(0)->N()[1]; nz0 = (*fi).V(0)->N()[2]; - + r0 = (*fi).V(0)->C()[0]; g0 = (*fi).V(0)->C()[1]; b0 = (*fi).V(0)->C()[2]; a0 = (*fi).V(0)->C()[3]; - + q0 = (*fi).V(0)->Q(); - + // set attributes for Second vertex // coords, normal coords, quality x1 = (*fi).V(1)->P()[0]; y1 = (*fi).V(1)->P()[1]; z1 = (*fi).V(1)->P()[2]; - + nx1 = (*fi).V(1)->N()[0]; ny1 = (*fi).V(1)->N()[1]; nz1 = (*fi).V(1)->N()[2]; - + r1 = (*fi).V(1)->C()[0]; g1 = (*fi).V(1)->C()[1]; b1 = (*fi).V(1)->C()[2]; a1 = (*fi).V(1)->C()[3]; - + q1 = (*fi).V(1)->Q(); - + // set attributes for Third vertex // coords, normal coords, quality x2 = (*fi).V(2)->P()[0]; y2 = (*fi).V(2)->P()[1]; z2 = (*fi).V(2)->P()[2]; - + nx2 = (*fi).V(2)->N()[0]; ny2 = (*fi).V(2)->N()[1]; nz2 = (*fi).V(2)->N()[2]; - + r2 = (*fi).V(2)->C()[0]; g2 = (*fi).V(2)->C()[1]; b2 = (*fi).V(2)->C()[2]; a2 = (*fi).V(2)->C()[3]; - + q2 = (*fi).V(2)->Q(); - - if(HasPerFaceQuality(m)) - fq=(*fi).Q(); - else fq=0; - + + if (HasPerFaceQuality(m)) + fq = (*fi).Q(); + else + fq = 0; + // set face color attributes - if(HasPerFaceColor(m)){ + if (HasPerFaceColor(m)) { fr = (*fi).C()[0]; fg = (*fi).C()[1]; fb = (*fi).C()[2]; fa = (*fi).C()[3]; - } else { - fr=fg=fb=fa=255; } - - //face normal + else { + fr = fg = fb = fa = 255; + } + + // face normal fnx = (*fi).N()[0]; fny = (*fi).N()[1]; fnz = (*fi).N()[2]; - + // zero based index of face f = fi - m.face.begin(); - + // zero based index of its vertices v0i = ((*fi).V(0) - &m.vert[0]); v1i = ((*fi).V(1) - &m.vert[0]); v2i = ((*fi).V(2) - &m.vert[0]); - - if(tri::HasPerWedgeTexCoord(m)) - { - wtu0=(*fi).WT(0).U(); - wtv0=(*fi).WT(0).V(); - wtu1=(*fi).WT(1).U(); - wtv1=(*fi).WT(1).V(); - wtu2=(*fi).WT(2).U(); - wtv2=(*fi).WT(2).V(); - ti = (*fi).WT(0).N(); + + if (tri::HasPerWedgeTexCoord(m)) { + wtu0 = (*fi).WT(0).U(); + wtv0 = (*fi).WT(0).V(); + wtu1 = (*fi).WT(1).U(); + wtv1 = (*fi).WT(1).V(); + wtu2 = (*fi).WT(2).U(); + wtv2 = (*fi).WT(2).V(); + ti = (*fi).WT(0).N(); } - else { wtu0=wtv0=wtu1=wtv1=wtu2=wtv2=ti=0; } - - //selection + else { + wtu0 = wtv0 = wtu1 = wtv1 = wtu2 = wtv2 = ti = 0; + } + + // selection vsel0 = ((*fi).V(0)->IsS()) ? 1.0 : 0.0; vsel1 = ((*fi).V(1)->IsS()) ? 1.0 : 0.0; vsel2 = ((*fi).V(2)->IsS()) ? 1.0 : 0.0; - fsel = ((*fi).IsS()) ? 1.0 : 0.0; - + fsel = ((*fi).IsS()) ? 1.0 : 0.0; + // if user-defined attributes exist (vector is not empty) // set variables to explicit value obtained through attribute's handler - for(int i = 0; i < (int) f_attrValue.size(); i++) + for (int i = 0; i < (int) f_attrValue.size(); i++) f_attrValue[i] = f_handlers[i][fi]; } // Function explicitly define parser variables to perform per-vertex filter action // x, y, z for vertex coord, nx, ny, nz for normal coord, r, g ,b for color // and q for quality -void FilterFunctionPlugin::setPerVertexVariables(Parser &p, CMeshO &m) +void FilterFunctionPlugin::setPerVertexVariables(Parser& p, CMeshO& m) { p.DefineVar(conversion::fromStringToWString("x"), &x); p.DefineVar(conversion::fromStringToWString("y"), &y); @@ -1254,13 +1655,13 @@ void FilterFunctionPlugin::setPerVertexVariables(Parser &p, CMeshO &m) p.DefineVar(conversion::fromStringToWString("b"), &b); p.DefineVar(conversion::fromStringToWString("a"), &a); p.DefineVar(conversion::fromStringToWString("q"), &q); - p.DefineVar(conversion::fromStringToWString("vi"),&v); - p.DefineVar(conversion::fromStringToWString("rad"),&rad); - p.DefineVar(conversion::fromStringToWString("vtu"),&vtu); - p.DefineVar(conversion::fromStringToWString("vtv"),&vtv); + p.DefineVar(conversion::fromStringToWString("vi"), &v); + p.DefineVar(conversion::fromStringToWString("rad"), &rad); + p.DefineVar(conversion::fromStringToWString("vtu"), &vtu); + p.DefineVar(conversion::fromStringToWString("vtv"), &vtv); p.DefineVar(conversion::fromStringToWString("ti"), &ti); p.DefineVar(conversion::fromStringToWString("vsel"), &vsel); - + // define var for user-defined attributes (if any exists) // if vector is empty, code won't be executed v_handlers.clear(); @@ -1270,42 +1671,41 @@ void FilterFunctionPlugin::setPerVertexVariables(Parser &p, CMeshO &m) v3_attrNames.clear(); v3_attrValue.clear(); std::vector AllVertexAttribName; - tri::Allocator::GetAllPerVertexAttribute< Scalarm >(m,AllVertexAttribName); - for(int i = 0; i < (int) AllVertexAttribName.size(); i++) - { - CMeshO::PerVertexAttributeHandle hh = tri::Allocator::GetPerVertexAttribute(m, AllVertexAttribName[i]); + tri::Allocator::GetAllPerVertexAttribute(m, AllVertexAttribName); + for (int i = 0; i < (int) AllVertexAttribName.size(); i++) { + CMeshO::PerVertexAttributeHandle hh = + tri::Allocator::GetPerVertexAttribute(m, AllVertexAttribName[i]); v_handlers.push_back(hh); v_attrNames.push_back(AllVertexAttribName[i]); v_attrValue.push_back(0); p.DefineVar(conversion::fromStringToWString(v_attrNames.back()), &v_attrValue.back()); - qDebug("Adding custom per vertex float variable %s",v_attrNames.back().c_str()); + qDebug("Adding custom per vertex float variable %s", v_attrNames.back().c_str()); } AllVertexAttribName.clear(); - tri::Allocator::GetAllPerVertexAttribute< Point3m >(m,AllVertexAttribName); - for(int i = 0; i < (int) AllVertexAttribName.size(); i++) - { - CMeshO::PerVertexAttributeHandle hh3 = tri::Allocator::GetPerVertexAttribute(m, AllVertexAttribName[i]); - + tri::Allocator::GetAllPerVertexAttribute(m, AllVertexAttribName); + for (int i = 0; i < (int) AllVertexAttribName.size(); i++) { + CMeshO::PerVertexAttributeHandle hh3 = + tri::Allocator::GetPerVertexAttribute(m, AllVertexAttribName[i]); + v3_handlers.push_back(hh3); - + v3_attrValue.push_back(0); - v3_attrNames.push_back(AllVertexAttribName[i]+"_x"); + v3_attrNames.push_back(AllVertexAttribName[i] + "_x"); p.DefineVar(conversion::fromStringToWString(v3_attrNames.back()), &v3_attrValue.back()); - + v3_attrValue.push_back(0); - v3_attrNames.push_back(AllVertexAttribName[i]+"_y"); + v3_attrNames.push_back(AllVertexAttribName[i] + "_y"); p.DefineVar(conversion::fromStringToWString(v3_attrNames.back()), &v3_attrValue.back()); - + v3_attrValue.push_back(0); - v3_attrNames.push_back(AllVertexAttribName[i]+"_z"); + v3_attrNames.push_back(AllVertexAttribName[i] + "_z"); p.DefineVar(conversion::fromStringToWString(v3_attrNames.back()), &v3_attrValue.back()); - qDebug("Adding custom per vertex Point3f variable %s",v3_attrNames.back().c_str()); + qDebug("Adding custom per vertex Point3f variable %s", v3_attrNames.back().c_str()); } } - // Function explicitly define parser variables to perform Per-Face filter action -void FilterFunctionPlugin::setPerFaceVariables(Parser &p, CMeshO &m) +void FilterFunctionPlugin::setPerFaceVariables(Parser& p, CMeshO& m) { // coord of the three vertices within a face p.DefineVar(conversion::fromStringToWString("x0"), &x0); @@ -1317,119 +1717,114 @@ void FilterFunctionPlugin::setPerFaceVariables(Parser &p, CMeshO &m) p.DefineVar(conversion::fromStringToWString("x2"), &x2); p.DefineVar(conversion::fromStringToWString("y2"), &y2); p.DefineVar(conversion::fromStringToWString("z2"), &z2); - + // attributes of the vertices // normals: p.DefineVar(conversion::fromStringToWString("nx0"), &nx0); p.DefineVar(conversion::fromStringToWString("ny0"), &ny0); p.DefineVar(conversion::fromStringToWString("nz0"), &nz0); - + p.DefineVar(conversion::fromStringToWString("nx1"), &nx1); p.DefineVar(conversion::fromStringToWString("ny1"), &ny1); p.DefineVar(conversion::fromStringToWString("nz1"), &nz1); - + p.DefineVar(conversion::fromStringToWString("nx2"), &nx2); p.DefineVar(conversion::fromStringToWString("ny2"), &ny2); p.DefineVar(conversion::fromStringToWString("nz2"), &nz2); - + // colors: p.DefineVar(conversion::fromStringToWString("r0"), &r0); p.DefineVar(conversion::fromStringToWString("g0"), &g0); p.DefineVar(conversion::fromStringToWString("b0"), &b0); p.DefineVar(conversion::fromStringToWString("a0"), &a0); - + p.DefineVar(conversion::fromStringToWString("r1"), &r1); p.DefineVar(conversion::fromStringToWString("g1"), &g1); p.DefineVar(conversion::fromStringToWString("b1"), &b1); p.DefineVar(conversion::fromStringToWString("a1"), &a1); - + p.DefineVar(conversion::fromStringToWString("r2"), &r2); p.DefineVar(conversion::fromStringToWString("g2"), &g2); p.DefineVar(conversion::fromStringToWString("b2"), &b2); p.DefineVar(conversion::fromStringToWString("a2"), &a2); - + // quality p.DefineVar(conversion::fromStringToWString("q0"), &q0); p.DefineVar(conversion::fromStringToWString("q1"), &q1); p.DefineVar(conversion::fromStringToWString("q2"), &q2); - + // face color p.DefineVar(conversion::fromStringToWString("fr"), &fr); p.DefineVar(conversion::fromStringToWString("fg"), &fg); p.DefineVar(conversion::fromStringToWString("fb"), &fb); p.DefineVar(conversion::fromStringToWString("fa"), &fa); - + // face normal p.DefineVar(conversion::fromStringToWString("fnx"), &fnx); p.DefineVar(conversion::fromStringToWString("fny"), &fny); p.DefineVar(conversion::fromStringToWString("fnz"), &fnz); - + // face quality p.DefineVar(conversion::fromStringToWString("fq"), &fq); - + // index - p.DefineVar(conversion::fromStringToWString("fi"),&f); - p.DefineVar(conversion::fromStringToWString("vi0"),&v0i); - p.DefineVar(conversion::fromStringToWString("vi1"),&v1i); - p.DefineVar(conversion::fromStringToWString("vi2"),&v2i); - + p.DefineVar(conversion::fromStringToWString("fi"), &f); + p.DefineVar(conversion::fromStringToWString("vi0"), &v0i); + p.DefineVar(conversion::fromStringToWString("vi1"), &v1i); + p.DefineVar(conversion::fromStringToWString("vi2"), &v2i); + // texture - p.DefineVar(conversion::fromStringToWString("wtu0"),&wtu0); - p.DefineVar(conversion::fromStringToWString("wtv0"),&wtv0); - p.DefineVar(conversion::fromStringToWString("wtu1"),&wtu1); - p.DefineVar(conversion::fromStringToWString("wtv1"),&wtv1); - p.DefineVar(conversion::fromStringToWString("wtu2"),&wtu2); - p.DefineVar(conversion::fromStringToWString("wtv2"),&wtv2); + p.DefineVar(conversion::fromStringToWString("wtu0"), &wtu0); + p.DefineVar(conversion::fromStringToWString("wtv0"), &wtv0); + p.DefineVar(conversion::fromStringToWString("wtu1"), &wtu1); + p.DefineVar(conversion::fromStringToWString("wtv1"), &wtv1); + p.DefineVar(conversion::fromStringToWString("wtu2"), &wtu2); + p.DefineVar(conversion::fromStringToWString("wtv2"), &wtv2); p.DefineVar(conversion::fromStringToWString("ti"), &ti); - - //selection + + // selection p.DefineVar(conversion::fromStringToWString("vsel0"), &vsel0); p.DefineVar(conversion::fromStringToWString("vsel1"), &vsel1); p.DefineVar(conversion::fromStringToWString("vsel2"), &vsel2); p.DefineVar(conversion::fromStringToWString("fsel"), &fsel); - + // define var for user-defined attributes (if any exists) // if vector is empty, code won't be executed std::vector AllFaceAttribName; - tri::Allocator::GetAllPerFaceAttribute< Scalarm >(m,AllFaceAttribName); + tri::Allocator::GetAllPerFaceAttribute(m, AllFaceAttribName); f_handlers.clear(); f_attrNames.clear(); f_attrValue.clear(); - for(int i = 0; i < (int) AllFaceAttribName.size(); i++) - { - CMeshO::PerFaceAttributeHandle hh = tri::Allocator::GetPerFaceAttribute(m, AllFaceAttribName[i]); + for (int i = 0; i < (int) AllFaceAttribName.size(); i++) { + CMeshO::PerFaceAttributeHandle hh = + tri::Allocator::GetPerFaceAttribute(m, AllFaceAttribName[i]); f_handlers.push_back(hh); f_attrNames.push_back(AllFaceAttribName[i]); f_attrValue.push_back(0); p.DefineVar(conversion::fromStringToWString(f_attrNames.back()), &f_attrValue.back()); } - } -FilterPlugin::FilterArity FilterFunctionPlugin::filterArity(const QAction* filter ) const +FilterPlugin::FilterArity FilterFunctionPlugin::filterArity(const QAction* filter) const { - switch(ID(filter)) - { - case FF_VERT_SELECTION: - case FF_FACE_SELECTION: - case FF_GEOM_FUNC: - case FF_FACE_COLOR: - case FF_FACE_QUALITY: - case FF_VERT_COLOR: - case FF_VERT_QUALITY: - case FF_VERT_TEXTURE_FUNC: - case FF_WEDGE_TEXTURE_FUNC: - case FF_VERT_NORMAL: - case FF_DEF_VERT_ATTRIB: - case FF_DEF_FACE_ATTRIB: - case FF_REFINE: - return FilterPlugin::SINGLE_MESH; - case FF_GRID: - case FF_ISOSURFACE: - return FilterPlugin::NONE; + switch (ID(filter)) { + case FF_VERT_SELECTION: + case FF_FACE_SELECTION: + case FF_GEOM_FUNC: + case FF_FACE_COLOR: + case FF_FACE_QUALITY: + case FF_VERT_COLOR: + case FF_VERT_QUALITY: + case FF_VERT_TEXTURE_FUNC: + case FF_WEDGE_TEXTURE_FUNC: + case FF_VERT_NORMAL: + case FF_DEF_VERT_SCALAR_ATTRIB: + case FF_DEF_FACE_SCALAR_ATTRIB: + case FF_REFINE: return FilterPlugin::SINGLE_MESH; + case FF_GRID: + case FF_ISOSURFACE: return FilterPlugin::NONE; } return FilterPlugin::NONE; } - MESHLAB_PLUGIN_NAME_EXPORTER(FilterFunctionPlugin) diff --git a/src/meshlabplugins/filter_func/filter_func.h b/src/meshlabplugins/filter_func/filter_func.h index 9e5186dd2..76fc2590f 100644 --- a/src/meshlabplugins/filter_func/filter_func.h +++ b/src/meshlabplugins/filter_func/filter_func.h @@ -1,25 +1,25 @@ -/**************************************************************************** -* MeshLab o o * -* A versatile mesh processing toolbox o o * -* _ O _ * -* Copyright(C) 2005 \/)\/ * -* 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. * -* * -****************************************************************************/ +/***************************************************************************** + * 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 FILTER_FUNC_PLUGIN_H #define FILTER_FUNC_PLUGIN_H @@ -28,7 +28,6 @@ #include -#include "muParser.h" #include "filter_refine.h" class FilterFunctionPlugin : public QObject, public FilterPlugin @@ -38,65 +37,69 @@ class FilterFunctionPlugin : public QObject, public FilterPlugin Q_INTERFACES(FilterPlugin) protected: - double x,y,z,nx,ny,nz,r,g,b,a,q,rad,vtu,vtv,vsel; - double x0,y0,z0,x1,y1,z1,x2,y2,z2,nx0,ny0,nz0,nx1,ny1,nz1,nx2,ny2,nz2,r0,g0,b0,a0,r1,g1,b1,a1,r2,g2,b2,a2,q0,q1,q2,wtu0,wtv0,wtu1,wtv1,wtu2,wtv2,vsel0,vsel1,vsel2; - double fr,fg,fb,fa,fnx,fny,fnz,fq,fsel; - double v,f,v0i,v1i,v2i,ti; + double x, y, z, nx, ny, nz, r, g, b, a, q, rad, vtu, vtv, vsel; + double x0, y0, z0, x1, y1, z1, x2, y2, z2, nx0, ny0, nz0, nx1, ny1, nz1, nx2, ny2, nz2, r0, g0, + b0, a0, r1, g1, b1, a1, r2, g2, b2, a2, q0, q1, q2, wtu0, wtv0, wtu1, wtv1, wtu2, wtv2, + vsel0, vsel1, vsel2; + double fr, fg, fb, fa, fnx, fny, fnz, fq, fsel; + double v, f, v0i, v1i, v2i, ti; std::vector v_attrNames; // names of the per vertex attributes std::vector v_attrValue; // values of the per vertex attributes - std::vector v3_attrNames; // names of the per vertex attributes There are 3x (one foreach coord _x, _y, _z) - std::vector v3_attrValue; // values of the per vertex attributes. There are 3x (one foreach coord _x, _y, _z) - std::vector f_attrNames; - std::vector f_attrValue; - std::vector > v_handlers; - std::vector > v3_handlers; - std::vector > f_handlers; - QString errorMsg; + std::vector v3_attrNames; // names of the per vertex attributes There are + // 3x (one foreach coord _x, _y, _z) + std::vector v3_attrValue; // values of the per vertex attributes. There are 3x + // (one foreach coord _x, _y, _z) + std::vector f_attrNames; + std::vector f_attrValue; + std::vector> v_handlers; + std::vector> v3_handlers; + std::vector> f_handlers; + QString errorMsg; public: enum { - FF_VERT_SELECTION, - FF_FACE_SELECTION, - FF_GEOM_FUNC, - FF_VERT_TEXTURE_FUNC, - FF_WEDGE_TEXTURE_FUNC, - FF_FACE_COLOR, - FF_VERT_COLOR, - FF_VERT_NORMAL, - FF_VERT_QUALITY, - FF_FACE_QUALITY, - FF_DEF_VERT_ATTRIB, - FF_DEF_FACE_ATTRIB, - FF_GRID, - FF_ISOSURFACE, - FF_REFINE - } ; + FF_VERT_SELECTION, + FF_FACE_SELECTION, + FF_GEOM_FUNC, + FF_VERT_TEXTURE_FUNC, + FF_WEDGE_TEXTURE_FUNC, + FF_FACE_COLOR, + FF_VERT_COLOR, + FF_VERT_NORMAL, + FF_VERT_QUALITY, + FF_FACE_QUALITY, + FF_DEF_VERT_SCALAR_ATTRIB, + FF_DEF_FACE_SCALAR_ATTRIB, + FF_DEF_VERT_POINT_ATTRIB, + FF_DEF_FACE_POINT_ATTRIB, + FF_GRID, + FF_ISOSURFACE, + FF_REFINE + }; FilterFunctionPlugin(); ~FilterFunctionPlugin(); - - QString pluginName() const; - QString filterName(ActionIDType filter) const; - QString filterInfo(ActionIDType filter) const; - FilterClass getClass(const QAction*) const; - int postCondition(const QAction *action) const; - RichParameterList initParameterList(const QAction*, const MeshModel &/*m*/); - virtual int getRequirements(const QAction*); + + QString pluginName() const; + QString filterName(ActionIDType filter) const; + QString filterInfo(ActionIDType filter) const; + FilterClass getClass(const QAction*) const; + int postCondition(const QAction* action) const; + RichParameterList initParameterList(const QAction*, const MeshModel& /*m*/); + virtual int getRequirements(const QAction*); std::map applyFilter( - const QAction* action, - const RichParameterList & parameters, - MeshDocument &md, - unsigned int& postConditionMask, - vcg::CallBackPos * cb); + const QAction* action, + const RichParameterList& parameters, + MeshDocument& md, + unsigned int& postConditionMask, + vcg::CallBackPos* cb); FilterArity filterArity(const QAction* filter) const; - - void showParserError(const QString &s, mu::Parser::exception_type &e); - void setAttributes(CMeshO::VertexIterator &vi,CMeshO &m); - void setAttributes(CMeshO::FaceIterator &fi,CMeshO &m); - void setPerVertexVariables(mu::Parser &p, CMeshO &m); - void setPerFaceVariables(mu::Parser &p, CMeshO &m); - + void showParserError(const QString& s, mu::Parser::exception_type& e); + void setAttributes(CMeshO::VertexIterator& vi, CMeshO& m); + void setAttributes(CMeshO::FaceIterator& fi, CMeshO& m); + void setPerVertexVariables(mu::Parser& p, CMeshO& m); + void setPerFaceVariables(mu::Parser& p, CMeshO& m); }; #endif diff --git a/src/meshlabplugins/filter_func/filter_refine.h b/src/meshlabplugins/filter_func/filter_refine.h index 0072f793e..ca08a127e 100644 --- a/src/meshlabplugins/filter_func/filter_refine.h +++ b/src/meshlabplugins/filter_func/filter_refine.h @@ -23,6 +23,7 @@ #include #include "string_conversion.h" +#include "muParser.h" using namespace vcg; using namespace mu; diff --git a/src/meshlabplugins/filter_unsharp/filter_unsharp.cpp b/src/meshlabplugins/filter_unsharp/filter_unsharp.cpp index 0fc38151f..c6adb234d 100644 --- a/src/meshlabplugins/filter_unsharp/filter_unsharp.cpp +++ b/src/meshlabplugins/filter_unsharp/filter_unsharp.cpp @@ -1,36 +1,36 @@ -/**************************************************************************** -* MeshLab o o * -* An extendible mesh processor o o * -* _ O _ * -* Copyright(C) 2005, 2006 \/)\/ * -* 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. * -* * -****************************************************************************/ +/***************************************************************************** + * MeshLab o o * + * An extendible mesh processor 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_unsharp.h" #include -#include #include #include +#include using namespace vcg; using namespace std; -enum WeightModeParam {WMP_AVG = 0, WMP_AREA, WMP_ANGLE, WMP_AS_DEF}; +enum WeightModeParam { WMP_AVG = 0, WMP_AREA, WMP_ANGLE, WMP_AS_DEF }; FilterUnsharp::FilterUnsharp() { @@ -42,7 +42,8 @@ FilterUnsharp::FilterUnsharp() FP_TWO_STEP_SMOOTH, FP_TAUBIN_SMOOTH, FP_DEPTH_SMOOTH, - FP_DIRECTIONAL_PRESERVATION, + //FP_DIRECTIONAL_PRESERVATION_STORE, + FP_DIRECTIONAL_PRESERVATION_BLEND, FP_VERTEX_QUALITY_SMOOTHING, FP_FACE_NORMAL_SMOOTHING, FP_UNSHARP_NORMAL, @@ -55,528 +56,820 @@ FilterUnsharp::FilterUnsharp() FP_FACE_NORMAL_NORMALIZE, FP_VERTEX_NORMAL_NORMALIZE, FP_LINEAR_MORPH, - FP_SCALAR_HARMONIC_FIELD - }; + FP_SCALAR_HARMONIC_FIELD}; - for(ActionIDType tt : types()) + for (ActionIDType tt : types()) actionList.push_back(new QAction(filterName(tt), this)); - } -FilterUnsharp::~FilterUnsharp() { +FilterUnsharp::~FilterUnsharp() +{ } QString FilterUnsharp::pluginName() const { - return "FilterUnsharp"; + return "FilterUnsharp"; } QString FilterUnsharp::filterName(ActionIDType filter) const { - switch(filter) - { - case FP_LAPLACIAN_SMOOTH : return QString("Laplacian Smooth"); - case FP_HC_LAPLACIAN_SMOOTH : return QString("HC Laplacian Smooth"); - case FP_SD_LAPLACIAN_SMOOTH : return QString("ScaleDependent Laplacian Smooth"); - case FP_TWO_STEP_SMOOTH : return QString("TwoStep Smooth"); - case FP_TAUBIN_SMOOTH : return QString("Taubin Smooth"); - case FP_DEPTH_SMOOTH : return QString("Depth Smooth"); - case FP_DIRECTIONAL_PRESERVATION : return QString("Directional Geom. Preserv."); - case FP_CREASE_CUT : return QString("Cut mesh along crease edges"); - case FP_FACE_NORMAL_NORMALIZE: return QString("Normalize Face Normals"); - case FP_VERTEX_NORMAL_NORMALIZE: return QString("Normalize Vertex Normals"); - case FP_FACE_NORMAL_SMOOTHING: return QString("Smooth Face Normals"); - case FP_VERTEX_QUALITY_SMOOTHING: return QString("Smooth Vertex Quality"); - case FP_UNSHARP_NORMAL: return QString("UnSharp Mask Normals"); - case FP_UNSHARP_GEOMETRY: return QString("UnSharp Mask Geometry"); - case FP_UNSHARP_QUALITY: return QString("UnSharp Mask Quality"); - case FP_UNSHARP_VERTEX_COLOR: return QString("UnSharp Mask Color"); - case FP_RECOMPUTE_VERTEX_NORMAL: return QString("Re-Compute Vertex Normals"); - case FP_RECOMPUTE_FACE_NORMAL: return QString("Re-Compute Face Normals"); - case FP_RECOMPUTE_QUADFACE_NORMAL: return QString("Re-Compute Per-Polygon Face Normals"); - case FP_LINEAR_MORPH : return QString("Vertex Linear Morphing"); - case FP_SCALAR_HARMONIC_FIELD: return QString("Generate Scalar Harmonic Field"); + switch (filter) { + case FP_LAPLACIAN_SMOOTH: return QString("Laplacian Smooth"); + case FP_HC_LAPLACIAN_SMOOTH: return QString("HC Laplacian Smooth"); + case FP_SD_LAPLACIAN_SMOOTH: return QString("ScaleDependent Laplacian Smooth"); + case FP_TWO_STEP_SMOOTH: return QString("TwoStep Smooth"); + case FP_TAUBIN_SMOOTH: return QString("Taubin Smooth"); + case FP_DEPTH_SMOOTH: return QString("Depth Smooth"); + //case FP_DIRECTIONAL_PRESERVATION_STORE: return QString("Directional Geom. Preserv."); + case FP_DIRECTIONAL_PRESERVATION_BLEND: return QString("Directional Geometry Preservation"); + case FP_CREASE_CUT: return QString("Cut mesh along crease edges"); + case FP_FACE_NORMAL_NORMALIZE: return QString("Normalize Face Normals"); + case FP_VERTEX_NORMAL_NORMALIZE: return QString("Normalize Vertex Normals"); + case FP_FACE_NORMAL_SMOOTHING: return QString("Smooth Face Normals"); + case FP_VERTEX_QUALITY_SMOOTHING: return QString("Smooth Vertex Quality"); + case FP_UNSHARP_NORMAL: return QString("UnSharp Mask Normals"); + case FP_UNSHARP_GEOMETRY: return QString("UnSharp Mask Geometry"); + case FP_UNSHARP_QUALITY: return QString("UnSharp Mask Quality"); + case FP_UNSHARP_VERTEX_COLOR: return QString("UnSharp Mask Color"); + case FP_RECOMPUTE_VERTEX_NORMAL: return QString("Re-Compute Vertex Normals"); + case FP_RECOMPUTE_FACE_NORMAL: return QString("Re-Compute Face Normals"); + case FP_RECOMPUTE_QUADFACE_NORMAL: return QString("Re-Compute Per-Polygon Face Normals"); + case FP_LINEAR_MORPH: return QString("Vertex Linear Morphing"); + case FP_SCALAR_HARMONIC_FIELD: return QString("Generate Scalar Harmonic Field"); - default: assert(0); - } - return QString("Error on FilterUnsharp::filterName()"); + default: assert(0); + } + return QString("Error on FilterUnsharp::filterName()"); } QString FilterUnsharp::filterInfo(ActionIDType filterId) const { - switch(filterId) - { - case FP_LAPLACIAN_SMOOTH : return tr("Laplacian smooth. Average each vertex position with weighted positions of neighbour vertices.
" - "Laplacian Mesh Processing by Olga Sorkine. EUROGRAPHICS 2005
" - "doi:10.2312/egst.20051044"); - case FP_HC_LAPLACIAN_SMOOTH : return tr("HC Laplacian Smoothing. Extended version of Laplacian Smoothing based on the article:
" - "Improved Laplacian Smoothing of Noisy Surface Meshes " - "by Vollmer, Mencl and Müller. EUROGRAPHICS Volume 18 (1999), Number 3, 131-138.
" - "doi:10.1111/1467-8659.00334"); - case FP_SD_LAPLACIAN_SMOOTH : return tr("Scale Dependent Laplacian Smoothing, extended version of Laplacian Smoothing based on the Fujiwara extended umbrella operator.
" - "Implicit Fairing of Irregular Meshes using Diffusion and Curvature Flow " - "by Desbrun, Meyer, Schroeder and Barr. SIGGRAPH 1999
" - "doi:10.1145/311535.311576"); - case FP_TWO_STEP_SMOOTH : return tr("Two Steps Smoothing, a feature preserving/enhancing fairing filter based on two stages:
  1. Normal Smoothing, where " - "similar normals are averaged together.
  2. Vertex reposition, where vertices are moved to fit on the new normals.
" - "A Comparison of Mesh Smoothing Methods by A. Belyaev and Y. Ohtake. " - "Proc. Israel-Korea Bi-National Conf. Geometric Modeling and Computer Graphics, pp. 83-87, 2003.
" - "publication"); - case FP_TAUBIN_SMOOTH : return tr("The λ-μ Taubin smoothing, combines two steps of low-pass filtering for each iteration. Based on the article:
" - "A signal processing approach to fair surface design by Gabriel Taubin, SIGGRAPH 1995
" - "doi:10.1145/218380.218473"); - case FP_DEPTH_SMOOTH : return tr("A laplacian smooth that is constrained to move vertices only in one given direction (usually the viewer direction)."); - case FP_DIRECTIONAL_PRESERVATION : return tr("Store and Blend the current geometry with the result of another previous smoothing processing step. This is useful to " - "limit the influence of any smoothing algorithm along the viewing direction. This is useful to cope with the biased " - "distribution of measuring error in many scanning devices, because TOF scanners usually have very good x,y" - "accuracy but suffer of greater depth errors."); - case FP_CREASE_CUT: return tr("Cut the mesh along crease edges, duplicating the vertices as necessary. Crease (or sharp) edges are defined according " - "to the variation of normal of the adjacent faces."); - case FP_FACE_NORMAL_NORMALIZE: return tr("Normalize Face Normal Lengths to unit vectors."); - case FP_VERTEX_NORMAL_NORMALIZE: return tr("Normalize Vertex Normal Lengths to unit vectors."); - case FP_VERTEX_QUALITY_SMOOTHING: return tr("Laplacian smooth of the quality per vertex values."); - case FP_FACE_NORMAL_SMOOTHING: return tr("Laplacian smooth of the face normals, without touching the position of the vertices."); - case FP_UNSHARP_NORMAL: return tr("Unsharp mask filtering of the normals per face, putting in more evidence normal variations.
" - "A simple normal enhancement technique for interactive non-photorealistic renderings " - "by Cignoni, Scopigno and Tarini, Comput Graph, 29 (1) (2005)
" - "doi:10.1016/j.cag.2004.11.012"); - case FP_UNSHARP_GEOMETRY: return tr("Apply Unsharp filter to geometric shape, putting in more evidence ridges and valleys variations.
" - "Unsharp Masking"); - case FP_UNSHARP_QUALITY: return tr("Apply Unsharp filter to values of quality per vertex.
" - "See Unsharp Masking"); - case FP_UNSHARP_VERTEX_COLOR: return tr("Apply Unsharp filter to the vertex color, putting in more evidence color variations.
" - "See Unsharp Masking"); - case FP_RECOMPUTE_VERTEX_NORMAL: return tr("Recompute vertex normals according to four different schemes:
" - "1) Simple (no weights) average of normals of the incident faces
" - "2) Area weighted average of normals of the incident faces
" - "3) Angle weighted sum of normals of the incident faces according to the article [1]. " - "Probably this is the best all-purpose choice. It could slightly bias the result for degenerate, fat triangles.
" - "4) Weighted sum of normals of the incident faces, as defined by article [2]. " - "The weight for each wedge is the cross product of the two edges over the product of the square of the two edge lengths." - "According to the original article it is perfect only for spherical surface, but it should perform well also in practice.
" - "[1]: Computing Vertex Normals from Polygonal Facet by G Thurmer and CA Wuthrich, JGT volume3, num 1. 1998
" - "doi:10.1080/10867651.1998.10487487
" - "[2]: Weights for Computing Vertex Normals from Facet Normals by Nelson Max, JGT vol4, num 2. 1999
" - "doi:10.1080/10867651.1999.10487501"); - case FP_RECOMPUTE_FACE_NORMAL: return tr("Recompute face normals as the normal of the plane of the face.
" - "See How to find surface normal of a triangle"); - case FP_RECOMPUTE_QUADFACE_NORMAL: return tr("Recompute face normals as the average of the normals of the triangles that builds a polygon. " - "Useful for showing uniformly shaded quad or polygonal meshes represented using " - "faux edges."); - case FP_LINEAR_MORPH : return tr("Morph deformation of current mesh towards a target mesh with the same number of vertices and same vertex ordering. " - "Each vertex of the source mesh is linearly interpolated towards the corresponding vertex on the target mesh " - "using the formula:

resulti = (1-λ)*sourcei + λ*targeti

" - "Three-dimensional metamorphosis: a survey
by F. Lazarus and A. Verroust, Visual Computer, 1998
" - "doi:10.1007/s003710050149"); - case FP_SCALAR_HARMONIC_FIELD: return QString("Generates a scalar harmonic field over the mesh. Input scalar values must be assigned to two vertices " - "as Dirichlet boundary conditions. Applying the filter, a discrete Laplace operator generates the harmonic " - "field values for all the mesh vertices, which are stored in the " - "quality per vertex attribute of the mesh.
" - "For more details see:" - "Dynamic Harmonic Fields for Surface Processing by Kai Xua, Hao Zhang, Daniel Cohen-Or, Yueshan Xionga. " - "Computers & Graphics, 2009
" - "doi:10.1016/j.cag.2009.03.022"); - default: assert(0); - } - return QString("Error on FilterUnsharp::filterInfo()!"); + switch (filterId) { + case FP_LAPLACIAN_SMOOTH: + return tr( + "Laplacian smooth. Average each vertex position with weighted positions of neighbour " + "vertices.
" + "Laplacian Mesh Processing by Olga Sorkine. EUROGRAPHICS 2005
" + "doi:10.2312/egst.20051044"); + case FP_HC_LAPLACIAN_SMOOTH: + return tr( + "HC Laplacian Smoothing. Extended version of Laplacian Smoothing based on the article: " + "
" + "Improved Laplacian Smoothing of Noisy Surface Meshes " + "by Vollmer, Mencl and Müller. EUROGRAPHICS Volume 18 (1999), Number 3, " + "131-138.
" + "doi:10.1111/1467-8659.00334"); + case FP_SD_LAPLACIAN_SMOOTH: + return tr( + "Scale Dependent Laplacian Smoothing, extended version of Laplacian Smoothing based on " + "the Fujiwara extended umbrella operator.
" + "Implicit Fairing of Irregular Meshes using Diffusion and Curvature Flow " + "by Desbrun, Meyer, Schroeder and Barr. SIGGRAPH 1999
" + "doi:10.1145/311535.311576"); + case FP_TWO_STEP_SMOOTH: + return tr( + "Two Steps Smoothing, a feature preserving/enhancing fairing filter based on two " + "stages:
  1. Normal Smoothing, where " + "similar normals are averaged together.
  2. Vertex reposition, where vertices are moved " + "to fit on the new normals.
" + "A Comparison of Mesh Smoothing Methods by A. Belyaev and Y. Ohtake. " + "Proc. Israel-Korea Bi-National Conf. Geometric Modeling and Computer Graphics, pp. " + "83-87, 2003.
" + "publication"); + case FP_TAUBIN_SMOOTH: + return tr( + "The λ-μ Taubin smoothing, combines two steps of low-pass filtering for each " + "iteration. Based on the article:
" + "A signal processing approach to fair surface design by Gabriel Taubin, " + "SIGGRAPH 1995
" + "doi:10.1145/218380.218473"); + case FP_DEPTH_SMOOTH: + return tr( + "A laplacian smooth that is constrained to move vertices only in one given direction " + "(usually the viewer direction)."); + //case FP_DIRECTIONAL_PRESERVATION_STORE: + // return tr( + // "Blend the geometry previously stored in a per vertex custom point attribute with the " + // "current geometry. This is useful to limit the influence of any smoothing algorithm " + // "along the viewing direction. This is useful to cope with the biased distribution of " + // "measuring error in many scanning devices, because TOF scanners usually have very good " + // "x,y accuracy but suffer of greater depth errors."); + case FP_DIRECTIONAL_PRESERVATION_BLEND: + return tr( + "Blend through a given direction the geometry previously stored in a per vertex " + "custom point attribute with the current geometry. This is useful to limit the " + "influence of any smoothing algorithm along the viewing direction. This is useful to " + "cope with the biased distribution of measuring error in many scanning devices, " + "because TOF scanners usually have very good x,y accuracy but suffer of greater " + "depth errors."); + case FP_CREASE_CUT: + return tr( + "Cut the mesh along crease edges, duplicating the vertices as necessary. Crease (or " + "sharp) edges are defined according " + "to the variation of normal of the adjacent faces."); + case FP_FACE_NORMAL_NORMALIZE: return tr("Normalize Face Normal Lengths to unit vectors."); + case FP_VERTEX_NORMAL_NORMALIZE: return tr("Normalize Vertex Normal Lengths to unit vectors."); + case FP_VERTEX_QUALITY_SMOOTHING: + return tr( + "Laplacian smooth of the quality per vertex values."); + case FP_FACE_NORMAL_SMOOTHING: + return tr( + "Laplacian smooth of the face normals, without touching the position of the vertices."); + case FP_UNSHARP_NORMAL: + return tr( + "Unsharp mask filtering of the normals per face, putting in more evidence normal " + "variations.
" + "A simple normal enhancement technique for interactive non-photorealistic " + "renderings " + "by Cignoni, Scopigno and Tarini, Comput Graph, 29 (1) (2005)
" + "doi:10.1016/j.cag.2004.11.012"); + case FP_UNSHARP_GEOMETRY: + return tr( + "Apply Unsharp filter to geometric shape, putting in more evidence ridges and valleys " + "variations.
" + "Unsharp Masking"); + case FP_UNSHARP_QUALITY: + return tr( + "Apply Unsharp filter to values of quality per vertex.
" + "See Unsharp Masking"); + case FP_UNSHARP_VERTEX_COLOR: + return tr( + "Apply Unsharp filter to the vertex color, putting in more evidence color " + "variations.
" + "See Unsharp Masking"); + case FP_RECOMPUTE_VERTEX_NORMAL: + return tr( + "Recompute vertex normals according to four different schemes:
" + "1) Simple (no weights) average of normals of the incident faces
" + "2) Area weighted average of normals of the incident faces
" + "3) Angle weighted sum of normals of the incident faces according to the article " + "[1]. " + "Probably this is the best all-purpose choice. It could slightly bias the result for " + "degenerate, fat triangles.
" + "4) Weighted sum of normals of the incident faces, as defined by article [2]. " + "The weight for each wedge is the cross product of the two edges over the product of " + "the square of the two edge lengths." + "According to the original article it is perfect only for spherical surface, but it " + "should perform well also in practice.
" + "[1]: Computing Vertex Normals from Polygonal Facet by G Thurmer and CA " + "Wuthrich, JGT volume3, num 1. 1998
" + "doi:10.1080/" + "10867651.1998.10487487
" + "[2]: Weights for Computing Vertex Normals from Facet Normals by Nelson " + "Max, JGT vol4, num 2. 1999
" + "doi:10.1080/" + "10867651.1999.10487501"); + case FP_RECOMPUTE_FACE_NORMAL: + return tr( + "Recompute face normals as the normal of the plane of the face.
" + "See How to find surface " + "normal of a triangle"); + case FP_RECOMPUTE_QUADFACE_NORMAL: + return tr( + "Recompute face normals as the average of the normals of the triangles that builds a " + "polygon. " + "Useful for showing uniformly shaded quad or polygonal meshes represented using " + "faux edges."); + case FP_LINEAR_MORPH: + return tr( + "Morph deformation of current mesh towards a target mesh with the same number of " + "vertices and same vertex ordering. " + "Each vertex of the source mesh is linearly interpolated towards the corresponding " + "vertex on the target mesh " + "using the formula:

resulti = " + "(1-λ)*sourcei + " + "λ*targeti

" + "Three-dimensional metamorphosis: a survey
by F. Lazarus and A. " + "Verroust, Visual Computer, 1998
" + "doi:10.1007/s003710050149"); + case FP_SCALAR_HARMONIC_FIELD: + return QString( + "Generates a scalar harmonic field over the mesh. Input scalar values must be assigned " + "to two vertices " + "as Dirichlet boundary conditions. Applying the filter, a discrete Laplace operator " + "generates the harmonic " + "field values for all the mesh vertices, which are stored in the " + "quality per vertex " + "attribute of the mesh.
" + "For more details see:" + "Dynamic Harmonic Fields for Surface Processing by Kai Xua, Hao Zhang, " + "Daniel Cohen-Or, Yueshan Xionga. " + "Computers & Graphics, 2009
" + "doi:10.1016/j.cag.2009.03.022"); + default: assert(0); + } + return QString("Error on FilterUnsharp::filterInfo()!"); } - FilterUnsharp::FilterClass FilterUnsharp::getClass(const QAction *a) const +FilterUnsharp::FilterClass FilterUnsharp::getClass(const QAction* a) const { - switch(ID(a)) - { - case FP_CREASE_CUT : - return FilterPlugin::FilterClass( FilterPlugin::Normal | FilterPlugin::Remeshing); - case FP_SD_LAPLACIAN_SMOOTH: - case FP_HC_LAPLACIAN_SMOOTH: - case FP_LAPLACIAN_SMOOTH: - case FP_TWO_STEP_SMOOTH: - case FP_TAUBIN_SMOOTH: - case FP_DEPTH_SMOOTH: - case FP_DIRECTIONAL_PRESERVATION: - case FP_FACE_NORMAL_SMOOTHING: - case FP_VERTEX_QUALITY_SMOOTHING: - case FP_UNSHARP_NORMAL: - case FP_UNSHARP_GEOMETRY: - case FP_UNSHARP_QUALITY: - case FP_LINEAR_MORPH : - return FilterPlugin::Smoothing; + switch (ID(a)) { + case FP_CREASE_CUT: + return FilterPlugin::FilterClass(FilterPlugin::Normal | FilterPlugin::Remeshing); + case FP_SD_LAPLACIAN_SMOOTH: + case FP_HC_LAPLACIAN_SMOOTH: + case FP_LAPLACIAN_SMOOTH: + case FP_TWO_STEP_SMOOTH: + case FP_TAUBIN_SMOOTH: + case FP_DEPTH_SMOOTH: + //case FP_DIRECTIONAL_PRESERVATION_STORE: + case FP_DIRECTIONAL_PRESERVATION_BLEND: + case FP_FACE_NORMAL_SMOOTHING: + case FP_VERTEX_QUALITY_SMOOTHING: + case FP_UNSHARP_NORMAL: + case FP_UNSHARP_GEOMETRY: + case FP_UNSHARP_QUALITY: + case FP_LINEAR_MORPH: return FilterPlugin::Smoothing; - case FP_UNSHARP_VERTEX_COLOR: - return FilterPlugin::FilterClass( FilterPlugin::Smoothing | FilterPlugin::VertexColoring); + case FP_UNSHARP_VERTEX_COLOR: + return FilterPlugin::FilterClass(FilterPlugin::Smoothing | FilterPlugin::VertexColoring); - case FP_RECOMPUTE_FACE_NORMAL : - case FP_RECOMPUTE_QUADFACE_NORMAL : - case FP_RECOMPUTE_VERTEX_NORMAL : - case FP_FACE_NORMAL_NORMALIZE: - case FP_VERTEX_NORMAL_NORMALIZE: - return FilterPlugin::Normal; - case FP_SCALAR_HARMONIC_FIELD: return FilterPlugin::Remeshing; + case FP_RECOMPUTE_FACE_NORMAL: + case FP_RECOMPUTE_QUADFACE_NORMAL: + case FP_RECOMPUTE_VERTEX_NORMAL: + case FP_FACE_NORMAL_NORMALIZE: + case FP_VERTEX_NORMAL_NORMALIZE: return FilterPlugin::Normal; + case FP_SCALAR_HARMONIC_FIELD: return FilterPlugin::Remeshing; - default : return FilterPlugin::Generic; - } + default: return FilterPlugin::Generic; + } } -int FilterUnsharp::getPreConditions(const QAction *a) const +int FilterUnsharp::getPreConditions(const QAction* a) const { - switch(ID(a)) - { - case FP_VERTEX_QUALITY_SMOOTHING: - case FP_UNSHARP_QUALITY: - return MeshModel::MM_FACENUMBER | MeshModel::MM_VERTQUALITY; - case FP_SD_LAPLACIAN_SMOOTH: - case FP_HC_LAPLACIAN_SMOOTH: - case FP_LAPLACIAN_SMOOTH: - case FP_TWO_STEP_SMOOTH: - case FP_TAUBIN_SMOOTH: - case FP_DEPTH_SMOOTH: - case FP_LINEAR_MORPH : - case FP_UNSHARP_NORMAL: - case FP_UNSHARP_GEOMETRY: - case FP_DIRECTIONAL_PRESERVATION: - case FP_FACE_NORMAL_SMOOTHING: - case FP_RECOMPUTE_FACE_NORMAL : - case FP_RECOMPUTE_QUADFACE_NORMAL : - case FP_RECOMPUTE_VERTEX_NORMAL : - case FP_FACE_NORMAL_NORMALIZE: - case FP_CREASE_CUT: - case FP_SCALAR_HARMONIC_FIELD: - return MeshModel::MM_FACENUMBER; - case FP_UNSHARP_VERTEX_COLOR: - return MeshModel::MM_FACENUMBER | MeshModel::MM_VERTCOLOR; - - case FP_VERTEX_NORMAL_NORMALIZE: return MeshModel::MM_NONE; - - default : assert(0); return MeshModel::MM_NONE; - } -} + switch (ID(a)) { + case FP_VERTEX_QUALITY_SMOOTHING: + case FP_UNSHARP_QUALITY: return MeshModel::MM_FACENUMBER | MeshModel::MM_VERTQUALITY; + case FP_SD_LAPLACIAN_SMOOTH: + case FP_HC_LAPLACIAN_SMOOTH: + case FP_LAPLACIAN_SMOOTH: + case FP_TWO_STEP_SMOOTH: + case FP_TAUBIN_SMOOTH: + case FP_DEPTH_SMOOTH: + case FP_LINEAR_MORPH: + case FP_UNSHARP_NORMAL: + case FP_UNSHARP_GEOMETRY: + //case FP_DIRECTIONAL_PRESERVATION_STORE: + case FP_DIRECTIONAL_PRESERVATION_BLEND: + case FP_FACE_NORMAL_SMOOTHING: + case FP_RECOMPUTE_FACE_NORMAL: + case FP_RECOMPUTE_QUADFACE_NORMAL: + case FP_RECOMPUTE_VERTEX_NORMAL: + case FP_FACE_NORMAL_NORMALIZE: + case FP_CREASE_CUT: + case FP_SCALAR_HARMONIC_FIELD: return MeshModel::MM_FACENUMBER; + case FP_UNSHARP_VERTEX_COLOR: return MeshModel::MM_FACENUMBER | MeshModel::MM_VERTCOLOR; + case FP_VERTEX_NORMAL_NORMALIZE: return MeshModel::MM_NONE; -int FilterUnsharp::postCondition(const QAction *a) const -{ - switch(ID(a)) - { - case FP_SD_LAPLACIAN_SMOOTH: - case FP_HC_LAPLACIAN_SMOOTH: - case FP_LAPLACIAN_SMOOTH: - case FP_TWO_STEP_SMOOTH: - case FP_TAUBIN_SMOOTH: - case FP_DEPTH_SMOOTH: - case FP_LINEAR_MORPH : - case FP_UNSHARP_NORMAL: - case FP_UNSHARP_GEOMETRY: return MeshModel::MM_VERTCOORD | MeshModel::MM_VERTNORMAL | MeshModel::MM_FACENORMAL; - case FP_DIRECTIONAL_PRESERVATION: - case FP_VERTEX_QUALITY_SMOOTHING: - case FP_UNSHARP_QUALITY: - case FP_CREASE_CUT: return MeshModel::MM_ALL; - case FP_FACE_NORMAL_SMOOTHING: - case FP_RECOMPUTE_FACE_NORMAL: - case FP_RECOMPUTE_QUADFACE_NORMAL: - case FP_FACE_NORMAL_NORMALIZE: return MeshModel::MM_FACENORMAL; - case FP_RECOMPUTE_VERTEX_NORMAL: - case FP_VERTEX_NORMAL_NORMALIZE: return MeshModel::MM_VERTNORMAL; - case FP_UNSHARP_VERTEX_COLOR: return MeshModel::MM_VERTCOLOR; - case FP_SCALAR_HARMONIC_FIELD: return MeshModel::MM_VERTQUALITY; - default : assert(0); return MeshModel::MM_ALL; + default: assert(0); return MeshModel::MM_NONE; } } - int FilterUnsharp::getRequirements(const QAction *action) +int FilterUnsharp::postCondition(const QAction* a) const { - switch(ID(action)) - { - case FP_TWO_STEP_SMOOTH: return MeshModel::MM_VERTFACETOPO; - - case FP_CREASE_CUT : - case FP_UNSHARP_NORMAL: - case FP_RECOMPUTE_QUADFACE_NORMAL : - case FP_FACE_NORMAL_SMOOTHING : return MeshModel::MM_FACEFACETOPO; - - case FP_RECOMPUTE_FACE_NORMAL : - case FP_RECOMPUTE_VERTEX_NORMAL : - case FP_FACE_NORMAL_NORMALIZE: - case FP_VERTEX_NORMAL_NORMALIZE: - case FP_DIRECTIONAL_PRESERVATION: - case FP_LINEAR_MORPH : - case FP_HC_LAPLACIAN_SMOOTH: - case FP_SD_LAPLACIAN_SMOOTH: - case FP_TAUBIN_SMOOTH: - case FP_DEPTH_SMOOTH: - case FP_LAPLACIAN_SMOOTH: - case FP_UNSHARP_GEOMETRY: - case FP_UNSHARP_QUALITY: - case FP_VERTEX_QUALITY_SMOOTHING: - case FP_SCALAR_HARMONIC_FIELD: - case FP_UNSHARP_VERTEX_COLOR: return MeshModel::MM_NONE; - default: assert(0); - } - return MeshModel::MM_NONE; + switch (ID(a)) { + case FP_SD_LAPLACIAN_SMOOTH: + case FP_HC_LAPLACIAN_SMOOTH: + case FP_LAPLACIAN_SMOOTH: + case FP_TWO_STEP_SMOOTH: + case FP_TAUBIN_SMOOTH: + case FP_DEPTH_SMOOTH: + case FP_LINEAR_MORPH: + case FP_UNSHARP_NORMAL: + case FP_UNSHARP_GEOMETRY: + return MeshModel::MM_VERTCOORD | MeshModel::MM_VERTNORMAL | MeshModel::MM_FACENORMAL; + //case FP_DIRECTIONAL_PRESERVATION_STORE: + case FP_DIRECTIONAL_PRESERVATION_BLEND: + case FP_VERTEX_QUALITY_SMOOTHING: + case FP_UNSHARP_QUALITY: + case FP_CREASE_CUT: return MeshModel::MM_ALL; + case FP_FACE_NORMAL_SMOOTHING: + case FP_RECOMPUTE_FACE_NORMAL: + case FP_RECOMPUTE_QUADFACE_NORMAL: + case FP_FACE_NORMAL_NORMALIZE: return MeshModel::MM_FACENORMAL; + case FP_RECOMPUTE_VERTEX_NORMAL: + case FP_VERTEX_NORMAL_NORMALIZE: return MeshModel::MM_VERTNORMAL; + case FP_UNSHARP_VERTEX_COLOR: return MeshModel::MM_VERTCOLOR; + case FP_SCALAR_HARMONIC_FIELD: return MeshModel::MM_VERTQUALITY; + default: assert(0); return MeshModel::MM_ALL; + } } -RichParameterList FilterUnsharp::initParameterList(const QAction *action, const MeshDocument &md) +int FilterUnsharp::getRequirements(const QAction* action) { - RichParameterList parlst; - switch(ID(action)) - { - case FP_RECOMPUTE_VERTEX_NORMAL : - parlst.addParam(RichEnum("weightMode", 0, QStringList() << "Simple Average" << "By Area" << "By Angle" << "As defined by N. Max", tr("Weighting Mode:"), "")); - break; - case FP_CREASE_CUT : - parlst.addParam(RichFloat("angleDeg", 90.f, tr("Crease Angle (degree)"), tr("If the angle between the normals of two adjacent faces is larger that this threshold the edge is considered a creased and the mesh is cut along it."))); - break; - case FP_UNSHARP_NORMAL: - parlst.addParam(RichBool("recalc", false, tr("Recompute Normals"), tr("Recompute normals from scratch before the unsharp masking"))); - parlst.addParam(RichFloat("weight", 0.3f, tr("Unsharp Weight"), tr("the unsharp weight wu in the unsharp mask equation:
woorig + wu (orig - lowpass)
"))); - parlst.addParam(RichFloat("weightOrig", 1.f, tr("Original Weight"), tr("How much the original signal is used, e.g. the weight wo in the above unsharp mask equation.
Usually you should not need to change the default 1.0 value."))); - parlst.addParam(RichInt("iterations", 5, "Smooth Iterations", tr("number of laplacian face smooth iterations in every run"))); - break; - case FP_UNSHARP_GEOMETRY: - parlst.addParam(RichFloat("weight", 0.3f, tr("Unsharp Weight"), tr("the unsharp weight wu in the unsharp mask equation:
woorig + wu (orig - lowpass)
"))); - parlst.addParam(RichFloat("weightOrig", 1.f, tr("Original Weight"), tr("How much the original signal is used, e.g. the weight wo in the above unsharp mask equation
Usually you should not need to change the default 1.0 value."))); - parlst.addParam(RichInt("iterations", 5, "Smooth Iterations", tr("number of iterations of laplacian smooth in every run"))); - break; - case FP_UNSHARP_VERTEX_COLOR: - parlst.addParam(RichFloat("weight", 0.3f, tr("Unsharp Weight"), tr("the unsharp weight wu in the unsharp mask equation:
woorig + wu (orig - lowpass)
"))); - parlst.addParam(RichFloat("weightOrig", 1.f, tr("Original Color Weight"), tr("How much the original signal is used, e.g. the weight wo in the above unsharp mask equation
Usually you should not need to change the default 1.0 value."))); - parlst.addParam(RichInt("iterations", 5, "Smooth Iterations", tr("number of iterations of laplacian smooth in every run"))); - break; - case FP_UNSHARP_QUALITY: - parlst.addParam(RichFloat("weight", 0.3f, tr("Unsharp Weight"), tr("the unsharp weight wu in the unsharp mask equation:
woorig + wu (orig - lowpass)
"))); - parlst.addParam(RichFloat("weightOrig", 1.f, tr("Original Weight"), tr("How much the original signal is used, e.g. the weight wo in the above unsharp mask equation
Usually you should not need to change the default 1.0 value."))); - parlst.addParam(RichInt("iterations", 5, "Smooth Iterations", tr("number of iterations of laplacian smooth in every run"))); - break; - case FP_TWO_STEP_SMOOTH: - parlst.addParam(RichInt ("stepSmoothNum", (int) 3,"Smoothing steps", "The number of times that the whole algorithm (normal smoothing + vertex fitting) is iterated.")); - parlst.addParam(RichFloat("normalThr", (float) 60,"Feature Angle Threshold (deg)", "Specify a threshold angle (0..90) for features that you want to be preserved.
Features forming angles LARGER than the specified threshold will be preserved.
0 -> no smoothing
90 -> all faces will be smoothed")); - parlst.addParam(RichInt ("stepNormalNum", (int) 20,"Normal Smoothing steps", "Number of iterations of normal smoothing step. The larger the better and (the slower)")); - parlst.addParam(RichInt ("stepFitNum", (int) 20,"Vertex Fitting steps", "Number of iterations of the vertex fitting procedure.")); - parlst.addParam(RichBool ("Selected",md.mm()->cm.sfn>0,"Affect only selected faces","If checked the filter is performed only on the selected faces")); - break; - case FP_LAPLACIAN_SMOOTH: - parlst.addParam(RichInt ("stepSmoothNum", (int) 3,"Smoothing steps", "The number of times that the whole algorithm (normal smoothing + vertex fitting) is iterated.")); - parlst.addParam(RichBool ("Boundary",true,"1D Boundary Smoothing", "Smooth boundary edges only by themselves (e.g. the polyline forming the boundary of the mesh is independently smoothed). This can reduce the shrinking on the border but can have strange effects on very small boundaries.")); - parlst.addParam(RichBool ("cotangentWeight",true,"Cotangent weighting", "Use cotangent weighting scheme for the averaging of the position. Otherwise the simpler umbrella scheme (1 if the edge is present) is used.")); - parlst.addParam(RichBool("Selected", md.mm()->cm.sfn>0, "Affect only selection", "If checked the filter is performed only on the selected area")); - break; - case FP_DEPTH_SMOOTH: - parlst.addParam(RichInt ("stepSmoothNum", (int) 3,"Smoothing steps", "The number of times that the whole algorithm (normal smoothing + vertex fitting) is iterated.")); - parlst.addParam(RichDirection ("viewPoint", Point3f(0,0,0),"Viewpoint", "The position of the view point that is used to get the constraint direction.")); - parlst.addParam(RichAbsPerc ("delta", 1.0, 0, 1.0, "Strength", "How much smoothing is applied: 0 (no smooth) e 1 (full smooth)")); - parlst.addParam(RichBool ("Selected",md.mm()->cm.sfn>0,"Affect only selection","If checked the filter is performed only on the selected area")); - break; - case FP_DIRECTIONAL_PRESERVATION: - parlst.addParam(RichEnum("step", 0, - QStringList() << "Store Vertex Position" << "Blend Vertex Position", - tr("Step:"), - tr("The purpose of this filter is to constrain any smoothing algorithm to moving vertices only along a give line of sight.
First you should store current vertex position, than after applying one of the many smoothing algorithms you should re start this filter and blend the original positions with the smoothed results.
" - "Given a view point vp , the smoothed vertex position vs and the original position v, The new vertex position is computed as the projection of vs on the line connecting v and vp."))); - parlst.addParam(RichDirection ("viewPoint", Point3f(0,0,0),"Viewpoint", "The position of the view point that is used to get the constraint direction.")); - parlst.addParam(RichBool ("Selected",md.mm()->cm.sfn>0,"Affect only selected faces","If checked the filter is performed only on the selected faces")); - break; - case FP_TAUBIN_SMOOTH: - parlst.addParam(RichFloat("lambda", (float) 0.5,"Lambda", "The lambda parameter of the Taubin Smoothing algorithm")); - parlst.addParam(RichFloat("mu", (float) -0.53,"mu", "The mu parameter of the Taubin Smoothing algorithm")); - parlst.addParam(RichInt ("stepSmoothNum", (int) 10,"Smoothing steps", "The number of times that the taubin smoothing is iterated. Usually it requires a larger number of iteration than the classical laplacian")); - parlst.addParam(RichBool ("Selected",md.mm()->cm.sfn>0,"Affect only selected faces","If checked the filter is performed only on the selected faces")); - break; - case FP_SD_LAPLACIAN_SMOOTH: - { - parlst.addParam(RichInt ("stepSmoothNum", (int) 3,"Smoothing steps", "The number of times that the whole algorithm (normal smoothing + vertex fitting) is iterated.")); - float maxVal = md.mm()->cm.bbox.Diag()/10; - parlst.addParam(RichAbsPerc("delta",maxVal*0.01,0,maxVal,"delta", "")); - parlst.addParam(RichBool ("Selected",md.mm()->cm.sfn>0,"Affect only selected faces","If checked the filter is performed only on the selected faces")); - } - break; - case FP_LINEAR_MORPH : - { - parlst.addParam(RichMesh ("TargetMesh", md.mm()->id(), &md,"Target Mesh", "The mesh that is the morph target.")); - parlst.addParam(RichDynamicFloat("PercentMorph", 0.0, -150, 250, - "% Morph", tr("The percent you want to morph towards (or away from) the target.
" - "0 means current mesh
" - "100 means targe mesh
" - "<0 and >100 linearly extrapolate between the two mesh
"))); - } - break; - case FP_SCALAR_HARMONIC_FIELD: - parlst.addParam(RichPosition("point1", md.mm()->cm.bbox.min, "Point 1", "A vertex on the mesh that represent one harmonic field boundary condition.")); - parlst.addParam(RichPosition("point2", md.mm()->cm.bbox.max, "Point 2", "A vertex on the mesh that represent one harmonic field boundary condition.")); - parlst.addParam(RichDynamicFloat("value1", 0.0f, 0.0f, 1.0f, "value for the 1st point", "Harmonic field value for the vertex.")); - parlst.addParam(RichDynamicFloat("value2", 1.0f, 0.0f, 1.0f, "value for the 2nd point", "Harmonic field value for the vertex.")); - parlst.addParam(RichBool("colorize", true, "Colorize", "Colorize the mesh to provide an indication of the obtained harmonic field.")); + switch (ID(action)) { + case FP_TWO_STEP_SMOOTH: return MeshModel::MM_VERTFACETOPO; + + case FP_CREASE_CUT: + case FP_UNSHARP_NORMAL: + case FP_RECOMPUTE_QUADFACE_NORMAL: + case FP_FACE_NORMAL_SMOOTHING: return MeshModel::MM_FACEFACETOPO; + + case FP_RECOMPUTE_FACE_NORMAL: + case FP_RECOMPUTE_VERTEX_NORMAL: + case FP_FACE_NORMAL_NORMALIZE: + case FP_VERTEX_NORMAL_NORMALIZE: + //case FP_DIRECTIONAL_PRESERVATION_STORE: + case FP_DIRECTIONAL_PRESERVATION_BLEND: + case FP_LINEAR_MORPH: + case FP_HC_LAPLACIAN_SMOOTH: + case FP_SD_LAPLACIAN_SMOOTH: + case FP_TAUBIN_SMOOTH: + case FP_DEPTH_SMOOTH: + case FP_LAPLACIAN_SMOOTH: + case FP_UNSHARP_GEOMETRY: + case FP_UNSHARP_QUALITY: + case FP_VERTEX_QUALITY_SMOOTHING: + case FP_SCALAR_HARMONIC_FIELD: + case FP_UNSHARP_VERTEX_COLOR: return MeshModel::MM_NONE; + default: assert(0); + } + return MeshModel::MM_NONE; +} + +RichParameterList FilterUnsharp::initParameterList(const QAction* action, const MeshDocument& md) +{ + RichParameterList parlst; + switch (ID(action)) { + case FP_RECOMPUTE_VERTEX_NORMAL: + parlst.addParam(RichEnum( + "weightMode", + 0, + QStringList() << "Simple Average" + << "By Area" + << "By Angle" + << "As defined by N. Max", + tr("Weighting Mode:"), + "")); break; - } - return parlst; + case FP_CREASE_CUT: + parlst.addParam(RichFloat( + "angleDeg", + 90.f, + tr("Crease Angle (degree)"), + tr("If the angle between the normals of two adjacent faces is larger that this " + "threshold the edge is considered a creased and the mesh is cut along it."))); + break; + case FP_UNSHARP_NORMAL: + parlst.addParam(RichBool( + "recalc", + false, + tr("Recompute Normals"), + tr("Recompute normals from scratch before the unsharp masking"))); + parlst.addParam(RichFloat( + "weight", + 0.3f, + tr("Unsharp Weight"), + tr("the unsharp weight wu in the unsharp mask equation: " + "
woorig + wu (orig - " + "lowpass)
"))); + parlst.addParam(RichFloat( + "weightOrig", + 1.f, + tr("Original Weight"), + tr("How much the original signal is used, e.g. the weight " + "wo in the above unsharp mask equation.
Usually " + "you should not need to change the default 1.0 value."))); + parlst.addParam(RichInt( + "iterations", + 5, + "Smooth Iterations", + tr("number of laplacian face smooth iterations in every run"))); + break; + case FP_UNSHARP_GEOMETRY: + parlst.addParam(RichFloat( + "weight", + 0.3f, + tr("Unsharp Weight"), + tr("the unsharp weight wu in the unsharp mask equation: " + "
woorig + wu (orig - " + "lowpass)
"))); + parlst.addParam(RichFloat( + "weightOrig", + 1.f, + tr("Original Weight"), + tr("How much the original signal is used, e.g. the weight " + "wo in the above unsharp mask equation
Usually you " + "should not need to change the default 1.0 value."))); + parlst.addParam(RichInt( + "iterations", + 5, + "Smooth Iterations", + tr("number of iterations of laplacian smooth in every run"))); + break; + case FP_UNSHARP_VERTEX_COLOR: + parlst.addParam(RichFloat( + "weight", + 0.3f, + tr("Unsharp Weight"), + tr("the unsharp weight wu in the unsharp mask equation: " + "
woorig + wu (orig - " + "lowpass)
"))); + parlst.addParam(RichFloat( + "weightOrig", + 1.f, + tr("Original Color Weight"), + tr("How much the original signal is used, e.g. the weight " + "wo in the above unsharp mask equation
Usually you " + "should not need to change the default 1.0 value."))); + parlst.addParam(RichInt( + "iterations", + 5, + "Smooth Iterations", + tr("number of iterations of laplacian smooth in every run"))); + break; + case FP_UNSHARP_QUALITY: + parlst.addParam(RichFloat( + "weight", + 0.3f, + tr("Unsharp Weight"), + tr("the unsharp weight wu in the unsharp mask equation: " + "
woorig + wu (orig - " + "lowpass)
"))); + parlst.addParam(RichFloat( + "weightOrig", + 1.f, + tr("Original Weight"), + tr("How much the original signal is used, e.g. the weight " + "wo in the above unsharp mask equation
Usually you " + "should not need to change the default 1.0 value."))); + parlst.addParam(RichInt( + "iterations", + 5, + "Smooth Iterations", + tr("number of iterations of laplacian smooth in every run"))); + break; + case FP_TWO_STEP_SMOOTH: + parlst.addParam(RichInt( + "stepSmoothNum", + (int) 3, + "Smoothing steps", + "The number of times that the whole algorithm (normal smoothing + vertex fitting) is " + "iterated.")); + parlst.addParam(RichFloat( + "normalThr", + (float) 60, + "Feature Angle Threshold (deg)", + "Specify a threshold angle (0..90) for features that you want to be " + "preserved.
Features forming angles LARGER than the specified threshold will be " + "preserved.
0 -> no smoothing
90 -> all faces will be smoothed")); + parlst.addParam(RichInt( + "stepNormalNum", + (int) 20, + "Normal Smoothing steps", + "Number of iterations of normal smoothing step. The larger the better and (the " + "slower)")); + parlst.addParam(RichInt( + "stepFitNum", + (int) 20, + "Vertex Fitting steps", + "Number of iterations of the vertex fitting procedure.")); + parlst.addParam(RichBool( + "Selected", + md.mm()->cm.sfn > 0, + "Affect only selected faces", + "If checked the filter is performed only on the selected faces")); + break; + case FP_LAPLACIAN_SMOOTH: + parlst.addParam(RichInt( + "stepSmoothNum", + (int) 3, + "Smoothing steps", + "The number of times that the whole algorithm (normal smoothing + vertex fitting) is " + "iterated.")); + parlst.addParam(RichBool( + "Boundary", + true, + "1D Boundary Smoothing", + "Smooth boundary edges only by themselves (e.g. the polyline forming the boundary of " + "the mesh is independently smoothed). This can reduce the shrinking on the border but " + "can have strange effects on very small boundaries.")); + parlst.addParam(RichBool( + "cotangentWeight", + true, + "Cotangent weighting", + "Use cotangent weighting scheme for the averaging of the position. Otherwise the " + "simpler umbrella scheme (1 if the edge is present) is used.")); + parlst.addParam(RichBool( + "Selected", + md.mm()->cm.sfn > 0, + "Affect only selection", + "If checked the filter is performed only on the selected area")); + break; + case FP_DEPTH_SMOOTH: + parlst.addParam(RichInt( + "stepSmoothNum", + (int) 3, + "Smoothing steps", + "The number of times that the whole algorithm (normal smoothing + vertex fitting) is " + "iterated.")); + parlst.addParam(RichDirection( + "viewPoint", + Point3f(0, 0, 0), + "Viewpoint", + "The position of the view point that is used to get the constraint direction.")); + parlst.addParam(RichAbsPerc( + "delta", + 1.0, + 0, + 1.0, + "Strength", + "How much smoothing is applied: 0 (no smooth) e 1 (full smooth)")); + parlst.addParam(RichBool( + "Selected", + md.mm()->cm.sfn > 0, + "Affect only selection", + "If checked the filter is performed only on the selected area")); + break; + //case FP_DIRECTIONAL_PRESERVATION_STORE: + //parlst.addParam(RichEnum( + // "step", + // 0, + // QStringList() << "Store Vertex Position" + // << "Blend Vertex Position", + // tr("Step:"), + // tr("The purpose of this filter is to constrain any smoothing algorithm to " + // "moving vertices only along a give line of sight.
First you should store " + // "current vertex position, than after applying one of the many smoothing algorithms " + // "you should re start this filter and blend the original positions with the smoothed " + // "results.
" + // "Given a view point vp , the smoothed vertex position vs and the " + // "original position v, The new vertex position is computed as the projection " + // "of vs on the line connecting v and vp."))); + //break; + case FP_DIRECTIONAL_PRESERVATION_BLEND: { + QString s; + if (md.mm()->cm.vert_attr.size() != 0) // get the first per vertex custom attribute name + s = QString::fromStdString((*md.mm()->cm.vert_attr.begin())._name); + parlst.addParam(RichString( + "attr_name", + s, + "Custom attribute name", + "The name of the per vertex custom point attribute that contains the previous " + "geometry.")); + parlst.addParam(RichDirection( + "viewPoint", + Point3f(0, 0, 0), + "Viewpoint", + "The position of the view point that is used to get the constraint direction.")); + } + break; + case FP_TAUBIN_SMOOTH: + parlst.addParam(RichFloat( + "lambda", + (float) 0.5, + "Lambda", + "The lambda parameter of the Taubin Smoothing algorithm")); + parlst.addParam(RichFloat( + "mu", (float) -0.53, "mu", "The mu parameter of the Taubin Smoothing algorithm")); + parlst.addParam(RichInt( + "stepSmoothNum", + (int) 10, + "Smoothing steps", + "The number of times that the taubin smoothing is iterated. Usually it requires a " + "larger number of iteration than the classical laplacian")); + parlst.addParam(RichBool( + "Selected", + md.mm()->cm.sfn > 0, + "Affect only selected faces", + "If checked the filter is performed only on the selected faces")); + break; + case FP_SD_LAPLACIAN_SMOOTH: { + parlst.addParam(RichInt( + "stepSmoothNum", + (int) 3, + "Smoothing steps", + "The number of times that the whole algorithm (normal smoothing + vertex fitting) is " + "iterated.")); + float maxVal = md.mm()->cm.bbox.Diag() / 10; + parlst.addParam(RichAbsPerc("delta", maxVal * 0.01, 0, maxVal, "delta", "")); + parlst.addParam(RichBool( + "Selected", + md.mm()->cm.sfn > 0, + "Affect only selected faces", + "If checked the filter is performed only on the selected faces")); + } break; + case FP_LINEAR_MORPH: { + parlst.addParam(RichMesh( + "TargetMesh", md.mm()->id(), &md, "Target Mesh", "The mesh that is the morph target.")); + parlst.addParam(RichDynamicFloat( + "PercentMorph", + 0.0, + -150, + 250, + "% Morph", + tr("The percent you want to morph towards (or away from) the target.
" + "0 means current mesh
" + "100 means targe mesh
" + "<0 and >100 linearly extrapolate between the two mesh
"))); + } break; + case FP_SCALAR_HARMONIC_FIELD: + parlst.addParam(RichPosition( + "point1", + md.mm()->cm.bbox.min, + "Point 1", + "A vertex on the mesh that represent one harmonic field boundary condition.")); + parlst.addParam(RichPosition( + "point2", + md.mm()->cm.bbox.max, + "Point 2", + "A vertex on the mesh that represent one harmonic field boundary condition.")); + parlst.addParam(RichDynamicFloat( + "value1", + 0.0f, + 0.0f, + 1.0f, + "value for the 1st point", + "Harmonic field value for the vertex.")); + parlst.addParam(RichDynamicFloat( + "value2", + 1.0f, + 0.0f, + 1.0f, + "value for the 2nd point", + "Harmonic field value for the vertex.")); + parlst.addParam(RichBool( + "colorize", + true, + "Colorize", + "Colorize the mesh to provide an indication of the obtained harmonic field.")); + break; + } + return parlst; } std::map FilterUnsharp::applyFilter( - const QAction *filter, - const RichParameterList & par, - MeshDocument &md, - unsigned int& /*postConditionMask*/, - vcg::CallBackPos * cb) + const QAction* filter, + const RichParameterList& par, + MeshDocument& md, + unsigned int& /*postConditionMask*/, + vcg::CallBackPos* cb) { - MeshModel &m=*(md.mm()); - switch(ID(filter)) - { - case FP_CREASE_CUT :{ - if ( tri::Clean::CountNonManifoldEdgeFF(m.cm,false) > 0 || tri::Clean::CountNonManifoldVertexFF(m.cm,false) > 0) - { - throw MLException("Mesh has some not 2 manifold faces, this filter require manifoldness"); + MeshModel& m = *(md.mm()); + switch (ID(filter)) { + case FP_CREASE_CUT: { + if (tri::Clean::CountNonManifoldEdgeFF(m.cm, false) > 0 || + tri::Clean::CountNonManifoldVertexFF(m.cm, false) > 0) { + throw MLException( + "Mesh has some not 2 manifold faces, this filter require manifoldness"); } Scalarm angleDeg = par.getFloat("angleDeg"); tri::CreaseCut(m.cm, math::ToRad(angleDeg)); m.clearDataMask(MeshModel::MM_FACEFACETOPO); - } - break; + } break; - case FP_FACE_NORMAL_SMOOTHING : + case FP_FACE_NORMAL_SMOOTHING: tri::UpdateFlags::FaceBorderFromNone(m.cm); tri::Smooth::FaceNormalLaplacianFF(m.cm); break; - case FP_VERTEX_QUALITY_SMOOTHING : + case FP_VERTEX_QUALITY_SMOOTHING: tri::UpdateFlags::FaceBorderFromNone(m.cm); tri::Smooth::VertexQualityLaplacian(m.cm); break; - case FP_LAPLACIAN_SMOOTH : - { + case FP_LAPLACIAN_SMOOTH: { tri::UpdateFlags::FaceBorderFromNone(m.cm); - int stepSmoothNum = par.getInt("stepSmoothNum"); - bool Selected=par.getBool("Selected"); - if(Selected && m.cm.svn==0) - m.cm.svn=tri::UpdateSelection::VertexFromFaceStrict(m.cm); - - bool boundarySmooth = par.getBool("Boundary"); - bool cotangentWeight = par.getBool("cotangentWeight"); - if(!boundarySmooth) tri::UpdateFlags::FaceClearB(m.cm); - - tri::Smooth::VertexCoordLaplacian(m.cm,stepSmoothNum,Selected,cotangentWeight,cb); - log( "Smoothed %d vertices", Selected ? m.cm.svn : m.cm.vn); - m.updateBoxAndNormals(); - } - break; - case FP_DEPTH_SMOOTH : - { - int stepSmoothNum = par.getInt("stepSmoothNum"); - bool Selected = par.getBool("Selected"); + int stepSmoothNum = par.getInt("stepSmoothNum"); + bool Selected = par.getBool("Selected"); if (Selected && m.cm.svn == 0) m.cm.svn = tri::UpdateSelection::VertexFromFaceStrict(m.cm); - Scalarm delta = par.getAbsPerc("delta"); + + bool boundarySmooth = par.getBool("Boundary"); + bool cotangentWeight = par.getBool("cotangentWeight"); + if (!boundarySmooth) + tri::UpdateFlags::FaceClearB(m.cm); + + tri::Smooth::VertexCoordLaplacian( + m.cm, stepSmoothNum, Selected, cotangentWeight, cb); + log("Smoothed %d vertices", Selected ? m.cm.svn : m.cm.vn); + m.updateBoxAndNormals(); + } break; + case FP_DEPTH_SMOOTH: { + int stepSmoothNum = par.getInt("stepSmoothNum"); + bool Selected = par.getBool("Selected"); + if (Selected && m.cm.svn == 0) + m.cm.svn = tri::UpdateSelection::VertexFromFaceStrict(m.cm); + Scalarm delta = par.getAbsPerc("delta"); Point3m viewpoint = par.getPoint3m("viewPoint"); - tri::Smooth::VertexCoordViewDepth(m.cm, viewpoint, delta, stepSmoothNum, Selected,true); + tri::Smooth::VertexCoordViewDepth( + m.cm, viewpoint, delta, stepSmoothNum, Selected, true); log("depth Smoothed %d vertices", Selected ? m.cm.svn : m.cm.vn); m.updateBoxAndNormals(); - } - break; - case FP_DIRECTIONAL_PRESERVATION: - { - const std::string AttribName("SavedVertPosition"); - int stepNum = par.getEnum("step"); - Point3m viewpoint = par.getPoint3m("viewPoint"); - float alpha = 1; + } break; +// case FP_DIRECTIONAL_PRESERVATION_STORE: { +// const std::string AttribName("SavedVertPosition"); +// if (tri::HasPerVertexAttribute(m.cm, AttribName)) { +// vcg::tri::Allocator::DeletePerVertexAttribute(m.cm, AttribName); +// } +// CMeshO::PerVertexAttributeHandle h = +// tri::Allocator::AddPerVertexAttribute(m.cm, AttribName); +// CMeshO::VertexIterator vi; - switch (stepNum) { - case 0: { // ***** Storing Vertex Data ***** - if(tri::HasPerVertexAttribute(m.cm,AttribName)) { - vcg::tri::Allocator::DeletePerVertexAttribute(m.cm,AttribName); - } - CMeshO::PerVertexAttributeHandle h = tri::Allocator::AddPerVertexAttribute (m.cm,AttribName); - CMeshO::VertexIterator vi; +// for (vi = m.cm.vert.begin(); vi != m.cm.vert.end(); ++vi) +// h[vi] = vi->cP(); - for(vi =m.cm.vert.begin();vi!= m.cm.vert.end();++vi) - h[vi] = vi->cP(); - - log( "Stored Position %d vertices", m.cm.vn); - break; +// log("Stored Position %d vertices", m.cm.vn); +// break; +// } + case FP_DIRECTIONAL_PRESERVATION_BLEND: { + const std::string attribName = par.getString("attr_name").toStdString(); + Point3m viewpoint = par.getPoint3m("viewPoint"); + float alpha = 1; + if (!tri::HasPerVertexAttribute(m.cm, attribName)) { + throw MLException( + "Failed to retrieve the stored vertex position. Current mesh has not a per vertex " + "custom point attribute called \"" + QString::fromStdString(attribName) + "\"
" + "You can create it by running the filter \"Define new per vertex custom point " + "attribute.\""); + } + CMeshO::PerVertexAttributeHandle h = + tri::Allocator::GetPerVertexAttribute(m.cm, attribName); + if (!vcg::tri::Allocator::IsValidHandle(m.cm, h)) { + throw MLException( + "Failed to retrieve the stored vertex position. Current mesh has not a per vertex " + "custom point attribute called \"" + QString::fromStdString(attribName) + "\"
" + "You can create it by running the filter \"Define new per vertex custom point " + "attribute.\""); } - case 1: { // ***** Recovering and Projection Vertex Data ***** - if(!tri::HasPerVertexAttribute(m.cm,AttribName)) { - throw MLException("Failed to retrieve the stored vertex position. First Store than recover."); - } - CMeshO::PerVertexAttributeHandle h = tri::Allocator::GetPerVertexAttribute (m.cm,AttribName); - CMeshO::VertexIterator vi; - for(vi= m.cm.vert.begin();vi!= m.cm.vert.end();++vi) { - Point3m d = h[vi] - viewpoint; - d.Normalize(); - Scalarm s = d * ( (*vi).cP() - h[vi] ); - (*vi).P() = h[vi] + d * (s*alpha); - } - m.updateBoxAndNormals(); - log("Projected smoothed Position %d vertices", m.cm.vn); - break; - } + CMeshO::VertexIterator vi; + for (vi = m.cm.vert.begin(); vi != m.cm.vert.end(); ++vi) { + Point3m d = h[vi] - viewpoint; + d.Normalize(); + Scalarm s = d * ((*vi).cP() - h[vi]); + (*vi).P() = h[vi] + d * (s * alpha); } + m.updateBoxAndNormals(); + log("Projected smoothed Position %d vertices", m.cm.vn); break; } - case FP_SD_LAPLACIAN_SMOOTH: - { + case FP_SD_LAPLACIAN_SMOOTH: { tri::UpdateFlags::FaceBorderFromNone(m.cm); - int stepSmoothNum = par.getInt("stepSmoothNum"); - size_t cnt=tri::UpdateSelection::VertexFromFaceStrict(m.cm); + int stepSmoothNum = par.getInt("stepSmoothNum"); + size_t cnt = tri::UpdateSelection::VertexFromFaceStrict(m.cm); // Small hack tri::UpdateFlags::FaceClearB(m.cm); Scalarm delta = par.getAbsPerc("delta"); - tri::Smooth::VertexCoordScaleDependentLaplacian_Fujiwara(m.cm,stepSmoothNum,delta); - log( "Smoothed %d vertices", cnt>0 ? cnt : m.cm.vn); + tri::Smooth::VertexCoordScaleDependentLaplacian_Fujiwara( + m.cm, stepSmoothNum, delta); + log("Smoothed %d vertices", cnt > 0 ? cnt : m.cm.vn); m.updateBoxAndNormals(); - } - break; - case FP_HC_LAPLACIAN_SMOOTH: - { + } break; + case FP_HC_LAPLACIAN_SMOOTH: { tri::UpdateFlags::FaceBorderFromNone(m.cm); - size_t cnt=tri::UpdateSelection::VertexFromFaceStrict(m.cm); - tri::Smooth::VertexCoordLaplacianHC(m.cm,1,cnt>0); + size_t cnt = tri::UpdateSelection::VertexFromFaceStrict(m.cm); + tri::Smooth::VertexCoordLaplacianHC(m.cm, 1, cnt > 0); m.updateBoxAndNormals(); - } - break; - case FP_TWO_STEP_SMOOTH: - { + } break; + case FP_TWO_STEP_SMOOTH: { tri::Clean::RemoveUnreferencedVertex(m.cm); tri::UpdateSelection::VertexFromFaceStrict(m.cm); int stepSmoothNum = par.getInt("stepSmoothNum"); // sigma==0 all is smoothed // sigma==1 nothing is smoothed - Scalarm sigma = cos(math::ToRad(par.getFloat("normalThr"))); - if(sigma<0) sigma=0; + Scalarm sigma = cos(math::ToRad(par.getFloat("normalThr"))); + if (sigma < 0) + sigma = 0; - int stepNormalNum = par.getInt("stepNormalNum"); - int stepFitNum = par.getInt("stepFitNum"); - bool selectedFlag = par.getBool("Selected"); - for(int i=0;i::PerFaceNormalized(m.cm); - tri::Smooth::VertexCoordPasoDoble(m.cm, stepNormalNum, sigma, stepFitNum,selectedFlag); + tri::Smooth::VertexCoordPasoDoble( + m.cm, stepNormalNum, sigma, stepFitNum, selectedFlag); } m.updateBoxAndNormals(); - } - break; - case FP_TAUBIN_SMOOTH : - { + } break; + case FP_TAUBIN_SMOOTH: { tri::UpdateFlags::FaceBorderFromNone(m.cm); - int stepSmoothNum = par.getInt("stepSmoothNum"); - Scalarm lambda=par.getFloat("lambda"); - Scalarm mu=par.getFloat("mu"); + int stepSmoothNum = par.getInt("stepSmoothNum"); + Scalarm lambda = par.getFloat("lambda"); + Scalarm mu = par.getFloat("mu"); - size_t cnt=tri::UpdateSelection::VertexFromFaceStrict(m.cm); - tri::Smooth::VertexCoordTaubin(m.cm,stepSmoothNum,lambda,mu,cnt>0,cb); - log( "Smoothed %d vertices", cnt>0 ? cnt : m.cm.vn); + size_t cnt = tri::UpdateSelection::VertexFromFaceStrict(m.cm); + tri::Smooth::VertexCoordTaubin(m.cm, stepSmoothNum, lambda, mu, cnt > 0, cb); + log("Smoothed %d vertices", cnt > 0 ? cnt : m.cm.vn); m.updateBoxAndNormals(); - } - break; - case FP_RECOMPUTE_FACE_NORMAL : - tri::UpdateNormal::PerFace(m.cm); - break; - case FP_RECOMPUTE_QUADFACE_NORMAL : + } break; + case FP_RECOMPUTE_FACE_NORMAL: tri::UpdateNormal::PerFace(m.cm); break; + case FP_RECOMPUTE_QUADFACE_NORMAL: // tri::UpdateNormal::PerBitQuadFaceNormalized(m.cm); tri::UpdateNormal::PerBitPolygonFaceNormalized(m.cm); break; - case FP_RECOMPUTE_VERTEX_NORMAL : - { + case FP_RECOMPUTE_VERTEX_NORMAL: { /** ToDo: This filter should NEVER modify per face normals... **/ int weightMode = par.getEnum("weightMode"); - switch(weightMode) - { + switch (weightMode) { case WMP_AVG: tri::UpdateNormal::NormalizePerFace(m.cm); tri::UpdateNormal::PerVertexFromCurrentFaceNormal(m.cm); @@ -595,226 +888,214 @@ std::map FilterUnsharp::applyFilter( tri::UpdateNormal::PerVertexNelsonMaxWeighted(m.cm); tri::UpdateNormal::NormalizePerVertex(m.cm); break; - default : - break; + default: break; } - } - break; - case FP_FACE_NORMAL_NORMALIZE : - tri::UpdateNormal::NormalizePerFace(m.cm); - break; - case FP_VERTEX_NORMAL_NORMALIZE : - tri::UpdateNormal::NormalizePerVertex(m.cm); - break; + } break; + case FP_FACE_NORMAL_NORMALIZE: tri::UpdateNormal::NormalizePerFace(m.cm); break; + case FP_VERTEX_NORMAL_NORMALIZE: tri::UpdateNormal::NormalizePerVertex(m.cm); break; - case FP_UNSHARP_NORMAL: - { + case FP_UNSHARP_NORMAL: { tri::UpdateFlags::FaceBorderFromNone(m.cm); - Scalarm alpha=par.getFloat("weight"); - Scalarm alphaorig=par.getFloat("weightOrig"); - int smoothIter = par.getInt("iterations"); + Scalarm alpha = par.getFloat("weight"); + Scalarm alphaorig = par.getFloat("weightOrig"); + int smoothIter = par.getInt("iterations"); tri::Allocator::CompactFaceVector(m.cm); vector normalOrig(m.cm.fn); - //Save original normal per face - for(int i=0;i::FaceNormalLaplacianFF(m.cm); - //Unsharp filter normal per face - for(int i=0;i::FaceBorderFromNone(m.cm); tri::UpdateFlags::FaceBorderFromNone(m.cm); - Scalarm alpha=par.getFloat("weight"); - Scalarm alphaorig=par.getFloat("weightOrig"); - int smoothIter = par.getInt("iterations"); + Scalarm alpha = par.getFloat("weight"); + Scalarm alphaorig = par.getFloat("weightOrig"); + int smoothIter = par.getInt("iterations"); tri::Allocator::CompactVertexVector(m.cm); vector geomOrig(m.cm.vn); - for(int i=0;i::VertexCoordLaplacian(m.cm,smoothIter); + tri::Smooth::VertexCoordLaplacian(m.cm, smoothIter); - for(int i=0;i::FaceBorderFromNone(m.cm); - Scalarm alpha=par.getFloat("weight"); - Scalarm alphaorig=par.getFloat("weightOrig"); - int smoothIter = par.getInt("iterations"); + Scalarm alpha = par.getFloat("weight"); + Scalarm alphaorig = par.getFloat("weightOrig"); + int smoothIter = par.getInt("iterations"); tri::Allocator::CompactVertexVector(m.cm); vector colorOrig(m.cm.vn); - for(int i=0;i::VertexColorLaplacian(m.cm,smoothIter); - for(int i=0;i::VertexColorLaplacian(m.cm, smoothIter); + for (int i = 0; i < m.cm.vn; ++i) { Color4f colorDelta = colorOrig[i] - Color4f::Construct(m.cm.vert[i].C()); - Color4f newCol = colorOrig[i]*alphaorig + colorDelta*alpha; // Unsharp formula + Color4f newCol = colorOrig[i] * alphaorig + colorDelta * alpha; // Unsharp formula Clamp(newCol); // Clamp everything in the 0..1 range m.cm.vert[i].C().Import(newCol); - } - } break; - case FP_UNSHARP_QUALITY: - { + } break; + case FP_UNSHARP_QUALITY: { tri::UpdateFlags::FaceBorderFromNone(m.cm); - Scalarm alpha=par.getFloat("weight"); - Scalarm alphaorig=par.getFloat("weightOrig"); - int smoothIter = par.getInt("iterations"); + Scalarm alpha = par.getFloat("weight"); + Scalarm alphaorig = par.getFloat("weightOrig"); + int smoothIter = par.getInt("iterations"); tri::Allocator::CompactVertexVector(m.cm); vector qualityOrig(m.cm.vn); - for(int i=0;i::VertexQualityLaplacian(m.cm, smoothIter); - for(int i=0;icm; - CMeshO &sourceMesh = m.cm; + case FP_LINEAR_MORPH: { + CMeshO& targetMesh = md.getMesh(par.getMeshId("TargetMesh"))->cm; + CMeshO& sourceMesh = m.cm; - //if the numbers of vertices don't match up - if(sourceMesh.vn != targetMesh.vn) - { - throw MLException("Number of vertices is not the same so you can't morph between these two meshes."); + // if the numbers of vertices don't match up + if (sourceMesh.vn != targetMesh.vn) { + throw MLException( + "Number of vertices is not the same so you can't morph between these two meshes."); } vcg::tri::Allocator::CompactEveryVector(sourceMesh); vcg::tri::Allocator::CompactEveryVector(targetMesh); - Scalarm percentage = par.getDynamicFloat("PercentMorph")/100.f; + Scalarm percentage = par.getDynamicFloat("PercentMorph") / 100.f; int i; - for(i=0;iupdateDataMask(MeshModel::MM_FACEFACETOPO); cb(1, "Computing harmonic field..."); - CMeshO & m = md.mm()->cm; + CMeshO& m = md.mm()->cm; vcg::tri::Allocator::CompactEveryVector(m); if (vcg::tri::Clean::CountConnectedComponents(m) > 1) { - throw MLException("A mesh composed by a single connected component is required by the filter to properly work."); + throw MLException( + "A mesh composed by a single connected component is required by the filter to " + "properly work."); } if (vcg::tri::Clean::CountNonManifoldEdgeFF(md.mm()->cm) > 0) { - throw MLException("Mesh has some not 2-manifold faces, this filter requires manifoldness"); + throw MLException( + "Mesh has some not 2-manifold faces, this filter requires manifoldness"); } - if (vcg::tri::Clean::CountNonManifoldVertexFF(md.mm()->cm) > 0) { - throw MLException("Mesh has some not 2-manifold vertices, this filter requires manifoldness"); + if (vcg::tri::Clean::CountNonManifoldVertexFF(md.mm()->cm) > 0) { + throw MLException( + "Mesh has some not 2-manifold vertices, this filter requires manifoldness"); } - md.mm()->updateDataMask(MeshModel::MM_VERTMARK | MeshModel::MM_FACEMARK | MeshModel::MM_FACEFLAG); + md.mm()->updateDataMask( + MeshModel::MM_VERTMARK | MeshModel::MM_FACEMARK | MeshModel::MM_FACEFLAG); // Get the two vertices with value set vcg::GridStaticPtr vg; vg.Set(m.vert.begin(), m.vert.end()); vcg::vertex::PointDistanceFunctor pd; - vcg::tri::Tmark mv; + vcg::tri::Tmark mv; mv.SetMesh(&m); mv.UnMarkAll(); - Point3m closestP; - Scalarm minDist = 0; - CVertexO * vp0 = vcg::GridClosest(vg, pd, mv, par.getPoint3m("point1"), m.bbox.Diag(), minDist, closestP); - CVertexO * vp1 = vcg::GridClosest(vg, pd, mv, par.getPoint3m("point2"), m.bbox.Diag(), minDist, closestP); - if (vp0 == NULL || vp1 == NULL || vp0 == vp1) - { + Point3m closestP; + Scalarm minDist = 0; + CVertexO* vp0 = vcg::GridClosest( + vg, pd, mv, par.getPoint3m("point1"), m.bbox.Diag(), minDist, closestP); + CVertexO* vp1 = vcg::GridClosest( + vg, pd, mv, par.getPoint3m("point2"), m.bbox.Diag(), minDist, closestP); + if (vp0 == NULL || vp1 == NULL || vp0 == vp1) { throw MLException("Error occurred for selected points."); } vcg::tri::Harmonic::ConstraintVec constraints; - constraints.push_back(vcg::tri::Harmonic::Constraint(vp0, FieldScalar(par.getFloat("value1")))); - constraints.push_back(vcg::tri::Harmonic::Constraint(vp1, FieldScalar(par.getFloat("value2")))); + constraints.push_back(vcg::tri::Harmonic::Constraint( + vp0, FieldScalar(par.getFloat("value1")))); + constraints.push_back(vcg::tri::Harmonic::Constraint( + vp1, FieldScalar(par.getFloat("value2")))); - CMeshO::PerVertexAttributeHandle handle = vcg::tri::Allocator::GetPerVertexAttribute(m, "harmonic"); + CMeshO::PerVertexAttributeHandle handle = + vcg::tri::Allocator::GetPerVertexAttribute(m, "harmonic"); - bool ok = vcg::tri::Harmonic::ComputeScalarField(m, constraints, handle); + bool ok = + vcg::tri::Harmonic::ComputeScalarField(m, constraints, handle); - if (!ok) - { + if (!ok) { throw MLException("An error occurred."); } md.mm()->updateDataMask(MeshModel::MM_VERTQUALITY); for (auto vi = m.vert.begin(); vi != m.vert.end(); ++vi) vi->Q() = handle[vi]; - if (par.getBool("colorize")) - { + if (par.getBool("colorize")) { md.mm()->updateDataMask(MeshModel::MM_VERTCOLOR); vcg::tri::UpdateColor::PerVertexQualityRamp(m); } cb(100, "Done."); } break; - default : - wrongActionCalled(filter); + default: wrongActionCalled(filter); } return std::map(); } -FilterPlugin::FilterArity FilterUnsharp::filterArity(const QAction * filter ) const +FilterPlugin::FilterArity FilterUnsharp::filterArity(const QAction* filter) const { - switch(ID(filter)) - { - case FP_LAPLACIAN_SMOOTH : - case FP_HC_LAPLACIAN_SMOOTH : - case FP_SD_LAPLACIAN_SMOOTH : - case FP_TWO_STEP_SMOOTH : - case FP_TAUBIN_SMOOTH : - case FP_DEPTH_SMOOTH : - case FP_DIRECTIONAL_PRESERVATION : - case FP_CREASE_CUT : - case FP_FACE_NORMAL_NORMALIZE: - case FP_VERTEX_NORMAL_NORMALIZE: - case FP_FACE_NORMAL_SMOOTHING: - case FP_VERTEX_QUALITY_SMOOTHING: - case FP_UNSHARP_NORMAL: - case FP_UNSHARP_GEOMETRY: - case FP_UNSHARP_QUALITY: - case FP_UNSHARP_VERTEX_COLOR: - case FP_RECOMPUTE_VERTEX_NORMAL: - case FP_RECOMPUTE_FACE_NORMAL: - case FP_RECOMPUTE_QUADFACE_NORMAL: - case FP_SCALAR_HARMONIC_FIELD: - return FilterPlugin::SINGLE_MESH; - case FP_LINEAR_MORPH : - return FilterPlugin::FIXED; - } - return FilterPlugin::NONE; + switch (ID(filter)) { + case FP_LAPLACIAN_SMOOTH: + case FP_HC_LAPLACIAN_SMOOTH: + case FP_SD_LAPLACIAN_SMOOTH: + case FP_TWO_STEP_SMOOTH: + case FP_TAUBIN_SMOOTH: + case FP_DEPTH_SMOOTH: + case FP_DIRECTIONAL_PRESERVATION_BLEND: + case FP_CREASE_CUT: + case FP_FACE_NORMAL_NORMALIZE: + case FP_VERTEX_NORMAL_NORMALIZE: + case FP_FACE_NORMAL_SMOOTHING: + case FP_VERTEX_QUALITY_SMOOTHING: + case FP_UNSHARP_NORMAL: + case FP_UNSHARP_GEOMETRY: + case FP_UNSHARP_QUALITY: + case FP_UNSHARP_VERTEX_COLOR: + case FP_RECOMPUTE_VERTEX_NORMAL: + case FP_RECOMPUTE_FACE_NORMAL: + case FP_RECOMPUTE_QUADFACE_NORMAL: + case FP_SCALAR_HARMONIC_FIELD: return FilterPlugin::SINGLE_MESH; + case FP_LINEAR_MORPH: return FilterPlugin::FIXED; + } + return FilterPlugin::NONE; } - MESHLAB_PLUGIN_NAME_EXPORTER(FilterUnsharp) diff --git a/src/meshlabplugins/filter_unsharp/filter_unsharp.h b/src/meshlabplugins/filter_unsharp/filter_unsharp.h index cad9cfc66..99decf0d9 100644 --- a/src/meshlabplugins/filter_unsharp/filter_unsharp.h +++ b/src/meshlabplugins/filter_unsharp/filter_unsharp.h @@ -1,32 +1,31 @@ -/**************************************************************************** -* MeshLab o o * -* A versatile mesh processing toolbox o o * -* _ O _ * -* Copyright(C) 2007 \/)\/ * -* 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 FilterUnsharp_PLUGIN_H -#define FilterUnsharp_PLUGIN_H +/***************************************************************************** + * MeshLab o o * + * A versatile mesh processing toolbox o o * + * _ O _ * + * Copyright(C) 2007-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 FILTER_UNSHARP_PLUGIN_H +#define FILTER_UNSHARP_PLUGIN_H #include #include - class FilterUnsharp : public QObject, public FilterPlugin { Q_OBJECT @@ -34,14 +33,11 @@ class FilterUnsharp : public QObject, public FilterPlugin Q_INTERFACES(FilterPlugin) public: - /* naming convention : - - FP -> Filter Plugin - - name of the plugin separated by _ - */ enum { FP_CREASE_CUT, FP_LAPLACIAN_SMOOTH, - FP_DIRECTIONAL_PRESERVATION, + //FP_DIRECTIONAL_PRESERVATION_STORE, + FP_DIRECTIONAL_PRESERVATION_BLEND, FP_DEPTH_SMOOTH, FP_HC_LAPLACIAN_SMOOTH, FP_SD_LAPLACIAN_SMOOTH, @@ -61,29 +57,26 @@ public: FP_RECOMPUTE_QUADFACE_NORMAL, FP_LINEAR_MORPH, FP_SCALAR_HARMONIC_FIELD - } ; - - /* default values for standard parameters' values of the plugin actions */ + }; + FilterUnsharp(); ~FilterUnsharp(); - QString pluginName() const; - QString filterName(ActionIDType filter) const; - QString filterInfo(ActionIDType filter) const; - FilterClass getClass(const QAction*) const; - int getRequirements(const QAction*); + QString pluginName() const; + QString filterName(ActionIDType filter) const; + QString filterInfo(ActionIDType filter) const; + FilterClass getClass(const QAction*) const; + int getRequirements(const QAction*); std::map applyFilter( - const QAction* action, - const RichParameterList & parameters, - MeshDocument &md, - unsigned int& postConditionMask, - vcg::CallBackPos * cb); - RichParameterList initParameterList(const QAction* action, const MeshDocument &/*m*/); - int postCondition(const QAction* ) const; - int getPreConditions(const QAction*) const; - FilterArity filterArity(const QAction* filter) const; - + const QAction* action, + const RichParameterList& parameters, + MeshDocument& md, + unsigned int& postConditionMask, + vcg::CallBackPos* cb); + RichParameterList initParameterList(const QAction* action, const MeshDocument& /*m*/); + int postCondition(const QAction*) const; + int getPreConditions(const QAction*) const; + FilterArity filterArity(const QAction* filter) const; }; - -#endif +#endif // FILTER_UNSHARP_PLUGIN_H From 9bcbe0aeddd2606c06cb88bc057f13e25417c35b Mon Sep 17 00:00:00 2001 From: alemuntoni Date: Thu, 7 Oct 2021 15:26:17 +0200 Subject: [PATCH 08/10] remove "change visibility of layers" filter --- .../filter_layer/filter_layer.cpp | 45 +------------------ .../filter_layer/filter_layer.h | 1 - 2 files changed, 1 insertion(+), 45 deletions(-) diff --git a/src/meshlabplugins/filter_layer/filter_layer.cpp b/src/meshlabplugins/filter_layer/filter_layer.cpp index 4151dbcfb..1deae0694 100644 --- a/src/meshlabplugins/filter_layer/filter_layer.cpp +++ b/src/meshlabplugins/filter_layer/filter_layer.cpp @@ -40,7 +40,6 @@ FilterLayerPlugin::FilterLayerPlugin() { typeList = { FP_FLATTEN, - FP_MESH_VISIBILITY, FP_DELETE_MESH, FP_DELETE_NON_VISIBLE_MESH, FP_DELETE_RASTER, @@ -80,7 +79,6 @@ QString FilterLayerPlugin::filterName(ActionIDType filterId) const case FP_FLATTEN: return QString("Flatten Visible Layers"); case FP_RENAME_MESH: return QString("Rename Current Mesh"); case FP_RENAME_RASTER: return QString("Rename Current Raster"); - case FP_MESH_VISIBILITY: return QString("Change Visibility of layer(s)"); case FP_EXPORT_CAMERAS: return QString("Export active rasters cameras to file"); case FP_IMPORT_CAMERAS: return QString("Import cameras for active rasters from file"); default: assert(0); @@ -115,8 +113,6 @@ QString FilterLayerPlugin::filterInfo(ActionIDType filterId) const "are preserved. Existing layers can be optionally deleted"); case FP_RENAME_MESH: return QString("Explicitly change the label shown for a given mesh"); case FP_RENAME_RASTER: return QString("Explicitly change the label shown for a given raster"); - case FP_MESH_VISIBILITY: - return QString("Make layer(s) visible/invisible. Useful for scripting."); case FP_EXPORT_CAMERAS: return QString("Export active cameras to file, in the .out or Agisoft .xml formats"); case FP_IMPORT_CAMERAS: @@ -175,27 +171,6 @@ FilterLayerPlugin::initParameterList(const QAction* action, const MeshDocument& parlst.addParam( RichString("newName", rm ? rm->label() : "", "New Label", "New Label for the raster.")); break; - case FP_MESH_VISIBILITY: - parlst.addParam(RichMesh( - "layer", - md.mm()->id(), - &md, - "Layer Name", - "The name of the layer that has to change visibility. If second parameter is not " - "empty, this parameter is ignored.")); - parlst.addParam(RichString( - "lName", - "", - "Substring match", - "Apply visibility to all layers with name substring matching the entered string. If " - "not empty, the first parameter is ignored.")); - parlst.addParam(RichBool( - "isMeshVisible", - true, - "Visible", - "It makes the selected layer(s) visible or invisible.")); - break; - case FP_EXPORT_CAMERAS: parlst.addParam(RichEnum( "ExportFile", @@ -249,21 +224,6 @@ std::map FilterLayerPlugin::applyFilter( } break; - case FP_MESH_VISIBILITY: { - QString match = par.getString("lName"); - if (match == "") { - MeshModel* mm = md.getMesh(par.getMeshId("layer")); - if (mm) - md.setVisible(mm->id(), par.getBool("isMeshVisible")); - } - else { - for (const MeshModel& mmp : md.meshIterator()) { - if (mmp.label().contains(match)) - md.setVisible(mmp.id(), par.getBool("isMeshVisible")); - } - } - } break; - case FP_DELETE_MESH: { if (md.mm()) md.delMesh(md.mm()->id()); @@ -930,7 +890,6 @@ FilterLayerPlugin::FilterClass FilterLayerPlugin::getClass(const QAction* a) con case FP_SPLITSELECTEDVERTICES: case FP_DUPLICATE: case FP_FLATTEN: - case FP_MESH_VISIBILITY: case FP_SPLITCONNECTED: case FP_DELETE_MESH: case FP_DELETE_NON_VISIBLE_MESH: return FilterPlugin::Layer; @@ -948,7 +907,6 @@ FilterPlugin::FilterArity FilterLayerPlugin::filterArity(const QAction* filter) { switch (ID(filter)) { case FP_RENAME_MESH: - case FP_MESH_VISIBILITY: case FP_SPLITSELECTEDFACES: case FP_SPLITSELECTEDVERTICES: case FP_DUPLICATE: @@ -978,8 +936,7 @@ int FilterLayerPlugin::postCondition(const QAction* filter) const case FP_DELETE_NON_SELECTED_RASTER: case FP_EXPORT_CAMERAS: case FP_IMPORT_CAMERAS: - case FP_SPLITCONNECTED: - case FP_MESH_VISIBILITY: return MeshModel::MM_NONE; + case FP_SPLITCONNECTED: return MeshModel::MM_NONE; case FP_SPLITSELECTEDFACES: case FP_SPLITSELECTEDVERTICES: return MeshModel::MM_GEOMETRY_AND_TOPOLOGY_CHANGE; diff --git a/src/meshlabplugins/filter_layer/filter_layer.h b/src/meshlabplugins/filter_layer/filter_layer.h index 29c5d1ffa..e828b9f7c 100644 --- a/src/meshlabplugins/filter_layer/filter_layer.h +++ b/src/meshlabplugins/filter_layer/filter_layer.h @@ -37,7 +37,6 @@ class FilterLayerPlugin : public QObject, public FilterPlugin public: enum { FP_FLATTEN, - FP_MESH_VISIBILITY, FP_SPLITSELECTEDFACES, FP_SPLITSELECTEDVERTICES, FP_SPLITCONNECTED, From d92495fdb412a7ded0047932a31f85a0ab03ff78 Mon Sep 17 00:00:00 2001 From: alemuntoni Date: Thu, 7 Oct 2021 15:31:00 +0200 Subject: [PATCH 09/10] remove "delaunay triangulation" filter --- .../filter_qhull/filter_qhull.cpp | 87 ------------------- .../filter_qhull/filter_qhull.h | 1 - 2 files changed, 88 deletions(-) diff --git a/src/meshlabplugins/filter_qhull/filter_qhull.cpp b/src/meshlabplugins/filter_qhull/filter_qhull.cpp index e34396bea..ad9d24bfb 100644 --- a/src/meshlabplugins/filter_qhull/filter_qhull.cpp +++ b/src/meshlabplugins/filter_qhull/filter_qhull.cpp @@ -44,7 +44,6 @@ QhullPlugin::QhullPlugin() { typeList = { FP_QHULL_CONVEX_HULL, - FP_QHULL_DELAUNAY_TRIANGULATION, FP_QHULL_VORONOI_FILTERING, FP_QHULL_ALPHA_COMPLEX_AND_SHAPE, FP_QHULL_VISIBLE_POINTS @@ -69,7 +68,6 @@ QString QhullPlugin::filterName(ActionIDType filterId) const { switch(filterId) { case FP_QHULL_CONVEX_HULL : return QString("Convex Hull"); - case FP_QHULL_DELAUNAY_TRIANGULATION : return QString("Delaunay Triangulation"); case FP_QHULL_VORONOI_FILTERING : return QString("Voronoi Filtering"); case FP_QHULL_ALPHA_COMPLEX_AND_SHAPE : return QString("Alpha Complex/Shape"); case FP_QHULL_VISIBLE_POINTS: return QString("Select Visible Points"); @@ -85,9 +83,6 @@ QString QhullPlugin::filterInfo(ActionIDType filterId) const switch(filterId) { case FP_QHULL_CONVEX_HULL : return QString("Calculate the convex hull with Qhull library (http://www.qhull.org/html/qconvex.htm).

" "The convex hull of a set of points is the boundary of the minimal convex set containing the given non-empty finite set of points."); - case FP_QHULL_DELAUNAY_TRIANGULATION : return QString("Calculate the Delaunay triangulation with Qhull library (http://www.qhull.org/html/qdelaun.htm).

" - "The Delaunay triangulation DT(P) of a set of points P in d-dimensional spaces is a triangulation of the convex hull " - "such that no point in P is inside the circum-sphere of any simplex in DT(P).
"); case FP_QHULL_VORONOI_FILTERING : return QString("Compute a Voronoi filtering (Amenta and Bern 1998) with Qhull library (http://www.qhull.org/).

" "The algorithm calculates a triangulation of the input point cloud without requiring vertex normals." "It uses a subset of the Voronoi vertices to remove triangles from the Delaunay triangulation.
" @@ -117,7 +112,6 @@ QhullPlugin::FilterClass QhullPlugin::getClass(const QAction *a) const switch(ID(a)) { case FP_QHULL_CONVEX_HULL : - case FP_QHULL_DELAUNAY_TRIANGULATION : case FP_QHULL_VORONOI_FILTERING : case FP_QHULL_ALPHA_COMPLEX_AND_SHAPE: return FilterClass (FilterPlugin::Remeshing) ; @@ -144,10 +138,6 @@ RichParameterList QhullPlugin::initParameterList(const QAction *action,const Mes //parlst.addParam(RichBool("reorient", false,"Re-orient all faces coherentely","Re-orient all faces coherentely")); break; } - case FP_QHULL_DELAUNAY_TRIANGULATION : - { - break; - } case FP_QHULL_VORONOI_FILTERING : { parlst.addParam(RichDynamicFloat("threshold",10.0f, 0.0f, 2000.0f,"Pole Discard Thr", @@ -220,83 +210,6 @@ std::map QhullPlugin::applyFilter( if (!result) throw MLException("Failed computing convex hull."); } break; - case FP_QHULL_DELAUNAY_TRIANGULATION: - { - MeshModel &m=*md.mm(); - MeshModel &pm =*md.addNewMesh("","Delaunay Triangulation"); - - m.clearDataMask(MeshModel::MM_WEDGTEXCOORD); - m.clearDataMask(MeshModel::MM_VERTTEXCOORD); - - int dim= 3; /* dimension of points */ - int numpoints= m.cm.vn; /* number of mesh vertices */ - - //facet_list contains the Delaunauy triangulation as a list of tetrahedral facets */ - facetT *facet_list = compute_delaunay(dim,numpoints,m); - - if(facet_list!=NULL){ - - int convexNumVert = qh_setsize(qh_facetvertices (facet_list, NULL, false)); - assert( qh num_vertices == convexNumVert); - - tri::Allocator::AddVertices(pm.cm,convexNumVert); - - vector::VertexPointer> ivp(qh num_vertices); - vertexT *vertex; - int i=0; - FORALLvertices{ - if ((*vertex).point){ - pm.cm.vert[i].P()[0] = (*vertex).point[0]; - pm.cm.vert[i].P()[1] = (*vertex).point[1]; - pm.cm.vert[i].P()[2] = (*vertex).point[2]; - ivp[qh_pointid(vertex->point)] = &pm.cm.vert[i]; - i++; - } - } - - // In 3-d Delaunay triangulation each facet is a tetrahedron. If triangulated, - //each ridge (d-1 vertices between two neighboring facets) is a triangle. - - facetT *facet, *neighbor; - qh visit_id++; - int ridgeCount=0; - - //Compute each ridge (triangle) once - FORALLfacet_(facet_list) - if (!facet->upperdelaunay) { - facet->visitid= qh visit_id; - qh_makeridges(facet); - ridgeT *ridge, **ridgep; - FOREACHridge_(facet->ridges) { - neighbor= otherfacet_(ridge, facet); - if (neighbor->visitid != qh visit_id) { - tri::Allocator::FaceIterator fi=tri::Allocator::AddFaces(pm.cm,1); - ridgeCount++; - int vertex_n, vertex_i; - FOREACHvertex_i_(ridge->vertices) - (*fi).V(vertex_i)= ivp[qh_pointid(vertex->point)]; - } - } - } - - assert(pm.cm.fn == ridgeCount); - log("Successfully created a mesh of %i vert and %i faces",pm.cm.vn,pm.cm.fn); - //m.cm.Clear(); - - //vcg::tri::UpdateBounding::Box(pm.cm); - //vcg::tri::UpdateNormal::PerVertexNormalizedPerFace(pm.cm); - pm.updateBoxAndNormals(); - - int curlong, totlong; /* memory remaining after qh_memfreeshort */ - qh_freeqhull(!qh_ALL); - qh_memfreeshort (&curlong, &totlong); - if (curlong || totlong) - fprintf (stderr, "qhull internal warning (main): did not free %d bytes of long memory (%d pieces)\n", - totlong, curlong); - } - else - throw MLException("Failed computing delaunay triangulation."); - } break; case FP_QHULL_VORONOI_FILTERING: { MeshModel &m=*md.mm(); diff --git a/src/meshlabplugins/filter_qhull/filter_qhull.h b/src/meshlabplugins/filter_qhull/filter_qhull.h index 5ed01bb3e..87f49f99d 100644 --- a/src/meshlabplugins/filter_qhull/filter_qhull.h +++ b/src/meshlabplugins/filter_qhull/filter_qhull.h @@ -46,7 +46,6 @@ public: enum { FP_QHULL_CONVEX_HULL, - FP_QHULL_DELAUNAY_TRIANGULATION, FP_QHULL_VORONOI_FILTERING, FP_QHULL_ALPHA_COMPLEX_AND_SHAPE, FP_QHULL_VISIBLE_POINTS From c5ca4f0023f6b2a90b5db84d962302e8d6ee3bb3 Mon Sep 17 00:00:00 2001 From: alemuntoni Date: Thu, 7 Oct 2021 16:19:39 +0200 Subject: [PATCH 10/10] "points cloud movement" takes two mesh parameters --- .../filter_dirt/filter_dirt.cpp | 336 +++++++------ src/meshlabplugins/filter_dirt/filter_dirt.h | 89 ++-- .../filter_mesh_booleans.cpp | 460 +++++++++--------- .../filter_mesh_booleans.h | 118 +++-- 4 files changed, 513 insertions(+), 490 deletions(-) diff --git a/src/meshlabplugins/filter_dirt/filter_dirt.cpp b/src/meshlabplugins/filter_dirt/filter_dirt.cpp index 562ddb172..6ede064b5 100644 --- a/src/meshlabplugins/filter_dirt/filter_dirt.cpp +++ b/src/meshlabplugins/filter_dirt/filter_dirt.cpp @@ -1,45 +1,44 @@ -/**************************************************************************** -* MeshLab o o * -* An extendible mesh processor o o * -* _ O _ * -* Copyright(C) 2005, 2006 \/)\/ * -* 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. * -* * -****************************************************************************/ +/***************************************************************************** + * MeshLab o o * + * An extendible mesh processor 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_dirt.h" -#include "particle.h" #include "dirt_utils.h" +#include "particle.h" -#include -#include -#include -#include -#include -#include -#include -#include #include -#include -#include -#include -#include -#include +#include #include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include #include #include @@ -49,12 +48,9 @@ using namespace tri; FilterDirt::FilterDirt() { - typeList = { - FP_DIRT, - FP_CLOUD_MOVEMENT - }; + typeList = {FP_DIRT, FP_CLOUD_MOVEMENT}; - for(ActionIDType tt: types()) + for (ActionIDType tt : types()) actionList.push_back(new QAction(filterName(tt), this)); } @@ -66,17 +62,17 @@ QString FilterDirt::pluginName() const QString FilterDirt::filterName(ActionIDType filterId) const { switch (filterId) { - case FP_DIRT:{ + case FP_DIRT: { return QString("Dust Accumulation"); break; } - case FP_CLOUD_MOVEMENT: - { + case FP_CLOUD_MOVEMENT: { return QString("Points Cloud Movement"); break; } - default:{ - assert(0); return QString("error"); + default: { + assert(0); + return QString("error"); break; } } @@ -85,162 +81,214 @@ QString FilterDirt::filterName(ActionIDType filterId) const QString FilterDirt::filterInfo(ActionIDType filterId) const { switch (filterId) { - case FP_DIRT:{ - return QString("Simulate dust accumulation over the mesh generating a cloud of points lying on the current mesh"); + case FP_DIRT: + return QString( + "Simulate dust accumulation over the mesh generating a cloud of points lying on the " + "current mesh"); break; - } - case FP_CLOUD_MOVEMENT:{ - return QString("Simulate the movement of a points cloud over a mesh"); + case FP_CLOUD_MOVEMENT: + return QString("Simulate the movement of a point cloud over a mesh"); break; - } default: - assert(0); return QString("error"); + assert(0); + return QString("error"); break; } } -RichParameterList FilterDirt::initParameterList(const QAction* filter, const MeshDocument & /*md*/) +RichParameterList FilterDirt::initParameterList(const QAction* filter, const MeshDocument& md) { RichParameterList par; - switch(ID(filter)){ - - case FP_DIRT:{ - par.addParam(RichDirection("dust_dir", Point3m(0, 1, 0), "Direction", "Direction of the dust source")); - par.addParam(RichInt("nparticles", 3, "max particles x face", "Max Number of Dust Particles to Generate Per Face")); - par.addParam(RichFloat("slippiness", 1.0f, "s", "The surface slippines(large s means less sticky)")); - par.addParam(RichFloat("adhesion", 0.2f, "k", "Factor to model the general adhesion")); - par.addParam(RichBool("draw_texture", false, "Draw Dust", "create a new texture saved in dirt_texture.png")); - // par.addParam(RichBool("colorize_mesh",false,"Map to Color","Color the mesh with colors based on the movement of the particle")); - break; + const MeshModel* pc = md.mm(); + const MeshModel* target = md.mm(); + if (md.mm()->cm.FN() == 0) { // point cloud looks ok + // looking for the target mesh different that the current one + for (const MeshModel& t : md.meshIterator()) { + if (&t != md.mm() && t.cm.FN() > 0) { + target = &t; + break; + } + } } - case FP_CLOUD_MOVEMENT:{ + else { // target mesh looks ok + // looking for the point cloud mesh different that the current one + for (const MeshModel& t : md.meshIterator()) { + if (&t != md.mm() && t.cm.FN() == 0) { + pc = &t; + break; + } + } + } + + switch (ID(filter)) { + case FP_DIRT: + par.addParam(RichDirection( + "dust_dir", Point3m(0, 1, 0), "Direction", "Direction of the dust source")); + par.addParam(RichInt( + "nparticles", + 3, + "max particles x face", + "Max Number of Dust Particles to Generate Per Face")); + par.addParam( + RichFloat("slippiness", 1.0f, "s", "The surface slippines(large s means less sticky)")); + par.addParam(RichFloat("adhesion", 0.2f, "k", "Factor to model the general adhesion")); + par.addParam(RichBool( + "draw_texture", false, "Draw Dust", "create a new texture saved in dirt_texture.png")); + // par.addParam(RichBool("colorize_mesh",false,"Map to Color","Color the mesh with colors + // based on the movement of the particle")); + break; + case FP_CLOUD_MOVEMENT: + par.addParam(RichMesh( + "point_cloud", + pc->id(), + &md, + "Point cloud", + "The point cloud that will be moved over the target mesh.")); + par.addParam(RichMesh( + "target_mesh", + target->id(), + &md, + "Target mesh", + "Target mesh on which the point cloud will be moved.")); par.addParam(RichDirection("gravity_dir", Point3m(0, -1, 0), "g", "Direction of gravity")); - par.addParam(RichDirection("force_dir", Point3m(0, 0, 0), "force", "Direction of the force acting on the points cloud")); + par.addParam(RichDirection( + "force_dir", + Point3m(0, 0, 0), + "force", + "Direction of the force acting on the points cloud")); par.addParam(RichInt("steps", 1, "s", "Simulation Steps")); - par.addParam(RichDynamicFloat("adhesion", 1.0f, 0.0f, 1.0f, "adhesion", "Factor to model the general adhesion.")); + par.addParam(RichDynamicFloat( + "adhesion", 1.0f, 0.0f, 1.0f, "adhesion", "Factor to model the general adhesion.")); par.addParam(RichFloat("velocity", 0, "v", "Initial velocity of the particle")); par.addParam(RichFloat("mass", 1, "m", "Mass of the particle")); - par.addParam(RichBool("colorize_mesh", false, "Map to Color", "Color the mesh with colors based on the movement of the particle")); + par.addParam(RichBool( + "colorize_mesh", + false, + "Map to Color", + "Color the mesh with colors based on the movement of the particle")); break; - } - default:{ - break; - } + default: break; } return par; } -int FilterDirt::getRequirements(const QAction * /*action*/) +int FilterDirt::getRequirements(const QAction* /*action*/) { - return MeshModel::MM_FACEFACETOPO | MeshModel::MM_VERTCOLOR |MeshModel::MM_FACECOLOR; + return MeshModel::MM_FACEFACETOPO | MeshModel::MM_VERTCOLOR | MeshModel::MM_FACECOLOR; } -std::map FilterDirt::applyFilter(const QAction *filter, const RichParameterList &par, MeshDocument &md, unsigned int& /*postConditionMask*/, vcg::CallBackPos *cb){ - switch(ID(filter)){ - - case FP_DIRT:{ +std::map FilterDirt::applyFilter( + const QAction* filter, + const RichParameterList& par, + MeshDocument& md, + unsigned int& /*postConditionMask*/, + vcg::CallBackPos* cb) +{ + switch (ID(filter)) { + case FP_DIRT: { /*Get Parameters*/ - Point3m dir=par.getPoint3m("dust_dir"); - Scalarm s=par.getFloat("slippiness"); - Scalarm k=par.getFloat("adhesion"); - bool draw=par.getBool("draw_texture"); - //bool colorize=par.getBool("colorize_mesh"); - int n_p=par.getInt("nparticles"); + Point3m dir = par.getPoint3m("dust_dir"); + Scalarm s = par.getFloat("slippiness"); + Scalarm k = par.getFloat("adhesion"); + bool draw = par.getBool("draw_texture"); + // bool colorize=par.getBool("colorize_mesh"); + int n_p = par.getInt("nparticles"); - MeshModel* currMM=md.mm(); + MeshModel* currMM = md.mm(); - if (currMM->cm.fn==0) { - throw MLException("This filter requires a mesh with some faces, it does not work on PointSet"); + if (currMM->cm.fn == 0) { + throw MLException( + "This filter requires a mesh with some faces, it does not work on PointSet"); } - if(draw && !tri::HasPerWedgeTexCoord(currMM->cm)){ + if (draw && !tri::HasPerWedgeTexCoord(currMM->cm)) { throw MLException("Current Mesh does not have per Wedge Tex Coordinates"); } vector dust_points; prepareMesh(currMM); - if(cb) (*cb)(10,"Computing Dust Amount..."); + if (cb) + (*cb)(10, "Computing Dust Amount..."); - ComputeNormalDustAmount(currMM,dir,k,s); - if(cb) (*cb)(30,"Computing Mesh Exposure..."); + ComputeNormalDustAmount(currMM, dir, k, s); + if (cb) + (*cb)(30, "Computing Mesh Exposure..."); - ComputeSurfaceExposure(currMM,1,1); + ComputeSurfaceExposure(currMM, 1, 1); - if(cb) (*cb)(50,"Generating Particles..."); + if (cb) + (*cb)(50, "Generating Particles..."); - GenerateParticles(currMM, dust_points,/*dust_particles,*/n_p, 0.6f); - MeshModel* dmm=md.addNewMesh("","dust_mesh",true); + GenerateParticles(currMM, dust_points, /*dust_particles,*/ n_p, 0.6f); + MeshModel* dmm = md.addNewMesh("", "dust_mesh", true); dmm->cm.Clear(); - tri::Allocator::AddVertices(dmm->cm,dust_points.size()); - CMeshO::VertexIterator vi; - vector::iterator dvi=dust_points.begin(); - if(cb) (*cb)(70,"Creating cloud Mesh..."); - for(vi=dmm->cm.vert.begin();vi!=dmm->cm.vert.end();++vi){ - vi->P()=(*dvi); + tri::Allocator::AddVertices(dmm->cm, dust_points.size()); + CMeshO::VertexIterator vi; + vector::iterator dvi = dust_points.begin(); + if (cb) + (*cb)(70, "Creating cloud Mesh..."); + for (vi = dmm->cm.vert.begin(); vi != dmm->cm.vert.end(); ++vi) { + vi->P() = (*dvi); ++dvi; } - if(draw) DrawDust(currMM,dmm); - //if(colorize) ColorizeMesh(currMM); - + if (draw) + DrawDust(currMM, dmm); + // if(colorize) ColorizeMesh(currMM); break; } - case FP_CLOUD_MOVEMENT:{ - if(md.meshNumber()!=2){ - throw MLException("This filter requires two mesh"); + case FP_CLOUD_MOVEMENT: { + MeshModel* base_mesh = md.getMesh(par.getMeshId("target_mesh")); + if (base_mesh->cm.fn == 0) { + throw MLException("The filter requires that the target mesh has some faces"); } - MeshModel* base_mesh=md.getMesh(0); - if(base_mesh->cm.fn==0){ - throw MLException("The filter requires that the first mesh has some faces"); + MeshModel* cloud_mesh = md.getMesh(par.getMeshId("point_cloud")); + if (cloud_mesh->cm.fn != 0) { + throw MLException("The filter requires that the point cloud has zero faces"); } - MeshModel* cloud_mesh=md.getMesh(1); - if(cloud_mesh->cm.fn!=0){ - throw MLException("The filter requires that the second mesh is a Point Set"); - } - - //Get Parameters - Point3m dir=par.getPoint3m("force_dir"); - Point3m g=par.getPoint3m("gravity_dir"); - Scalarm adhesion =par.getDynamicFloat("adhesion"); - Scalarm l=base_mesh->cm.bbox.Diag()*0.01; //mm()->cm.bbox.Diag(); - Scalarm v=par.getFloat("velocity"); - Scalarm m=par.getFloat("mass"); - int s=par.getInt("steps"); - bool colorize=par.getBool("colorize_mesh"); - if(!HasPerVertexAttribute(cloud_mesh->cm,"ParticleInfo")){ + // Get Parameters + Point3m dir = par.getPoint3m("force_dir"); + Point3m g = par.getPoint3m("gravity_dir"); + Scalarm adhesion = par.getDynamicFloat("adhesion"); + Scalarm l = base_mesh->cm.bbox.Diag() * 0.01; // mm()->cm.bbox.Diag(); + Scalarm v = par.getFloat("velocity"); + Scalarm m = par.getFloat("mass"); + int s = par.getInt("steps"); + bool colorize = par.getBool("colorize_mesh"); + if (!HasPerVertexAttribute(cloud_mesh->cm, "ParticleInfo")) { prepareMesh(base_mesh); - //Associate every point to a mesh and a Particle to every point - associateParticles(base_mesh,cloud_mesh,m,v,g); + // Associate every point to a mesh and a Particle to every point + associateParticles(base_mesh, cloud_mesh, m, v, g); } - //Move Cloud Mesh - float frac=100/s; - for(int i=0;i(); -}//End applyFilter +} // End applyFilter -int FilterDirt::postCondition(const QAction *a) const +int FilterDirt::postCondition(const QAction* a) const { - switch (ID(a)){ + switch (ID(a)) { case FP_DIRT: return MeshModel::MM_ALL; case FP_CLOUD_MOVEMENT: return MeshModel::MM_ALL; default: assert(0); @@ -248,12 +296,12 @@ int FilterDirt::postCondition(const QAction *a) const return MeshModel::MM_ALL; } -FilterPlugin::FilterClass FilterDirt::getClass(const QAction *filter) const +FilterPlugin::FilterClass FilterDirt::getClass(const QAction* filter) const { - switch (ID(filter)) { - case FP_DIRT:return FilterPlugin::Sampling; - case FP_CLOUD_MOVEMENT:return FilterPlugin::Remeshing; - default:assert(0); + switch (ID(filter)) { + case FP_DIRT: return FilterPlugin::Sampling; + case FP_CLOUD_MOVEMENT: return FilterPlugin::Remeshing; + default: assert(0); } return FilterPlugin::Generic; } diff --git a/src/meshlabplugins/filter_dirt/filter_dirt.h b/src/meshlabplugins/filter_dirt/filter_dirt.h index d3a4467af..620404ead 100644 --- a/src/meshlabplugins/filter_dirt/filter_dirt.h +++ b/src/meshlabplugins/filter_dirt/filter_dirt.h @@ -1,75 +1,66 @@ -/**************************************************************************** -* MeshLab o o * -* A versatile mesh processing toolbox o o * -* _ O _ * -* Copyright(C) 2007 \/)\/ * -* 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. * -* * -****************************************************************************/ +/***************************************************************************** + * 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 FILTERDIRTPLUGIN_H #define FILTERDIRTPLUGIN_H #include -#include #include +#include #include -#include -#include -//#include "muParser.h" +#include +#include using namespace vcg; -//using namespace mu; - class FilterDirt : public QObject, public FilterPlugin { Q_OBJECT MESHLAB_PLUGIN_IID_EXPORTER(FILTER_PLUGIN_IID) Q_INTERFACES(FilterPlugin) -protected: - double x,y,z,nx,ny,nz,r,g,b,q,rad; - //double x0,y0,z0,x1,y1,z1,x2,y2,z2,nx0,ny0,nz0,nx1,ny1,nz1,nx2,ny2,nz2,r0,g0,b0,r1,g1,b1,r2,g2,b2,q0,q1,q2; - double v,f,v0i,v1i,v2i; - std::vector v_attrNames; - std::vector v_attrValue; - //std::vector f_attrNames; - //std:: vector f_attrValue; - std::vector > vhandlers; - //std::vector > fhandlers; public: - enum {FP_DIRT,FP_CLOUD_MOVEMENT} ; + enum { FP_DIRT, FP_CLOUD_MOVEMENT }; FilterDirt(); - ~FilterDirt(){}; + ~FilterDirt() {}; - QString pluginName() const; + QString pluginName() const; virtual QString filterName(ActionIDType filter) const; virtual QString filterInfo(ActionIDType filter) const; - virtual int getRequirements(const QAction*); - virtual bool autoDialog(QAction *) {return true;} + virtual int getRequirements(const QAction*); + virtual bool autoDialog(QAction*) { return true; } // virtual void initParameterSet(QAction* filter,MeshModel &,RichParameterSet &){}; - RichParameterList initParameterList(const QAction*, const MeshDocument &/*m*/); - std::map applyFilter(const QAction* action, const RichParameterList & /*parent*/, MeshDocument &md, unsigned int& postConditionMask, vcg::CallBackPos * cb); - virtual int postCondition(const QAction*) const; - virtual FilterClass getClass (const QAction *) const; - FilterArity filterArity(const QAction*) const {return SINGLE_MESH;} + RichParameterList initParameterList(const QAction*, const MeshDocument& /*m*/); + std::map applyFilter( + const QAction* action, + const RichParameterList& /*parent*/, + MeshDocument& md, + unsigned int& postConditionMask, + vcg::CallBackPos* cb); + virtual int postCondition(const QAction*) const; + virtual FilterClass getClass(const QAction*) const; + FilterArity filterArity(const QAction*) const { return SINGLE_MESH; } }; - #endif diff --git a/src/meshlabplugins/filter_mesh_booleans/filter_mesh_booleans.cpp b/src/meshlabplugins/filter_mesh_booleans/filter_mesh_booleans.cpp index 2bcdbb065..27cf3054f 100644 --- a/src/meshlabplugins/filter_mesh_booleans/filter_mesh_booleans.cpp +++ b/src/meshlabplugins/filter_mesh_booleans/filter_mesh_booleans.cpp @@ -1,25 +1,25 @@ -/**************************************************************************** -* 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. * -* * -****************************************************************************/ +/***************************************************************************** + * 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_mesh_booleans.h" @@ -32,17 +32,14 @@ * Constructor usually performs only two simple tasks of filling the two lists * - typeList: with all the possible id of the filtering actions * - actionList with the corresponding actions. - * If you want to add icons to your filtering actions you can do here by construction the QActions accordingly + * If you want to add icons to your filtering actions you can do here by construction the QActions + * accordingly */ FilterMeshBooleans::FilterMeshBooleans() { - typeList = { - MESH_INTERSECTION, - MESH_UNION, - MESH_DIFFERENCE, - MESH_XOR}; + typeList = {MESH_INTERSECTION, MESH_UNION, MESH_DIFFERENCE, MESH_XOR}; - for(const ActionIDType& tt : typeList) + for (const ActionIDType& tt : typeList) actionList.push_back(new QAction(filterName(tt), this)); } @@ -64,22 +61,15 @@ QString FilterMeshBooleans::vendor() const */ QString FilterMeshBooleans::filterName(ActionIDType filterId) const { - switch(filterId) { - case MESH_INTERSECTION : - return "Mesh Boolean: Intersection"; - case MESH_UNION: - return "Mesh Boolean: Union"; - case MESH_DIFFERENCE: - return "Mesh Boolean: Difference"; - case MESH_XOR: - return "Mesh Boolean: Symmetric Difference (XOR)"; - default : - assert(0); - return ""; + switch (filterId) { + case MESH_INTERSECTION: return "Mesh Boolean: Intersection"; + case MESH_UNION: return "Mesh Boolean: Union"; + case MESH_DIFFERENCE: return "Mesh Boolean: Difference"; + case MESH_XOR: return "Mesh Boolean: Symmetric Difference (XOR)"; + default: assert(0); return ""; } } - /** * @brief // Info() must return the longer string describing each filtering action * (this string is used in the About plugin dialog) @@ -95,18 +85,12 @@ QString FilterMeshBooleans::filterInfo(ActionIDType filterId) const "The implementation refers to the following paper:
" "Qingnan Zhou, Eitan Grinspun, Denis Zorin, Alec Jacobson,
" "\"Mesh Arrangements for Solid Geometry\"
"; - switch(filterId) { - case MESH_INTERSECTION : - return description.arg("intersection"); - case MESH_UNION: - return description.arg("union"); - case MESH_DIFFERENCE: - return description.arg("difference"); - case MESH_XOR: - return description.arg("symmetric difference (XOR)"); - default : - assert(0); - return "Unknown Filter"; + switch (filterId) { + case MESH_INTERSECTION: return description.arg("intersection"); + case MESH_UNION: return description.arg("union"); + case MESH_DIFFERENCE: return description.arg("difference"); + case MESH_XOR: return description.arg("symmetric difference (XOR)"); + default: assert(0); return "Unknown Filter"; } } @@ -117,17 +101,16 @@ QString FilterMeshBooleans::filterInfo(ActionIDType filterId) const * @param a: the action of the filter * @return the class od the filter */ -FilterMeshBooleans::FilterClass FilterMeshBooleans::getClass(const QAction *a) const +FilterMeshBooleans::FilterClass FilterMeshBooleans::getClass(const QAction* a) const { - switch(ID(a)) { - case MESH_INTERSECTION : + switch (ID(a)) { + case MESH_INTERSECTION: case MESH_UNION: case MESH_DIFFERENCE: case MESH_XOR: - return FilterPlugin::FilterClass(FilterPlugin::FilterClass(FilterPlugin::Layer + FilterPlugin::Remeshing)); - default : - assert(0); - return FilterPlugin::Generic; + return FilterPlugin::FilterClass( + FilterPlugin::FilterClass(FilterPlugin::Layer + FilterPlugin::Remeshing)); + default: assert(0); return FilterPlugin::Generic; } } @@ -144,7 +127,7 @@ FilterPlugin::FilterArity FilterMeshBooleans::filterArity(const QAction*) const * @brief FilterSamplePlugin::getPreConditions * @return */ -//int FilterMeshBooleans::getPreConditions(const QAction*) const +// int FilterMeshBooleans::getPreConditions(const QAction*) const //{ // return MeshModel::MM_NONE; //} @@ -153,37 +136,36 @@ FilterPlugin::FilterArity FilterMeshBooleans::filterArity(const QAction*) const * @brief FilterSamplePlugin::postCondition * @return */ -//int FilterMeshBooleans::postCondition(const QAction*) const +// int FilterMeshBooleans::postCondition(const QAction*) const //{ // return MeshModel::MM_VERTCOORD | MeshModel::MM_FACENORMAL | MeshModel::MM_VERTNORMAL; //} /** - * @brief This function define the needed parameters for each filter. Return true if the filter has some parameters - * it is called every time, so you can set the default value of parameters according to the mesh - * For each parameter you need to define, + * @brief This function define the needed parameters for each filter. Return true if the filter has + * some parameters it is called every time, so you can set the default value of parameters according + * to the mesh For each parameter you need to define, * - the name of the parameter, * - the default value * - the string shown in the dialog - * - a possibly long string describing the meaning of that parameter (shown as a popup help in the dialog) + * - a possibly long string describing the meaning of that parameter (shown as a popup help in the + * dialog) * @param action * @param m * @param parlst */ -RichParameterList FilterMeshBooleans::initParameterList( - const QAction *action, - const MeshDocument& md) +RichParameterList +FilterMeshBooleans::initParameterList(const QAction* action, const MeshDocument& md) { RichParameterList parlst; - switch(ID(action)) { - case MESH_INTERSECTION : + switch (ID(action)) { + case MESH_INTERSECTION: case MESH_UNION: case MESH_DIFFERENCE: - case MESH_XOR: - { - const MeshModel *target = md.mm(); - //looking for a second mesh different that the current one - for (const MeshModel& t : md.meshIterator()){ + case MESH_XOR: { + const MeshModel* target = md.mm(); + // looking for a second mesh different that the current one + for (const MeshModel& t : md.meshIterator()) { if (&t != md.mm()) { target = &t; break; @@ -191,35 +173,47 @@ RichParameterList FilterMeshBooleans::initParameterList( } parlst.addParam(RichMesh( - "first_mesh", md.mm()->id(), &md, "First Mesh", - "The first operand of the boolean operation")); + "first_mesh", + md.mm()->id(), + &md, + "First Mesh", + "The first operand of the boolean operation")); parlst.addParam(RichMesh( - "second_mesh", target->id(), &md, "Second Mesh", - "The second operand of the boolean operation")); + "second_mesh", + target->id(), + &md, + "Second Mesh", + "The second operand of the boolean operation")); parlst.addParam(RichBool( - "transfer_face_color", false, - "Transfer face color", "Save the color of the birth face to the faces of resulting mesh.")); + "transfer_face_color", + false, + "Transfer face color", + "Save the color of the birth face to the faces of resulting mesh.")); parlst.addParam(RichBool( - "transfer_face_quality", false, - "Transfer face quality", "Save the quality of the birth face to the faces of resulting mesh.")); + "transfer_face_quality", + false, + "Transfer face quality", + "Save the quality of the birth face to the faces of resulting mesh.")); parlst.addParam(RichBool( - "transfer_vert_color", false, - "Transfer vertex color", - "Save the color of the birth vertex to the faces of resulting mesh. For newly created vertices, " - "a simple average of the neighbours is computed.")); + "transfer_vert_color", + false, + "Transfer vertex color", + "Save the color of the birth vertex to the faces of resulting mesh. For newly created " + "vertices, " + "a simple average of the neighbours is computed.")); parlst.addParam(RichBool( - "transfer_vert_quality", false, - "Transfer vertex quality", - "Save the quality of the birth vertex to the faces of resulting mesh. For newly created vertices, " - "a simple average of the neighbours is computed.")); - } - break; - default : - assert(0); + "transfer_vert_quality", + false, + "Transfer vertex quality", + "Save the quality of the birth vertex to the faces of resulting mesh. For newly " + "created vertices, " + "a simple average of the neighbours is computed.")); + } break; + default: assert(0); } return parlst; } @@ -233,65 +227,63 @@ RichParameterList FilterMeshBooleans::initParameterList( * @return true if the filter has been applied correctly, false otherwise */ std::map FilterMeshBooleans::applyFilter( - const QAction * action, - const RichParameterList & par, - MeshDocument &md, - unsigned int& /*postConditionMask*/, - vcg::CallBackPos *) + const QAction* action, + const RichParameterList& par, + MeshDocument& md, + unsigned int& /*postConditionMask*/, + vcg::CallBackPos*) { bool transfFaceQuality = par.getBool("transfer_face_quality"); - bool transfFaceColor = par.getBool("transfer_face_color"); + bool transfFaceColor = par.getBool("transfer_face_color"); bool transfVertQuality = par.getBool("transfer_vert_quality"); - bool transfVertColor = par.getBool("transfer_vert_color"); + bool transfVertColor = par.getBool("transfer_vert_color"); - - switch(ID(action)) { - case MESH_INTERSECTION : + switch (ID(action)) { + case MESH_INTERSECTION: booleanOperation( - md, - *md.getMesh(par.getMeshId("first_mesh")), - *md.getMesh(par.getMeshId("second_mesh")), - igl::MESH_BOOLEAN_TYPE_INTERSECT, - transfFaceQuality, - transfFaceColor, - transfVertQuality, - transfVertColor); + md, + *md.getMesh(par.getMeshId("first_mesh")), + *md.getMesh(par.getMeshId("second_mesh")), + igl::MESH_BOOLEAN_TYPE_INTERSECT, + transfFaceQuality, + transfFaceColor, + transfVertQuality, + transfVertColor); break; case MESH_UNION: booleanOperation( - md, - *md.getMesh(par.getMeshId("first_mesh")), - *md.getMesh(par.getMeshId("second_mesh")), - igl::MESH_BOOLEAN_TYPE_UNION, - transfFaceQuality, - transfFaceColor, - transfVertQuality, - transfVertColor); + md, + *md.getMesh(par.getMeshId("first_mesh")), + *md.getMesh(par.getMeshId("second_mesh")), + igl::MESH_BOOLEAN_TYPE_UNION, + transfFaceQuality, + transfFaceColor, + transfVertQuality, + transfVertColor); break; case MESH_DIFFERENCE: booleanOperation( - md, - *md.getMesh(par.getMeshId("first_mesh")), - *md.getMesh(par.getMeshId("second_mesh")), - igl::MESH_BOOLEAN_TYPE_MINUS, - transfFaceQuality, - transfFaceColor, - transfVertQuality, - transfVertColor); + md, + *md.getMesh(par.getMeshId("first_mesh")), + *md.getMesh(par.getMeshId("second_mesh")), + igl::MESH_BOOLEAN_TYPE_MINUS, + transfFaceQuality, + transfFaceColor, + transfVertQuality, + transfVertColor); break; case MESH_XOR: booleanOperation( - md, - *md.getMesh(par.getMeshId("first_mesh")), - *md.getMesh(par.getMeshId("second_mesh")), - igl::MESH_BOOLEAN_TYPE_XOR, - transfFaceQuality, - transfFaceColor, - transfVertQuality, - transfVertColor); + md, + *md.getMesh(par.getMeshId("first_mesh")), + *md.getMesh(par.getMeshId("second_mesh")), + igl::MESH_BOOLEAN_TYPE_XOR, + transfFaceQuality, + transfFaceColor, + transfVertQuality, + transfVertColor); break; - default : - wrongActionCalled(action); + default: wrongActionCalled(action); } return std::map(); } @@ -307,56 +299,51 @@ std::map FilterMeshBooleans::applyFilter( * @param transfColor: if true, face color will be transferred in the res mesh */ void FilterMeshBooleans::booleanOperation( - MeshDocument& md, - const MeshModel& m1, - const MeshModel& m2, - int op, - bool transfFaceQuality, - bool transfFaceColor, - bool transfVertQuality, - bool transfVertColor) + MeshDocument& md, + const MeshModel& m1, + const MeshModel& m2, + int op, + bool transfFaceQuality, + bool transfFaceColor, + bool transfVertQuality, + bool transfVertColor) { QString name; switch (op) { - case igl::MESH_BOOLEAN_TYPE_INTERSECT: - name = "intersection"; - break; - case igl::MESH_BOOLEAN_TYPE_MINUS: - name = "difference"; - break; - case igl::MESH_BOOLEAN_TYPE_XOR: - name = "xor"; - break; - case igl::MESH_BOOLEAN_TYPE_UNION: - name = "union"; - break; + case igl::MESH_BOOLEAN_TYPE_INTERSECT: name = "intersection"; break; + case igl::MESH_BOOLEAN_TYPE_MINUS: name = "difference"; break; + case igl::MESH_BOOLEAN_TYPE_XOR: name = "xor"; break; + case igl::MESH_BOOLEAN_TYPE_UNION: name = "union"; break; default: - throw MLException("Boolean Operation not found! Please report this issue on https://github.com/cnr-isti-vclab/meshlab/issues"); + throw MLException( + "Boolean Operation not found! Please report this issue on " + "https://github.com/cnr-isti-vclab/meshlab/issues"); } - //vcg to eigen meshes - EigenMatrixX3m V1 = meshlab::vertexMatrix(m1.cm); + // vcg to eigen meshes + EigenMatrixX3m V1 = meshlab::vertexMatrix(m1.cm); Eigen::MatrixX3i F1 = meshlab::faceMatrix(m1.cm); - EigenMatrixX3m V2 = meshlab::vertexMatrix(m2.cm); + EigenMatrixX3m V2 = meshlab::vertexMatrix(m2.cm); Eigen::MatrixX3i F2 = meshlab::faceMatrix(m2.cm); - EigenMatrixX3m VR; + EigenMatrixX3m VR; Eigen::MatrixX3i FR; - Eigen::VectorXi indices; //mapping indices for birth faces + Eigen::VectorXi indices; // mapping indices for birth faces - bool result = igl::copyleft::cgal::mesh_boolean(V1, F1, V2, F2, (igl::MeshBooleanType)op, VR, FR, indices); + bool result = igl::copyleft::cgal::mesh_boolean( + V1, F1, V2, F2, (igl::MeshBooleanType) op, VR, FR, indices); - if (!result){ + if (!result) { throw MLException( "Mesh inputs must induce a piecewise constant winding number field.
" "Make sure that both the input mesh are watertight (closed)."); } else { - //everything ok, create new mesh into md + // everything ok, create new mesh into md MeshModel* mesh = md.addNewMesh("", name); - mesh->cm = meshlab::meshFromMatrices(VR, FR); + mesh->cm = meshlab::meshFromMatrices(VR, FR); - //if transfer option enabled + // if transfer option enabled if (transfFaceColor || transfFaceQuality) transferFaceAttributes(*mesh, indices, m1, m2, transfFaceQuality, transfFaceColor); if (transfVertColor || transfVertQuality) @@ -381,16 +368,16 @@ void FilterMeshBooleans::booleanOperation( * @param color: if true, face color will be transferred */ void FilterMeshBooleans::transferFaceAttributes( - MeshModel& res, - const Eigen::VectorXi& faceIndices, - const MeshModel& m1, - const MeshModel& m2, - bool quality, - bool color) + MeshModel& res, + const Eigen::VectorXi& faceIndices, + const MeshModel& m1, + const MeshModel& m2, + bool quality, + bool color) { - //checking if m1 and m2 have quality and color + // checking if m1 and m2 have quality and color bool m1HasQuality = true, m1HasColor = true, m2HasQuality = true, m2HasColor = true; - if (quality){ + if (quality) { res.updateDataMask(MeshModel::MM_FACEQUALITY); if (!m1.hasDataMask(MeshModel::MM_FACEQUALITY)) m1HasQuality = false; @@ -405,20 +392,20 @@ void FilterMeshBooleans::transferFaceAttributes( m2HasColor = false; } - //for each index in the birth faces vector - for (unsigned int i = 0; i < faceIndices.size(); ++i){ - bool fromM1 = true; + // for each index in the birth faces vector + for (unsigned int i = 0; i < faceIndices.size(); ++i) { + bool fromM1 = true; unsigned int mIndex = faceIndices[i]; - //if the index is >= FN of m1, it means that the index is of m2 - if (faceIndices[i] >= m1.cm.FN()){ + // if the index is >= FN of m1, it means that the index is of m2 + if (faceIndices[i] >= m1.cm.FN()) { fromM1 = false; mIndex -= m1.cm.FN(); } - //if we need to transfer quality - if (quality){ - Scalarm q = 0; //default quality value + // if we need to transfer quality + if (quality) { + Scalarm q = 0; // default quality value if (fromM1 && m1HasQuality) q = m1.cm.face[mIndex].Q(); if (!fromM1 && m2HasQuality) @@ -426,9 +413,9 @@ void FilterMeshBooleans::transferFaceAttributes( res.cm.face[i].Q() = q; } - //if we need to transfer color + // if we need to transfer color if (color) { - vcg::Color4b c(128, 128, 128, 255); //default color value + vcg::Color4b c(128, 128, 128, 255); // default color value if (fromM1 && m1HasColor) c = m1.cm.face[mIndex].C(); if (!fromM1 && m2HasColor) @@ -455,19 +442,19 @@ void FilterMeshBooleans::transferFaceAttributes( * @param color: if true, vertex color will be transferred */ void FilterMeshBooleans::transferVertexAttributes( - MeshModel& res, - const Eigen::VectorXi& faceIndices, - const MeshModel& m1, - const MeshModel& m2, - bool quality, - bool color) + MeshModel& res, + const Eigen::VectorXi& faceIndices, + const MeshModel& m1, + const MeshModel& m2, + bool quality, + bool color) { res.updateDataMask(MeshModel::MM_VERTFACETOPO); vcg::tri::UpdateTopology::VertexFace(res.cm); - //checking if m1 and m2 have quality and color + // checking if m1 and m2 have quality and color bool m1HasQuality = true, m1HasColor = true, m2HasQuality = true, m2HasColor = true; - if (quality){ + if (quality) { res.updateDataMask(MeshModel::MM_VERTQUALITY); if (!m1.hasDataMask(MeshModel::MM_VERTQUALITY)) m1HasQuality = false; @@ -482,34 +469,34 @@ void FilterMeshBooleans::transferVertexAttributes( m2HasColor = false; } - //vertIndices construction + // vertIndices construction Eigen::VectorXi vertIndices(res.cm.VN()); vertIndices.setConstant(-1); - for (unsigned int i = 0; i < faceIndices.size(); ++i){ - bool fromM1 = true; + for (unsigned int i = 0; i < faceIndices.size(); ++i) { + bool fromM1 = true; unsigned int mIndex = faceIndices[i]; - //if the index is >= FN of m1, it means that the index is of m2 - if (faceIndices[i] >= m1.cm.FN()){ + // if the index is >= FN of m1, it means that the index is of m2 + if (faceIndices[i] >= m1.cm.FN()) { fromM1 = false; mIndex -= m1.cm.FN(); } CMeshO::ConstFacePointer fBirth; - CMeshO::FacePointer fRes = &(res.cm.face[i]); + CMeshO::FacePointer fRes = &(res.cm.face[i]); if (fromM1) fBirth = &(m1.cm.face[mIndex]); else fBirth = &(m2.cm.face[mIndex]); - for (unsigned int j = 0; j < 3; ++j){ + for (unsigned int j = 0; j < 3; ++j) { CMeshO::VertexPointer vp = fRes->V(j); - unsigned int vi = vcg::tri::Index(res.cm, vp); - if (vertIndices[vi] == -1){ - //look if there is an equal vertex in fBirth - for (unsigned k = 0; k < 3; ++k){ - if (fRes->V(j)->P() == fBirth->V(k)->P()){ + unsigned int vi = vcg::tri::Index(res.cm, vp); + if (vertIndices[vi] == -1) { + // look if there is an equal vertex in fBirth + for (unsigned k = 0; k < 3; ++k) { + if (fRes->V(j)->P() == fBirth->V(k)->P()) { unsigned int birthVertIndex; if (fromM1) birthVertIndex = vcg::tri::Index(m1.cm, fBirth->V(k)); @@ -522,13 +509,13 @@ void FilterMeshBooleans::transferVertexAttributes( } } - //update birth vertices - for (unsigned int i = 0; i < vertIndices.size(); ++i){ + // update birth vertices + for (unsigned int i = 0; i < vertIndices.size(); ++i) { bool fromM1 = false; bool fromM2 = false; int mIndex = vertIndices[i]; - if (vertIndices[i] >= m1.cm.VN()){ + if (vertIndices[i] >= m1.cm.VN()) { fromM2 = true; mIndex -= m1.cm.VN(); } @@ -536,9 +523,9 @@ void FilterMeshBooleans::transferVertexAttributes( fromM1 = true; } - //if we need to transfer quality - if (quality){ - Scalarm q = 0; //default quality value + // if we need to transfer quality + if (quality) { + Scalarm q = 0; // default quality value if (fromM1 && m1HasQuality) q = m1.cm.vert[mIndex].Q(); if (!fromM1 && m2HasQuality) @@ -546,9 +533,9 @@ void FilterMeshBooleans::transferVertexAttributes( res.cm.vert[i].Q() = q; } - //if we need to transfer color + // if we need to transfer color if (color) { - vcg::Color4b c(128, 128, 128, 255); //default color value + vcg::Color4b c(128, 128, 128, 255); // default color value if (fromM1 && m1HasColor) c = m1.cm.vert[mIndex].C(); if (fromM2 && m2HasColor) @@ -557,43 +544,44 @@ void FilterMeshBooleans::transferVertexAttributes( } } - //update newly created vertices - for (unsigned int i = 0; i < vertIndices.size(); ++i){ - if (vertIndices[i] == -1){ - //base values - unsigned int avgr=0, avgg=0, avgb=0, avga=0; - Scalarm avgq=0; + // update newly created vertices + for (unsigned int i = 0; i < vertIndices.size(); ++i) { + if (vertIndices[i] == -1) { + // base values + unsigned int avgr = 0, avgg = 0, avgb = 0, avga = 0; + Scalarm avgq = 0; unsigned int nAdjs = 0; - CMeshO::VertexPointer vp = &res.cm.vert[i]; + CMeshO::VertexPointer vp = &res.cm.vert[i]; vcg::face::VFIterator fadjit(vp); - //for each incident face fadj to vp - for (; !fadjit.End(); ++fadjit){ - for (unsigned int j = 0; j < 3; j++){ - //get each vertex to f + // for each incident face fadj to vp + for (; !fadjit.End(); ++fadjit) { + for (unsigned int j = 0; j < 3; j++) { + // get each vertex to f CMeshO::VertexPointer vadj = fadjit.F()->V(j); - unsigned int vi = vcg::tri::Index(res.cm, vadj); - //if the vertex is not i and it is not newly created + unsigned int vi = vcg::tri::Index(res.cm, vadj); + // if the vertex is not i and it is not newly created if (vi != i && vertIndices[vi] != -1) { nAdjs++; - //if we need to transfer color + // if we need to transfer color if (color) { avgr += res.cm.vert[vi].C()[0]; avgg += res.cm.vert[vi].C()[1]; avgb += res.cm.vert[vi].C()[2]; avga += res.cm.vert[vi].C()[3]; } - if (quality){ + if (quality) { avgq += res.cm.vert[vi].Q(); } } } } - if (nAdjs != 0){ + if (nAdjs != 0) { if (color) { - res.cm.vert[i].C() = vcg::Color4b(avgr/nAdjs, avgg/nAdjs, avgb/nAdjs, avga/nAdjs); + res.cm.vert[i].C() = + vcg::Color4b(avgr / nAdjs, avgg / nAdjs, avgb / nAdjs, avga / nAdjs); } - if (quality){ + if (quality) { res.cm.vert[i].Q() = avgq / nAdjs; } } diff --git a/src/meshlabplugins/filter_mesh_booleans/filter_mesh_booleans.h b/src/meshlabplugins/filter_mesh_booleans/filter_mesh_booleans.h index c2c5794ee..0bff24614 100644 --- a/src/meshlabplugins/filter_mesh_booleans/filter_mesh_booleans.h +++ b/src/meshlabplugins/filter_mesh_booleans/filter_mesh_booleans.h @@ -1,25 +1,25 @@ -/**************************************************************************** -* 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. * -* * -****************************************************************************/ +/***************************************************************************** + * 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_MESH_BOOLEANS_H #define MESHLAB_FILTER_MESH_BOOLEANS_H @@ -47,59 +47,55 @@ class FilterMeshBooleans : public QObject, public FilterPlugin Q_INTERFACES(FilterPlugin) public: - //enum used to give an ID to every filter implemented in the plugin - enum FileterIds { - MESH_INTERSECTION, - MESH_UNION, - MESH_DIFFERENCE, - MESH_XOR}; + // enum used to give an ID to every filter implemented in the plugin + enum FileterIds { MESH_INTERSECTION, MESH_UNION, MESH_DIFFERENCE, MESH_XOR }; FilterMeshBooleans(); QString pluginName() const; QString vendor() const; - QString filterName(ActionIDType filter) const; - QString filterInfo(ActionIDType filter) const; + QString filterName(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 postCondition(const QAction* ) const; - RichParameterList initParameterList(const QAction*, const MeshDocument &/*m*/); + // int getPreConditions(const QAction *) const; + // int postCondition(const QAction* ) const; + RichParameterList initParameterList(const QAction*, const MeshDocument& /*m*/); std::map applyFilter( - const QAction* action, - const RichParameterList & params, - MeshDocument &md, - unsigned int& postConditionMask, - vcg::CallBackPos * cb); + const QAction* action, + const RichParameterList& params, + MeshDocument& md, + unsigned int& postConditionMask, + vcg::CallBackPos* cb); private: - //generic boolean operation function + // generic boolean operation function static void booleanOperation( - MeshDocument& md, - const MeshModel& m1, - const MeshModel& m2, - int op, - bool transfFaceQuality, - bool transfFaceColor, - bool transfVertQuality, - bool transfVertColor); + MeshDocument& md, + const MeshModel& m1, + const MeshModel& m2, + int op, + bool transfFaceQuality, + bool transfFaceColor, + bool transfVertQuality, + bool transfVertColor); - //transfer functions + // transfer functions static void transferFaceAttributes( - MeshModel& res, - const Eigen::VectorXi& faceIndices, - const MeshModel& m1, - const MeshModel& m2, - bool quality, - bool color); + MeshModel& res, + const Eigen::VectorXi& faceIndices, + const MeshModel& m1, + const MeshModel& m2, + bool quality, + bool color); static void transferVertexAttributes( - MeshModel& res, - const Eigen::VectorXi& faceIndices, - const MeshModel& m1, - const MeshModel& m2, - bool quality, - bool color); + MeshModel& res, + const Eigen::VectorXi& faceIndices, + const MeshModel& m1, + const MeshModel& m2, + bool quality, + bool color); }; -#endif //MESHLAB_FILTER_MESH_BOOLEANS_H +#endif // MESHLAB_FILTER_MESH_BOOLEANS_H