From b52bb4ec359d912f1a91182d6bd545295e73d89e Mon Sep 17 00:00:00 2001 From: Paolo Cignoni cignoni Date: Thu, 15 May 2014 16:30:39 +0000 Subject: [PATCH] Added voronoi filter --- .../filter_voronoi/filter_voronoi.cpp | 330 ++++++++++++++++++ .../filter_voronoi/filter_voronoi.h | 42 +++ .../filter_voronoi/filter_voronoi.pro | 11 + .../filter_voronoi/filter_voronoi.xml | 157 +++++++++ 4 files changed, 540 insertions(+) create mode 100644 src/meshlabplugins/filter_voronoi/filter_voronoi.cpp create mode 100644 src/meshlabplugins/filter_voronoi/filter_voronoi.h create mode 100644 src/meshlabplugins/filter_voronoi/filter_voronoi.pro create mode 100644 src/meshlabplugins/filter_voronoi/filter_voronoi.xml diff --git a/src/meshlabplugins/filter_voronoi/filter_voronoi.cpp b/src/meshlabplugins/filter_voronoi/filter_voronoi.cpp new file mode 100644 index 000000000..c67884f48 --- /dev/null +++ b/src/meshlabplugins/filter_voronoi/filter_voronoi.cpp @@ -0,0 +1,330 @@ +/**************************************************************************** +* 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. * +* * +****************************************************************************/ + +#include "filter_voronoi.h" +#include +#include +#include +#include +#include + +// 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 +using namespace vcg; +using namespace std; +namespace vcg { +namespace tri { + +template +void BuildExtrudedFaceShell(MeshType &mIn, MeshType &mOut, float height=0, float inset=0, bool smoothFlag=true ) +{ + typedef typename MeshType::VertexPointer VertexPointer; + typedef typename MeshType::CoordType CoordType; + if(height==0) height = mIn.bbox.Diag()/100.0f; + if(inset==0) inset = mIn.bbox.Diag()/100.0f; + tri::UpdateFlags::FaceClearV(mIn); + for(size_t i=0;i vertVec; + tri::PolygonSupport::ExtractPolygon(&(mIn.face[i]),vertVec); + size_t vn = vertVec.size(); + // Add vertices (alternated top and bottom) + tri::Allocator<_SphMesh>::AddVertex(faceM, bary-nf); + tri::Allocator<_SphMesh>::AddVertex(faceM, bary+nf); + for(size_t j=0;j::AddVertex(faceM, vertVec[j]->P()-nf); + tri::Allocator<_SphMesh>::AddVertex(faceM, vertVec[j]->P()+nf); + } + + // Build top and bottom faces + for(size_t j=0;j::AddFace(faceM, 0, 2+(j+0)*2, 2+((j+1)%vn)*2 ); + for(size_t j=0;j::AddFace(faceM, 1, 3+(j+0)*2, 3+((j+1)%vn)*2 ); + + // Build side strip + for(size_t j=0;j::AddFace(faceM, 2+ j0*2 + 0 , 2+ j0*2+1, 2+j1*2+0); + tri::Allocator<_SphMesh>::AddFace(faceM, 2+ j0*2 + 1 , 2+ j1*2+1, 2+j1*2+0); + } + + for(size_t j=0;j<2*vn;++j) + faceM.face[j].SetS(); + + tri::UpdateTopology<_SphMesh>::FaceFace(faceM); + tri::UpdateFlags<_SphMesh>::FaceBorderFromFF(faceM); + tri::Refine(faceM, MidPoint<_SphMesh>(&faceM),0,true); + tri::Refine(faceM, MidPoint<_SphMesh>(&faceM),0,true); + + tri::Append::Mesh(mOut,faceM); + + } // end main loop for each face; +} + + +}; +}; + +FilterVoronoiPlugin::FilterVoronoiPlugin() +{ +} + +bool FilterVoronoiPlugin::applyFilter( const QString& filterName,MeshDocument& md,EnvWrap& env, vcg::CallBackPos* cb) +{ + if(filterName == "Cross Field Coloring") + { + MeshModel &m=*md.mm(); + m.updateDataMask(MeshModel::MM_VERTCOLOR); + m.updateDataMask(MeshModel::MM_VERTQUALITY); + for(CMeshO::VertexIterator vi=m.cm.vert.begin();vi!=m.cm.vert.end();++vi) + { + vi->Q() = Norm(vi->PD1()) / Norm(vi->PD2()); + } + + tri::UpdateColor::PerVertexQualityRamp(m.cm); + return true; + } + if(filterName == "Cross Field Creation") + { + MeshModel &m=*md.mm(); + m.updateDataMask(MeshModel::MM_VERTCURVDIR); + + int crossType = env.evalEnum("crossType"); + if(crossType == 0) // Linear Y + { + float range = m.cm.bbox.DimY(); + for(int i=0;i::PerVertexBasicRadialCrossField(m.cm,2.0); + } + + if(crossType == 2) // Curvature + { + } + return true; + } + + if(filterName == "Voronoi Sampling") + { + MeshModel *om=md.addOrGetMesh("voro", "voro",false); + MeshModel *poly=md.addOrGetMesh("poly", "poly",false); + + om->updateDataMask(MeshModel::MM_VERTCOLOR); + + const int sampleNum =env.evalInt("sampleNum"); + const int iterNum = env.evalInt("iterNum"); + const float radiusVariance = env.evalFloat("radiusVariance"); + const int distanceType=env.evalEnum("distanceType"); + + MeshModel &m=*md.mm(); + + m.updateDataMask(MeshModel::MM_FACEFACETOPO); + m.updateDataMask(MeshModel::MM_VERTFACETOPO); + m.updateDataMask(MeshModel::MM_VERTCURV); + m.updateDataMask(MeshModel::MM_VERTCURVDIR); + m.updateDataMask(MeshModel::MM_VERTCOLOR); + tri::UpdateCurvature::PerVertexBasicRadialCrossField(m.cm); + +// tri::EuclideanDistance dd; + vector seedVec; +// tri::ClusteringSampler cs(seedVec); +// tri::SurfaceSampling >::SamplingRandomGenerator().initialize(randSeed); + vector pointVec; + float radius=0; + tri::PoissonSampling(m.cm,pointVec,sampleNum,radius,radiusVariance); + + tri::VoronoiProcessingParameter vpp; + vpp.geodesicRelaxFlag = (env.evalEnum("relaxType")==0); + vpp.colorStrategy = env.evalEnum("colorStrategy"); + vpp.deleteUnreachedRegionFlag=true; + vpp.refinementRatio=10; + + if(env.evalBool("preprocessFlag")) + { + tri::VoronoiProcessing::PreprocessForVoronoi(m.cm,radius,vpp); + } + tri::VoronoiProcessing::SeedToVertexConversion(m.cm,pointVec,seedVec); + + QList meshlist; meshlist << m.id(); + + if(distanceType==0) // Uniform Euclidean Distance + { + EuclideanDistance dd; + for(int i=0;i >::VoronoiRelaxing(m.cm, seedVec, 1,dd,vpp); + md.updateRenderStateMeshes(meshlist,int(MeshModel::MM_VERTCOLOR)); + if (intteruptreq) return true; + } +// tri::VoronoiProcessing::ConvertVoronoiDiagramToMesh(m.cm,om->cm,poly->cm,seedVec, vpp); + } + + if(distanceType==1) + { + IsotropicDistance id(m.cm,radiusVariance); + for(int i=0;i >::VoronoiRelaxing(m.cm, seedVec, 1,id,vpp); + md.updateRenderStateMeshes(meshlist,int(MeshModel::MM_VERTCOLOR)); + if (intteruptreq) return true; + } +// tri::VoronoiProcessing::ConvertVoronoiDiagramToMesh(m.cm,om->cm,poly->cm,seedVec, vpp); + } + if(distanceType==2) + { + for(int i=0;i bcf(m.cm); + AnisotropicDistance ad(m.cm,bcf); + tri::VoronoiProcessing >::VoronoiRelaxing(m.cm, seedVec, 1, ad, vpp); + md.updateRenderStateMeshes(meshlist,int(MeshModel::MM_VERTCOLOR)); + if (intteruptreq) return true; + } + // tri::VoronoiProcessing >::ConvertVoronoiDiagramToMesh(m.cm,om->cm,seedVec, ad, vpp); + } + + md.updateRenderStateMeshes(meshlist,int(MeshModel::MM_VERTCOLOR)); + if (intteruptreq) return true; + + om->UpdateBoxAndNormals(); + return true; + } + + if(filterName=="Volumetric Sampling") /******************************************************/ + { + MeshModel *m= md.mm(); + m->updateDataMask(MeshModel::MM_FACEMARK); + + float sampleSurfRadius = env.evalFloat("sampleSurfRadius"); + float poissonRadius = env.evalFloat("poissonRadius"); + int sampleVolNum = env.evalInt("sampleVolNum"); + int poissonFlag = env.evalBool("poissonFiltering"); + + MeshModel *mcVm= md.addOrGetMesh("Montecarlo Volume","Montecarlo Volume",false,RenderMode(GLW::DMPoints)); + MeshModel *pVm= md.addOrGetMesh("Poisson Sampling","Poisson Sampling",false,RenderMode(GLW::DMPoints)); + MeshModel *pSm= md.addOrGetMesh("Surface Sampling","Surface Sampling",false,RenderMode(GLW::DMPoints)); + mcVm->updateDataMask(MeshModel::MM_VERTCOLOR | MeshModel::MM_VERTQUALITY); + pSm->updateDataMask(MeshModel::MM_VERTCOLOR | MeshModel::MM_VERTQUALITY); + VoronoiVolumeSampling vvs(m->cm, pVm->cm); + Log("Sampling Surface at a radius %f ",sampleSurfRadius); + cb(1, "Init"); + vvs.Init(sampleSurfRadius); + cb(30, "Sampling Volume..."); + vvs.BuildVolumeSampling(sampleVolNum,0,poissonRadius,cb); + tri::Append::MeshCopy(mcVm->cm,vvs.montecarloVolumeMesh); + tri::UpdateColor::PerVertexQualityRamp(mcVm->cm); + vvs.ThicknessEvaluator(); + tri::Append::MeshCopy(pSm->cm,vvs.poissonSurfaceMesh); + return true; + } + if(filterName=="Voronoi Scaffolding") /******************************************************/ + { + MeshModel *m= md.mm(); + m->updateDataMask(MeshModel::MM_FACEMARK); + MeshModel *pm= md.addOrGetMesh("Poisson-disk Samples","Poisson-disk Samples",false,RenderMode(GLW::DMPoints)); + MeshModel *mcVm= md.addOrGetMesh("Montecarlo Volume","Montecarlo Volume",false,RenderMode(GLW::DMPoints)); + MeshModel *vsm= md.addOrGetMesh("Voronoi Seeds","Voronoi Seeds",false,RenderMode(GLW::DMPoints)); + MeshModel *sm= md.addOrGetMesh("Scaffolding","Scaffolding",false,RenderMode(GLW::DMFlat)); + + pm->updateDataMask(m); + cb(10, "Sampling Surface..."); + float sampleSurfRadius = env.evalFloat("sampleSurfRadius"); + int sampleVolNum = env.evalInt("sampleVolNum"); + int voronoiSeed = env.evalInt("voronoiSeed"); + int voxelRes = env.evalInt("voxelRes"); + float isoThr = env.evalFloat("isoThr"); + int smoothStep = env.evalInt("smoothStep"); + int relaxStep = env.evalInt("relaxStep"); + int surfFlag = env.evalBool("surfFlag"); + int elemType = env.evalEnum("elemType"); + + VoronoiVolumeSampling vvs(m->cm,vsm->cm); + Log("Sampling Surface at a radius %f ",sampleSurfRadius); + vvs.Init(sampleSurfRadius); + cb(30, "Sampling Volume..."); + float poissonVolumeRadius=0; + vvs.BuildVolumeSampling(sampleVolNum,voronoiSeed,poissonVolumeRadius); + Log("Base Poisson volume sampling at a radius %f ",poissonVolumeRadius); + + cb(40, "Relaxing Volume..."); + vvs.RelaxVoronoiSamples(relaxStep); + + cb(50, "Building Scaffloding Volume..."); + vvs.BuildScaffoldingMesh(sm->cm,voxelRes,isoThr,elemType,surfFlag); + cb(90, "Final Smoothing..."); + tri::Smooth::VertexCoordLaplacian(sm->cm, smoothStep); + sm->UpdateBoxAndNormals(); + tri::Append::MeshCopy(mcVm->cm,vvs.montecarloVolumeMesh); + tri::Append::MeshCopy(pm->cm,vvs.poissonSurfaceMesh); + return true; + } + + if(filterName=="Create Solid Wireframe") /******************************************************/ + { + MeshModel *m= md.mm(); + m->updateDataMask(MeshModel::MM_FACEFACETOPO); + MeshModel *sm= md.addOrGetMesh("Shell Mesh","Shell Mesh",false,RenderMode(GLW::DMFlat)); + float edgeCylRadius = env.evalFloat("edgeCylRadius"); + float vertCylRadius = env.evalFloat("vertCylRadius"); + float vertSphRadius = env.evalFloat("vertSphRadius"); + float faceExtHeight = env.evalFloat("faceExtHeight"); + bool edgeCylFlag = env.evalBool("edgeCylFlag"); + bool vertCylFlag = env.evalBool("vertCylFlag"); + bool vertSphFlag = env.evalBool("vertSphFlag"); + bool faceExtFlag = env.evalBool("faceExtFlag"); + + sm->cm.Clear(); + sm->updateDataMask(MeshModel::MM_FACEFACETOPO); + tri::RequireFFAdjacency(sm->cm); + tri::UpdateNormal::PerVertexNormalizedPerFace(m->cm); + tri::Clean::RemoveUnreferencedVertex(m->cm); + tri::Allocator::CompactEveryVector(m->cm); + if(edgeCylFlag) tri::BuildCylinderEdgeShell(m->cm,sm->cm,edgeCylRadius); + if(vertCylFlag) tri::BuildCylinderVertexShell(m->cm,sm->cm,vertCylRadius,edgeCylRadius); + if(vertSphFlag) tri::BuildSphereVertexShell(m->cm,sm->cm,vertSphRadius); + if(faceExtFlag) tri::BuildExtrudedFaceShell(m->cm,sm->cm,faceExtHeight); + + sm->UpdateBoxAndNormals(); + return true; +} + return false; +} + +MESHLAB_PLUGIN_NAME_EXPORTER(FilterVoronoiPlugin) diff --git a/src/meshlabplugins/filter_voronoi/filter_voronoi.h b/src/meshlabplugins/filter_voronoi/filter_voronoi.h new file mode 100644 index 000000000..dffbf2afa --- /dev/null +++ b/src/meshlabplugins/filter_voronoi/filter_voronoi.h @@ -0,0 +1,42 @@ +/**************************************************************************** +* 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. * +* * +****************************************************************************/ +#ifndef _FILTER_ICP_H_ +#define _FILTER_ICP_H_ + +#include +//class QScriptEngine; + +class FilterVoronoiPlugin : public MeshLabFilterInterface +{ + Q_OBJECT + MESHLAB_PLUGIN_IID_EXPORTER(MESHLAB_FILTER_INTERFACE_IID) + Q_INTERFACES(MeshLabFilterInterface) +public: + + FilterVoronoiPlugin(); + + bool applyFilter(const QString& filterName,MeshDocument& md,EnvWrap& env, vcg::CallBackPos* cb) ; +}; + + +#endif diff --git a/src/meshlabplugins/filter_voronoi/filter_voronoi.pro b/src/meshlabplugins/filter_voronoi/filter_voronoi.pro new file mode 100644 index 000000000..e32cbf450 --- /dev/null +++ b/src/meshlabplugins/filter_voronoi/filter_voronoi.pro @@ -0,0 +1,11 @@ +include (../../shared.pri) + +HEADERS += filter_voronoi.h \ + voronoi_volume_sampling.h + +SOURCES += filter_voronoi.cpp + +TARGET = filter_voronoi +PRE_TARGETDEPS += filter_voronoi.xml + +macx:QMAKE_POST_LINK = "rsync -u "$$TARGET".xml ../../distrib/plugins/"$$TARGET".xml; rsync -u ../../distrib/plugins/"$$TARGET".xml "$$TARGET".xml" diff --git a/src/meshlabplugins/filter_voronoi/filter_voronoi.xml b/src/meshlabplugins/filter_voronoi/filter_voronoi.xml new file mode 100644 index 000000000..9accf407f --- /dev/null +++ b/src/meshlabplugins/filter_voronoi/filter_voronoi.xml @@ -0,0 +1,157 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
  • Geodesic: the seed is placed onto the vertex that maximize the geodesic distance from the border of the region
  • +
  • Squared Distance: the seed is placed in the vertex that minimize the squared sum of the distances from all the pints of the region.
  • + + ]]>
    + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    +