Create openMVS.build
This commit is contained in:
commit
365aa390ba
1856 files changed
+839085
No files matched your search
@@ -0,0 +1,619 @@
|
||||
/****************************************************************************
|
||||
* VCGLib o o *
|
||||
* Visual and Computer Graphics Library o o *
|
||||
* _ O _ *
|
||||
* Copyright(C) 2004-2016 \/)\/ *
|
||||
* 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 __PLYMC_H__
|
||||
#define __PLYMC_H__
|
||||
|
||||
#ifndef WIN32
|
||||
#define _int64 long long
|
||||
#define __int64 long long
|
||||
#define __cdecl
|
||||
#endif
|
||||
|
||||
#include <cstdio>
|
||||
#include <time.h>
|
||||
#include <float.h>
|
||||
#include <math.h>
|
||||
|
||||
#include <vcg/complex/complex.h>
|
||||
|
||||
#include <vcg/math/histogram.h>
|
||||
#include <vcg/complex/algorithms/geodesic.h>
|
||||
#include <wrap/io_trimesh/import.h>
|
||||
#include <wrap/io_trimesh/export_ply.h>
|
||||
//#include <wrap/ply/plystuff.h>
|
||||
|
||||
#include <vcg/complex/algorithms/create/marching_cubes.h>
|
||||
#include <vcg/complex/algorithms/create/mc_trivial_walker.h>
|
||||
|
||||
// local optimization
|
||||
#include <vcg/complex/algorithms/local_optimization.h>
|
||||
#include <vcg/complex/algorithms/local_optimization/tri_edge_collapse.h>
|
||||
#include <vcg/complex/algorithms/local_optimization/tri_edge_collapse_quadric.h>
|
||||
|
||||
#include <stdarg.h>
|
||||
#include "volume.h"
|
||||
#include "tri_edge_collapse_mc.h"
|
||||
namespace vcg {
|
||||
namespace tri {
|
||||
|
||||
// Simple prototype for later use...
|
||||
template<class MeshType>
|
||||
int MCSimplify( MeshType &m, float perc, bool preserveBB=true, vcg::CallBackPos *cb=0);
|
||||
|
||||
|
||||
/** Surface Reconstruction
|
||||
*
|
||||
* To allow the managment of a very large set of meshes to be merged,
|
||||
* it is templated on a MeshProvider class that is able to provide the meshes to be merged.
|
||||
* IT is the surface reconstrction algorithm that have been used for a long time inside the ISTI-Visual Computer Lab.
|
||||
* It is mostly a variant of the Curless et al. e.g. a volumetric approach with some original weighting schemes,"
|
||||
* a different expansion rule, and another approach to hole filling through volume dilation/relaxations.
|
||||
*/
|
||||
|
||||
template < class SMesh, class MeshProvider>
|
||||
class PlyMC
|
||||
{
|
||||
public:
|
||||
|
||||
typedef typename SMesh::FaceIterator SFaceIterator;
|
||||
typedef typename SMesh::VertexIterator SVertexIterator;
|
||||
|
||||
class MCVertex;
|
||||
class MCEdge;
|
||||
class MCFace;
|
||||
|
||||
class MCUsedTypes: public vcg::UsedTypes < vcg::Use<MCVertex>::template AsVertexType,
|
||||
vcg::Use<MCEdge >::template AsEdgeType,
|
||||
vcg::Use<MCFace >::template AsFaceType >{};
|
||||
|
||||
class MCVertex : public Vertex< MCUsedTypes, vertex::Coord3f, vertex::Color4b, vertex::Mark, vertex::VFAdj, vertex::BitFlags, vertex::Qualityf>{};
|
||||
class MCEdge : public Edge<MCUsedTypes,edge::VertexRef>{};
|
||||
class MCFace : public Face< MCUsedTypes, face::InfoOcf, face::VertexRef, face::FFAdjOcf, face::VFAdjOcf, face::BitFlags> {};
|
||||
class MCMesh : public vcg::tri::TriMesh< std::vector< MCVertex>, face::vector_ocf< MCFace > > {};
|
||||
|
||||
|
||||
//******************************************
|
||||
//typedef Voxel<float> Voxelf;
|
||||
typedef Voxelfc Voxelf;
|
||||
//******************************************
|
||||
|
||||
class Parameter
|
||||
{
|
||||
public:
|
||||
Parameter()
|
||||
{
|
||||
NCell=10000;
|
||||
WideNum= 3;
|
||||
WideSize=0;
|
||||
VoxSize=0;
|
||||
IPosS=Point3i(0,0,0); // SubVolume Start
|
||||
IPosE=Point3i(0,0,0); // SubVolume End
|
||||
IPosB=Point3i(0,0,0); // SubVolume to restart from in lexicographic order (useful for crashes)
|
||||
IPos=Point3i(0,0,0);
|
||||
IDiv=Point3i(1,1,1);
|
||||
VerboseLevel=0;
|
||||
SliceNum=1;
|
||||
FillThr=12;
|
||||
ExpAngleDeg=30;
|
||||
SmoothNum=1;
|
||||
RefillNum=1;
|
||||
IntraSmoothFlag = false;
|
||||
QualitySmoothAbs = 0.0f; // 0 means un-setted value.
|
||||
QualitySmoothVox = 3.0f; // expressed in voxel
|
||||
OffsetFlag=false;
|
||||
OffsetThr=-3;
|
||||
GeodesicQualityFlag=true;
|
||||
PLYFileQualityFlag=false;
|
||||
FullyPreprocessedFlag=false;
|
||||
SaveVolumeFlag=false;
|
||||
SafeBorder=1;
|
||||
CleaningFlag=false;
|
||||
SimplificationFlag=false;
|
||||
VertSplatFlag=false;
|
||||
MergeColor=false;
|
||||
basename = "plymcout";
|
||||
}
|
||||
|
||||
int NCell;
|
||||
int WideNum;
|
||||
float WideSize;
|
||||
float VoxSize;
|
||||
Point3i IPosS; // SubVolume Start
|
||||
Point3i IPosE; // SubVolume End
|
||||
Point3i IPosB; // SubVolume to restart from in lexicographic order (useful for crashes)
|
||||
Point3i IPos;
|
||||
Point3i IDiv;
|
||||
int VerboseLevel;
|
||||
int SliceNum;
|
||||
int FillThr;
|
||||
float ExpAngleDeg;
|
||||
int SmoothNum;
|
||||
int RefillNum;
|
||||
bool IntraSmoothFlag;
|
||||
float QualitySmoothAbs; // 0 means un-setted value.
|
||||
float QualitySmoothVox; // expressed in voxel
|
||||
bool OffsetFlag;
|
||||
float OffsetThr;
|
||||
bool GeodesicQualityFlag;
|
||||
bool PLYFileQualityFlag;
|
||||
bool FullyPreprocessedFlag;
|
||||
bool CleaningFlag;
|
||||
bool SaveVolumeFlag;
|
||||
int SafeBorder;
|
||||
bool SimplificationFlag;
|
||||
bool VertSplatFlag;
|
||||
bool MergeColor;
|
||||
std::string basename;
|
||||
std::vector<std::string> OutNameVec;
|
||||
std::vector<std::string> OutNameSimpVec;
|
||||
}; //end Parameter class
|
||||
|
||||
/// PLYMC Data
|
||||
MeshProvider MP;
|
||||
Parameter p;
|
||||
Volume<Voxelf> VV;
|
||||
std::string errorMessage;
|
||||
|
||||
/// PLYMC Methods
|
||||
|
||||
bool InitMesh(SMesh &m, const char *filename, Matrix44f Tr)
|
||||
{
|
||||
int loadmask;
|
||||
int ret = tri::io::Importer<SMesh>::Open(m,filename,loadmask);
|
||||
if(ret)
|
||||
{
|
||||
printf("Error: unabe to open mesh '%s'",filename);
|
||||
return false;
|
||||
}
|
||||
|
||||
if(p.VertSplatFlag)
|
||||
{
|
||||
if(!(loadmask & tri::io::Mask::IOM_VERTNORMAL))
|
||||
{
|
||||
if(m.FN()==0)
|
||||
{
|
||||
errorMessage = "Error: mesh has not per vertex normals\n";
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
tri::Clean<SMesh>::RemoveUnreferencedVertex(m);
|
||||
tri::Allocator<SMesh>::CompactEveryVector(m);
|
||||
tri::UpdateNormal<SMesh>::PerVertexNormalizedPerFaceNormalized(m);
|
||||
}
|
||||
}
|
||||
tri::UpdateNormal<SMesh>::NormalizePerVertex(m);
|
||||
int badNormalCnt=0;
|
||||
for(SVertexIterator vi=m.vert.begin(); vi!=m.vert.end();++vi)
|
||||
if(math::Abs(SquaredNorm((*vi).N())-1.0)>0.0001)
|
||||
{
|
||||
badNormalCnt++;
|
||||
tri::Allocator<SMesh>::DeleteVertex(m,*vi);
|
||||
}
|
||||
tri::Allocator<SMesh>::CompactEveryVector(m);
|
||||
if(badNormalCnt > m.VN()/10)
|
||||
{
|
||||
errorMessage = "Error: mesh has null normals\n";
|
||||
return false;
|
||||
}
|
||||
|
||||
if(!(loadmask & tri::io::Mask::IOM_VERTQUALITY))
|
||||
tri::UpdateQuality<SMesh>::VertexConstant(m,0);
|
||||
tri::UpdateNormal<SMesh>::PerVertexMatrix(m,Tr);
|
||||
}
|
||||
else // processing for triangle meshes
|
||||
{
|
||||
if(!p.FullyPreprocessedFlag)
|
||||
{
|
||||
if(p.CleaningFlag){
|
||||
int dup = tri::Clean<SMesh>::RemoveDuplicateVertex(m);
|
||||
int unref = tri::Clean<SMesh>::RemoveUnreferencedVertex(m);
|
||||
printf("Removed %i duplicates and %i unref",dup,unref);
|
||||
}
|
||||
|
||||
tri::UpdateNormal<SMesh>::PerVertexNormalizedPerFaceNormalized(m);
|
||||
if(p.GeodesicQualityFlag) {
|
||||
tri::UpdateTopology<SMesh>::VertexFace(m);
|
||||
tri::UpdateFlags<SMesh>::FaceBorderFromVF(m);
|
||||
tri::Geodesic<SMesh>::DistanceFromBorder(m);
|
||||
}
|
||||
}
|
||||
|
||||
tri::UpdatePosition<SMesh>::Matrix(m,Tr,true);
|
||||
tri::UpdateBounding<SMesh>::Box(m);
|
||||
printf("Init Mesh %s (%ivn,%ifn)\n",filename,m.vn,m.fn);
|
||||
}
|
||||
for(SVertexIterator vi=m.vert.begin(); vi!=m.vert.end();++vi)
|
||||
VV.Interize((*vi).P());
|
||||
return true;
|
||||
}
|
||||
|
||||
// This function add a mesh (or a point cloud to the volume)
|
||||
// the point cloud MUST have normalized vertex normals.
|
||||
bool AddMeshToVolumeM(SMesh &m, std::string meshname, const double w )
|
||||
{
|
||||
tri::RequireCompactness(m);
|
||||
if(!m.bbox.Collide(VV.SubBoxSafe)) return false;
|
||||
size_t found =meshname.find_last_of("/\\");
|
||||
std::string shortname = meshname.substr(found+1);
|
||||
|
||||
Volume <Voxelf> B;
|
||||
B.Init(VV);
|
||||
|
||||
bool res=false;
|
||||
double quality=0;
|
||||
|
||||
// Now add the mesh to the volume
|
||||
if(!p.VertSplatFlag)
|
||||
{
|
||||
float minq=std::numeric_limits<float>::max(), maxq=-std::numeric_limits<float>::max();
|
||||
// Calcolo range qualita geodesica PER FACCIA come media di quelle per vertice
|
||||
for(SFaceIterator fi=m.face.begin(); fi!=m.face.end();++fi){
|
||||
(*fi).Q()=((*fi).V(0)->Q()+(*fi).V(1)->Q()+(*fi).V(2)->Q())/3.0f;
|
||||
minq=std::min((*fi).Q(),minq);
|
||||
maxq=std::max((*fi).Q(),maxq);
|
||||
}
|
||||
|
||||
// La qualita' e' inizialmente espressa come distanza assoluta dal bordo della mesh
|
||||
printf("Q [%4.2f %4.2f] \n",minq,maxq);
|
||||
bool closed=false;
|
||||
if(minq==maxq) closed=true; // se la mesh e' chiusa la ComputeGeodesicQuality mette la qualita a zero ovunque
|
||||
// Classical approach: scan each face
|
||||
int tt0=clock();
|
||||
printf("---- Face Rasterization");
|
||||
for(SFaceIterator fi=m.face.begin(); fi!=m.face.end();++fi)
|
||||
{
|
||||
if(closed || (p.PLYFileQualityFlag==false && p.GeodesicQualityFlag==false)) quality=1.0;
|
||||
else quality=w*(*fi).Q();
|
||||
if(quality)
|
||||
res |= B.ScanFace((*fi).V(0)->P(),(*fi).V(1)->P(),(*fi).V(2)->P(),quality,(*fi).N());
|
||||
}
|
||||
printf(" : %li\n",clock()-tt0);
|
||||
|
||||
} else
|
||||
{ // Splat approach add only the vertices to the volume
|
||||
printf("Vertex Splatting\n");
|
||||
for(SVertexIterator vi=m.vert.begin();vi!=m.vert.end();++vi)
|
||||
{
|
||||
if(p.PLYFileQualityFlag==false) quality=1.0;
|
||||
else quality=w*(*vi).Q();
|
||||
if(quality)
|
||||
res |= B.SplatVert((*vi).P(),quality,(*vi).N(),(*vi).C());
|
||||
}
|
||||
}
|
||||
if(!res) return false;
|
||||
|
||||
int vstp=0;
|
||||
if(p.VerboseLevel>0) {
|
||||
B.SlicedPPM(shortname.c_str(),std::string(SFormat("%02i",vstp)).c_str(),p.SliceNum );
|
||||
B.SlicedPPMQ(shortname.c_str(),std::string(SFormat("%02i",vstp)).c_str(),p.SliceNum );
|
||||
vstp++;
|
||||
}
|
||||
for(int i=0;i<p.WideNum;++i) {
|
||||
B.Expand(math::ToRad(p.ExpAngleDeg));
|
||||
if(p.VerboseLevel>1) B.SlicedPPM(shortname.c_str(),SFormat("%02ie",vstp++),p.SliceNum );
|
||||
B.Refill(p.FillThr);
|
||||
if(p.VerboseLevel>1) B.SlicedPPM(shortname.c_str(),SFormat("%02if",vstp++),p.SliceNum );
|
||||
if(p.IntraSmoothFlag)
|
||||
{
|
||||
Volume <Voxelf> SM;
|
||||
SM.Init(VV);
|
||||
SM.CopySmooth(B,1,p.QualitySmoothAbs);
|
||||
B=SM;
|
||||
if(p.VerboseLevel>1) B.SlicedPPM(shortname.c_str(),SFormat("%02is",vstp++),p.SliceNum );
|
||||
// if(VerboseLevel>1) B.SlicedPPMQ(shortname,SFormat("%02is",vstp),SliceNum );
|
||||
}
|
||||
}
|
||||
if(p.SmoothNum>0)
|
||||
{
|
||||
Volume <Voxelf> SM;
|
||||
SM.Init(VV);
|
||||
SM.CopySmooth(B,1,p.QualitySmoothAbs);
|
||||
B=SM;
|
||||
if(p.VerboseLevel>1) B.SlicedPPM(shortname.c_str(),SFormat("%02isf",vstp++),p.SliceNum );
|
||||
}
|
||||
VV.Merge(B);
|
||||
if(p.VerboseLevel>0) VV.SlicedPPMQ(std::string("merge_").c_str(),shortname.c_str(),p.SliceNum );
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Process(vcg::CallBackPos *cb=0)
|
||||
{
|
||||
errorMessage = "";
|
||||
printf("bbox scanning...\n"); fflush(stdout);
|
||||
Matrix44f Id; Id.SetIdentity();
|
||||
MP.InitBBox();
|
||||
printf("Completed BBox Scanning \n");
|
||||
Box3f fullb = MP.fullBB();
|
||||
assert (!fullb.IsNull());
|
||||
assert (!fullb.IsEmpty());
|
||||
// Calcolo gridsize
|
||||
Point3f voxdim;
|
||||
fullb.Offset(fullb.Diag() * 0.1 );
|
||||
|
||||
int saveMask=0;
|
||||
saveMask|=tri::io::Mask::IOM_VERTQUALITY;
|
||||
if(p.MergeColor) saveMask |= tri::io::Mask::IOM_VERTCOLOR ;
|
||||
|
||||
voxdim = fullb.max - fullb.min;
|
||||
|
||||
// if kcell==0 the number of cells is computed starting from required voxel size;
|
||||
__int64 cells;
|
||||
if(p.NCell>0) cells = (__int64)(p.NCell)*(__int64)(1000);
|
||||
else cells = (__int64)(voxdim[0]/p.VoxSize) * (__int64)(voxdim[1]/p.VoxSize) *(__int64)(voxdim[2]/p.VoxSize) ;
|
||||
|
||||
{
|
||||
Volume<Voxelf> B; // local to this small block
|
||||
|
||||
Box3f fullbf; fullbf.Import(fullb);
|
||||
B.Init(cells,fullbf,p.IDiv,p.IPosS);
|
||||
B.Dump(stdout);
|
||||
if(p.WideSize>0) p.WideNum=p.WideSize/B.voxel.Norm();
|
||||
|
||||
// Now the volume has been determined; the quality threshold in absolute units can be computed
|
||||
if(p.QualitySmoothAbs==0)
|
||||
p.QualitySmoothAbs= p.QualitySmoothVox * B.voxel.Norm();
|
||||
}
|
||||
|
||||
|
||||
int TotAdd=0,TotMC=0,TotSav=0; // partial timings counter
|
||||
|
||||
for(p.IPos[0]=p.IPosS[0];p.IPos[0]<=p.IPosE[0];++p.IPos[0])
|
||||
for(p.IPos[1]=p.IPosS[1];p.IPos[1]<=p.IPosE[1];++p.IPos[1])
|
||||
for(p.IPos[2]=p.IPosS[2];p.IPos[2]<=p.IPosE[2];++p.IPos[2])
|
||||
if((p.IPos[2]+(p.IPos[1]*p.IDiv[2])+(p.IPos[0]*p.IDiv[2]*p.IDiv[1])) >=
|
||||
(p.IPosB[2]+(p.IPosB[1]*p.IDiv[2])+(p.IPosB[0]*p.IDiv[2]*p.IDiv[1]))) // skip until IPos >= IPosB
|
||||
{
|
||||
printf("----------- SubBlock %2i %2i %2i ----------\n",p.IPos[0],p.IPos[1],p.IPos[2]);
|
||||
//Volume<Voxelf> B;
|
||||
int t0=clock();
|
||||
|
||||
Box3f fullbf; fullbf.Import(fullb);
|
||||
|
||||
VV.Init(cells,fullbf,p.IDiv,p.IPos);
|
||||
printf("\n\n --------------- Allocated subcells. %i\n",VV.Allocated());
|
||||
|
||||
std::string filename=p.basename;
|
||||
if(p.IDiv!=Point3i(1,1,1))
|
||||
{
|
||||
std::string subvoltag;
|
||||
VV.GetSubVolumeTag(subvoltag);
|
||||
filename+=subvoltag;
|
||||
}
|
||||
/********** Grande loop di scansione di tutte le mesh *********/
|
||||
bool res=false;
|
||||
if(!cb) printf("Step 1: Converting meshes into volume\n");
|
||||
for(int i=0;i<MP.size();++i)
|
||||
{
|
||||
Box3f bbb= MP.bb(i);
|
||||
/**********************/
|
||||
if(cb) cb((i+1)/MP.size(),"Step 1: Converting meshes into volume");
|
||||
/**********************/
|
||||
// if bbox of mesh #i is part of the subblock, then process it
|
||||
if(bbb.Collide(VV.SubBoxSafe))
|
||||
{
|
||||
SMesh *sm;
|
||||
if(!MP.Find(i,sm) )
|
||||
{
|
||||
res = InitMesh(*sm,MP.MeshName(i).c_str(),MP.Tr(i));
|
||||
if(!res)
|
||||
{
|
||||
errorMessage = "Failed Init of mesh " +MP.MeshName(i);
|
||||
return false ;
|
||||
}
|
||||
}
|
||||
res |= AddMeshToVolumeM(*sm, MP.MeshName(i),MP.W(i));
|
||||
}
|
||||
}
|
||||
|
||||
//B.Normalize(1);
|
||||
printf("End Scanning\n");
|
||||
if(p.OffsetFlag)
|
||||
{
|
||||
VV.Offset(p.OffsetThr);
|
||||
if (p.VerboseLevel>0)
|
||||
{
|
||||
VV.SlicedPPM("finaloff","__",p.SliceNum);
|
||||
VV.SlicedPPMQ("finaloff","__",p.SliceNum);
|
||||
}
|
||||
}
|
||||
//if(p.VerboseLevel>1) VV.SlicedPPM(filename.c_str(),SFormat("_%02im",i),p.SliceNum );
|
||||
|
||||
for(int i=0;i<p.RefillNum;++i)
|
||||
{
|
||||
VV.Refill(3,6);
|
||||
if(p.VerboseLevel>1) VV.SlicedPPM(filename.c_str(),SFormat("_%02imsr",i),p.SliceNum );
|
||||
//if(VerboseLevel>1) VV.SlicedPPMQ(filename,SFormat("_%02ips",i++),SliceNum );
|
||||
}
|
||||
|
||||
for(int i=0;i<p.SmoothNum;++i)
|
||||
{
|
||||
Volume <Voxelf> SM;
|
||||
SM.Init(VV);
|
||||
printf("%2i/%2i: ",i,p.SmoothNum);
|
||||
SM.CopySmooth(VV,1,p.QualitySmoothAbs);
|
||||
VV=SM;
|
||||
VV.Refill(3,6);
|
||||
if(p.VerboseLevel>1) VV.SlicedPPM(filename.c_str(),SFormat("_%02ims",i),p.SliceNum );
|
||||
}
|
||||
|
||||
int t1=clock(); //--------
|
||||
TotAdd+=t1-t0;
|
||||
printf("Extracting surface...\r");
|
||||
if (p.VerboseLevel>0)
|
||||
{
|
||||
VV.SlicedPPM("final","__",p.SliceNum);
|
||||
VV.SlicedPPMQ("final","__",p.SliceNum);
|
||||
}
|
||||
MCMesh me;
|
||||
if(res)
|
||||
{
|
||||
typedef vcg::tri::TrivialWalker<MCMesh, Volume <Voxelf> > Walker;
|
||||
typedef vcg::tri::MarchingCubes<MCMesh, Walker> MarchingCubes;
|
||||
|
||||
Walker walker;
|
||||
MarchingCubes mc(me, walker);
|
||||
/**********************/
|
||||
if(cb) cb(50,"Step 2: Marching Cube...");
|
||||
else printf("Step 2: Marching Cube...\n");
|
||||
/**********************/
|
||||
walker.SetExtractionBox(VV.SubPartSafe);
|
||||
walker.BuildMesh(me,VV,mc,0);
|
||||
|
||||
typename MCMesh::VertexIterator vi;
|
||||
Box3f bbb; bbb.Import(VV.SubPart);
|
||||
for(vi=me.vert.begin();vi!=me.vert.end();++vi)
|
||||
{
|
||||
if(!bbb.IsIn((*vi).P()))
|
||||
vcg::tri::Allocator< MCMesh >::DeleteVertex(me,*vi);
|
||||
VV.DeInterize((*vi).P());
|
||||
}
|
||||
for (typename MCMesh::FaceIterator fi = me.face.begin(); fi != me.face.end(); ++fi)
|
||||
{
|
||||
if((*fi).V(0)->IsD() || (*fi).V(1)->IsD() || (*fi).V(2)->IsD() )
|
||||
vcg::tri::Allocator< MCMesh >::DeleteFace(me,*fi);
|
||||
else std::swap((*fi).V1(0), (*fi).V2(0));
|
||||
}
|
||||
|
||||
int t2=clock(); //--------
|
||||
TotMC+=t2-t1;
|
||||
if(me.vn >0 || me.fn >0)
|
||||
{
|
||||
p.OutNameVec.push_back(filename+std::string(".ply"));
|
||||
tri::io::ExporterPLY<MCMesh>::Save(me,p.OutNameVec.back().c_str(),saveMask);
|
||||
if(p.SimplificationFlag)
|
||||
{
|
||||
/**********************/
|
||||
if(cb) cb(50,"Step 3: Simplify mesh...");
|
||||
else printf("Step 3: Simplify mesh...\n");
|
||||
/**********************/
|
||||
p.OutNameSimpVec.push_back(filename+std::string(".d.ply"));
|
||||
me.face.EnableVFAdjacency();
|
||||
MCSimplify<MCMesh>(me, VV.voxel[0]/4.0);
|
||||
tri::Allocator<MCMesh>::CompactFaceVector(me);
|
||||
me.face.EnableFFAdjacency();
|
||||
tri::Clean<MCMesh>::RemoveTVertexByFlip(me,20,true);
|
||||
tri::Clean<MCMesh>::RemoveFaceFoldByFlip(me);
|
||||
tri::io::ExporterPLY<MCMesh>::Save(me,p.OutNameSimpVec.back().c_str(),saveMask);
|
||||
}
|
||||
}
|
||||
int t3=clock(); //--------
|
||||
TotSav+=t3-t2;
|
||||
|
||||
}
|
||||
|
||||
printf("Mesh Saved '%s': %8d vertices, %8d faces \n",(filename+std::string(".ply")).c_str(),me.vn,me.fn);
|
||||
printf("Adding Meshes %8i\n",TotAdd);
|
||||
printf("MC %8i\n",TotMC);
|
||||
printf("Saving %8i\n",TotSav);
|
||||
printf("Total %8i\n",TotAdd+TotMC+TotSav);
|
||||
}
|
||||
else
|
||||
{
|
||||
printf("----------- skipping SubBlock %2i %2i %2i ----------\n",p.IPos[0],p.IPos[1],p.IPos[2]);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
}; //end PlyMC class
|
||||
|
||||
|
||||
template < class MeshType, class VertexPair>
|
||||
class PlyMCTriEdgeCollapse: public MCTriEdgeCollapse< MeshType, VertexPair, PlyMCTriEdgeCollapse<MeshType,VertexPair> > {
|
||||
public:
|
||||
typedef MCTriEdgeCollapse< MeshType, VertexPair, PlyMCTriEdgeCollapse > MCTEC;
|
||||
inline PlyMCTriEdgeCollapse( const VertexPair &p, int i, BaseParameterClass *pp) :MCTEC(p,i,pp){}
|
||||
};
|
||||
|
||||
|
||||
|
||||
template< class MeshType>
|
||||
int MCSimplify( MeshType &m, float absoluteError, bool preserveBB, vcg::CallBackPos *cb)
|
||||
{
|
||||
|
||||
typedef PlyMCTriEdgeCollapse<MeshType,BasicVertexPair<typename MeshType::VertexType> > MyColl;
|
||||
typedef typename MeshType::FaceIterator FaceIterator;
|
||||
typedef typename MeshType::CoordType CoordType;
|
||||
|
||||
|
||||
tri::UpdateBounding<MeshType>::Box(m);
|
||||
tri::UpdateTopology<MeshType>::VertexFace(m);
|
||||
TriEdgeCollapseMCParameter pp;
|
||||
pp.bb.Import(m.bbox);
|
||||
pp.preserveBBox=preserveBB;
|
||||
vcg::LocalOptimization<MeshType> DeciSession(m,&pp);
|
||||
if(absoluteError==0)
|
||||
{
|
||||
// guess the mc side.
|
||||
// In a MC mesh the vertices are on the egdes of the cells. and the edges are (mostly) on face of the cells.
|
||||
// If you have 2 vert over the same face xy they share z
|
||||
|
||||
std::vector<float> ZSet;
|
||||
for(FaceIterator fi = m.face.begin();fi!=m.face.end();++fi)
|
||||
if(!(*fi).IsD())
|
||||
{
|
||||
CoordType v0=(*fi).V(0)->P();
|
||||
CoordType v1=(*fi).V(1)->P();
|
||||
CoordType v2=(*fi).V(2)->P();
|
||||
if(v0[2]==v1[2] && v0[1]!=v1[1] && v0[0]!=v1[0]) ZSet.push_back(v0[2]);
|
||||
if(v0[2]==v2[2] && v0[1]!=v2[1] && v0[0]!=v2[0]) ZSet.push_back(v0[2]);
|
||||
if(v1[2]==v2[2] && v1[1]!=v2[1] && v1[0]!=v2[0]) ZSet.push_back(v1[2]);
|
||||
if(ZSet.size()>100) break;
|
||||
}
|
||||
if (ZSet.size() == 0) return -1; //no straight edges found. exit with error
|
||||
std::sort(ZSet.begin(),ZSet.end());
|
||||
std::vector<float>::iterator lastV = std::unique(ZSet.begin(),ZSet.end());
|
||||
ZSet.resize(lastV-ZSet.begin());
|
||||
float Delta=0;
|
||||
for(size_t i = 0; i< ZSet.size()-1;++i)
|
||||
{
|
||||
Delta = std::max(ZSet[i+1]-ZSet[i],Delta);
|
||||
//qDebug("%f",Delta);
|
||||
}
|
||||
absoluteError= Delta/4.0f;
|
||||
}
|
||||
//qDebug("Simplifying at absoluteError=%f",absoluteError);
|
||||
|
||||
float TargetError = absoluteError;
|
||||
DeciSession.template Init< MyColl > ();
|
||||
|
||||
pp.areaThr=TargetError*TargetError;
|
||||
DeciSession.SetTimeBudget(1.0f);
|
||||
if(TargetError < std::numeric_limits<float>::max() ) DeciSession.SetTargetMetric(TargetError);
|
||||
while(DeciSession.DoOptimization() && DeciSession.currMetric < TargetError)
|
||||
{
|
||||
std::string buf = "Simplyfing " + std::to_string(m.fn) + " err " + std::to_string(DeciSession.currMetric) + " \r";
|
||||
if (cb)
|
||||
cb(int(100.0f*DeciSession.currMetric/TargetError),buf.c_str());
|
||||
}
|
||||
|
||||
return 1; //success
|
||||
}
|
||||
|
||||
|
||||
} // end namespace tri
|
||||
} // end namespace vcg
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,233 @@
|
||||
#ifndef SIMPLEMESHPROVIDER_H
|
||||
#define SIMPLEMESHPROVIDER_H
|
||||
#include <wrap/io_trimesh/alnParser.h>
|
||||
#include <list>
|
||||
#include <vector>
|
||||
#include <vcg/space/box3.h>
|
||||
#include <wrap/ply/plystuff.h>
|
||||
#include <wrap/io_trimesh/import.h>
|
||||
|
||||
/*
|
||||
* A mesh provider class has the simpler role of passing the set of meshes to be merged to the surface reconstrcution algorithm.
|
||||
* The only reason for this abstraction is that, plymc can work in a out-of-core way and the loading of the needed range maps can be optimized with a high level caching system.
|
||||
*/
|
||||
template<class TriMeshType>
|
||||
class MinimalMeshProvider
|
||||
{
|
||||
private:
|
||||
|
||||
std::vector< std::string > nameVec;
|
||||
std::vector< TriMeshType * > meshVec;
|
||||
std::vector<vcg::Matrix44f> trVec;
|
||||
std::vector<float> weightVec; // weight tot be applied to each mesh.
|
||||
vcg::Box3f fullBBox;
|
||||
|
||||
public:
|
||||
bool Find(const std::string &name, TriMeshType * &sm)
|
||||
{
|
||||
for(int i=0;i<nameVec.size();++i)
|
||||
if(nameVec[i]==name) {
|
||||
sm=meshVec[i];
|
||||
return true;
|
||||
}
|
||||
sm=0; return false;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
/**
|
||||
* Cache based Loading of meshes to avoid reloading an processing of the same mesh multiple times.
|
||||
*
|
||||
*/
|
||||
|
||||
namespace vcg {
|
||||
|
||||
template<class TriMeshType>
|
||||
class MeshCache
|
||||
{
|
||||
class Pair
|
||||
{
|
||||
public:
|
||||
Pair(){used=0;}
|
||||
TriMeshType *M;
|
||||
std::string Name;
|
||||
int used; // 'data' dell'ultimo accesso. si butta fuori quello lru
|
||||
};
|
||||
|
||||
std::list<Pair> MV;
|
||||
|
||||
public:
|
||||
void clear();
|
||||
|
||||
MeshCache() {MeshCacheSize=6;}
|
||||
~MeshCache() {
|
||||
typename std::list<Pair>::iterator mi;
|
||||
for(mi=MV.begin();mi!=MV.end();++mi)
|
||||
delete (*mi).M;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Find load a mesh form the cache if it is in or from the disk otherwise
|
||||
* @param name what mesh to find
|
||||
* @param sm the pointer loaded mesh
|
||||
* @return true if the mesh was already in cache
|
||||
*
|
||||
*/
|
||||
bool Find(const std::string &name, TriMeshType * &sm)
|
||||
{
|
||||
typename std::list<Pair>::iterator mi;
|
||||
typename std::list<Pair>::iterator oldest; // quello che e' piu' tempo che non viene acceduto.
|
||||
int last;
|
||||
|
||||
last = std::numeric_limits<int>::max();
|
||||
oldest = MV.begin();
|
||||
|
||||
for(mi=MV.begin();mi!=MV.end();++mi)
|
||||
{
|
||||
if((*mi).used<last)
|
||||
{
|
||||
last=(*mi).used;
|
||||
oldest=mi;
|
||||
}
|
||||
if((*mi).Name==name) {
|
||||
sm=(*mi).M;
|
||||
(*mi).used++;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// we have not found the requested mesh
|
||||
// either allocate a new mesh or give back a previous mesh.
|
||||
|
||||
if(MV.size()>MeshCacheSize) {
|
||||
sm=(*oldest).M;
|
||||
(*oldest).used=0;
|
||||
(*oldest).Name=name;
|
||||
} else {
|
||||
MV.push_back(Pair());
|
||||
MV.back().Name=name;
|
||||
MV.back().M=new TriMeshType();
|
||||
sm=MV.back().M;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
size_t MeshCacheSize;
|
||||
size_t size() const {return MV.size();}
|
||||
};
|
||||
|
||||
template<class TriMeshType>
|
||||
class SimpleMeshProvider
|
||||
{
|
||||
private:
|
||||
std::vector< std::string > meshnames;
|
||||
std::vector<vcg::Matrix44f> TrV;
|
||||
std::vector<float> WV; // weight tot be applied to each mesh.
|
||||
std::vector<vcg::Box3f> BBV; // bbox of the transformed meshes..
|
||||
vcg::Box3f fullBBox;
|
||||
MeshCache<TriMeshType> MC;
|
||||
|
||||
public:
|
||||
|
||||
int size() {return meshnames.size();}
|
||||
|
||||
int getCacheSize() {return MC.MeshCacheSize;}
|
||||
int setCacheSize(size_t newsize)
|
||||
{
|
||||
if(newsize == MC.MeshCacheSize)
|
||||
return MC.MeshCacheSize;
|
||||
if(newsize <= 0)
|
||||
return MC.MeshCacheSize;
|
||||
|
||||
MC.MeshCacheSize = newsize;
|
||||
return newsize;
|
||||
}
|
||||
|
||||
bool openALN (const char* alnName)
|
||||
{
|
||||
std::vector<RangeMap> rmaps;
|
||||
ALNParser::ParseALN(rmaps, alnName);
|
||||
|
||||
for(size_t i=0; i<rmaps.size(); i++)
|
||||
AddSingleMesh(rmaps[i].filename.c_str(), rmaps[i].transformation, rmaps[i].quality);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool AddSingleMesh(const char* meshName, const Matrix44f &tr= Matrix44f::Identity(), float meshWeight=1)
|
||||
{
|
||||
assert(WV.size()==meshnames.size() && TrV.size() == WV.size());
|
||||
TrV.push_back(tr);
|
||||
meshnames.push_back(meshName);
|
||||
WV.push_back(meshWeight);
|
||||
BBV.push_back(Box3f());
|
||||
return true;
|
||||
}
|
||||
|
||||
vcg::Box3f bb(int i) {return BBV[i];}
|
||||
vcg::Box3f fullBB(){ return fullBBox;}
|
||||
vcg::Matrix44f Tr(int i) const {return TrV[i];}
|
||||
std::string MeshName(int i) const {return meshnames[i];}
|
||||
float W(int i) const {return WV[i];}
|
||||
|
||||
void Clear()
|
||||
{
|
||||
meshnames.clear();
|
||||
TrV.clear();
|
||||
WV.clear();
|
||||
BBV.clear();
|
||||
fullBBox.SetNull();
|
||||
MC.clear();
|
||||
}
|
||||
|
||||
bool Find(int i, TriMeshType * &sm)
|
||||
{
|
||||
return MC.Find(meshnames[i],sm);
|
||||
}
|
||||
|
||||
bool InitBBox()
|
||||
{
|
||||
fullBBox.SetNull();
|
||||
for(int i=0;i<int(meshnames.size());++i)
|
||||
{
|
||||
bool ret;
|
||||
printf("bbox scanning %4i/%i [%16s] \r",i+1,(int)meshnames.size(), meshnames[i].c_str());
|
||||
if(tri::io::Importer<TriMeshType>::FileExtension(meshnames[i],"PLY") || tri::io::Importer<TriMeshType>::FileExtension(meshnames[i],"ply"))
|
||||
{
|
||||
ret=ply::ScanBBox(meshnames[i].c_str(),BBV[i],TrV[i],true,0);
|
||||
}
|
||||
else
|
||||
{
|
||||
printf("Trying to import a non-ply file %s\n",meshnames[i].c_str());fflush(stdout);
|
||||
TriMeshType m;
|
||||
ret = (tri::io::Importer<TriMeshType>::Open(m,meshnames[i].c_str()) == tri::io::Importer<TriMeshType>::E_NOERROR);
|
||||
tri::UpdatePosition<TriMeshType>::Matrix(m,TrV[i]);
|
||||
tri::UpdateBounding<TriMeshType>::Box(m);
|
||||
BBV[i].Import(m.bbox);
|
||||
}
|
||||
if( ! ret)
|
||||
{
|
||||
printf("\n\nwarning:\n file '%s' not found\n",meshnames[i].c_str());fflush(stdout);
|
||||
continue;
|
||||
}
|
||||
fullBBox.Add(BBV[i]);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
class SVertex;
|
||||
class SFace;
|
||||
class SUsedTypes: public vcg::UsedTypes < vcg::Use<SVertex>::AsVertexType,
|
||||
vcg::Use<SFace >::AsFaceType >{};
|
||||
|
||||
class SVertex : public Vertex< SUsedTypes, vertex::Coord3f, vertex::Normal3f,vertex::VFAdj, vertex::BitFlags, vertex::Color4b, vertex::Qualityf>{};
|
||||
class SFace : public Face< SUsedTypes, face::VertexRef, face::Normal3f,face::Qualityf, face::VFAdj, face::BitFlags> {};
|
||||
class SMesh : public tri::TriMesh< std::vector< SVertex>, std::vector< SFace > > {};
|
||||
|
||||
}
|
||||
|
||||
#endif // SIMPLEMESHPROVIDER_H
|
||||
@@ -0,0 +1,174 @@
|
||||
/****************************************************************************
|
||||
* VCGLib o o *
|
||||
* Visual and Computer Graphics Library o o *
|
||||
* _ O _ *
|
||||
* Copyright(C) 2004-2016 \/)\/ *
|
||||
* 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 __SVOXEL_H__
|
||||
#define __SVOXEL_H__
|
||||
template<class SCALAR_TYPE=float>
|
||||
class SVoxel
|
||||
{
|
||||
|
||||
private:
|
||||
short v; // distanza dalla superficie espressa in centesimi di voxel;
|
||||
short q; // come distanza dal bordo espressa in centesimi di voxel; // nota che questo implica che non si potrebbe rasterizzare una singola mesh in un volume di lato > 3000^3
|
||||
char n[3];
|
||||
unsigned char cnt;
|
||||
// se != 0 b deve essere true;
|
||||
// b e'tenuto implicitamente usando cnt;
|
||||
// se cnt == 0 || cnt>0 -> b=false
|
||||
// se cnt == 255 -> b=true
|
||||
|
||||
// b==false cnt==0 totalmente non inzializzato (Zero)
|
||||
// b==false cnt >0 da normalizzare
|
||||
// b==true cnt==0 gia' normalizzato
|
||||
// b==true cnt >0 Errore!!!
|
||||
|
||||
|
||||
|
||||
public:
|
||||
typedef SCALAR_TYPE scalar;
|
||||
SVoxel(SCALAR_TYPE vv, bool /*bb*/, Point3<scalar> &nn, scalar qq) {SetV(vv);SetN(nn);SetQ(qq);}
|
||||
SVoxel(SCALAR_TYPE vv, const Point3<scalar> &nn, scalar qq) {SetV(vv);SetN(nn);SetQ(qq);cnt=255;}
|
||||
bool B() const {return cnt==255;} // puo' essere a true solo se cnt == 0; (il che significa che e' stato gia' normalizzato
|
||||
|
||||
void SetB(bool val) {
|
||||
assert( val == (cnt==255 || cnt==0) );
|
||||
if(val) cnt=255;
|
||||
else if(cnt==255) cnt=0;
|
||||
}
|
||||
|
||||
int Cnt() {
|
||||
if(cnt==255) return 0;
|
||||
else return int(cnt);
|
||||
}
|
||||
void SetCnt(int val) { cnt=(unsigned char)val;}
|
||||
|
||||
|
||||
Point3<scalar> N() const {
|
||||
return Point3<scalar>(scalar(n[0])/127.0f,scalar(n[1])/127.0f,scalar(n[2])/127.0f);
|
||||
}
|
||||
scalar N(const int i) const
|
||||
{
|
||||
return scalar(n[i])/127.0f;
|
||||
}
|
||||
|
||||
void SetN(const Point3<scalar> &nn)
|
||||
{
|
||||
n[0]=char( nn[0]*127.0f );
|
||||
n[1]=char( nn[1]*127.0f );
|
||||
n[2]=char( nn[2]*127.0f );
|
||||
}
|
||||
scalar V() const
|
||||
{
|
||||
return scalar(v)/100.0f;
|
||||
}
|
||||
|
||||
inline void Blend( SVoxel const & vx, scalar w)
|
||||
{
|
||||
float w1=1.0-w;
|
||||
SetV(V()*w1+vx.V()*w);
|
||||
SetQ(Q()*w1+vx.Q()*w);
|
||||
SetN(N()*w1+vx.N()*w);
|
||||
//return *this;
|
||||
}
|
||||
|
||||
void SetV(const float &vv)
|
||||
{
|
||||
v= short(vv*100.0f);
|
||||
if(v==0) v=1;
|
||||
}
|
||||
|
||||
scalar Q() const
|
||||
{
|
||||
return scalar(q)/20.0f;
|
||||
}
|
||||
|
||||
void SetQ(const float &qq)
|
||||
{
|
||||
int qi = qq * 20.0f;
|
||||
if (qi>32767) qi =32767;
|
||||
q = qi;
|
||||
}
|
||||
|
||||
void Merge(const SVoxel &VOX)
|
||||
{
|
||||
v=(v*Q()+VOX.Q()*VOX.v)/(Q()+VOX.Q());
|
||||
SetQ(Q()+VOX.Q());
|
||||
}
|
||||
void Set(const SVoxel &VOX)
|
||||
{
|
||||
v=VOX.v;
|
||||
n[0]=VOX.n[0];
|
||||
n[1]=VOX.n[1];
|
||||
n[2]=VOX.n[2];
|
||||
q=VOX.q;
|
||||
|
||||
}
|
||||
|
||||
inline SVoxel & operator += ( SVoxel const & vx)
|
||||
{
|
||||
if(cnt==0)
|
||||
{
|
||||
v=vx.v;
|
||||
q=vx.q;
|
||||
n[0]=vx.n[0];
|
||||
n[1]=vx.n[1];
|
||||
n[2]=vx.n[2];
|
||||
cnt=1;
|
||||
}
|
||||
else
|
||||
{
|
||||
const int cnt1=cnt+1;
|
||||
v+=vx.v;
|
||||
q = (q*cnt+vx.q)/(cnt1);
|
||||
n[0]=(vx.n[0]*int(cnt) +vx.n[0])/(cnt1) ;
|
||||
n[1]=(vx.n[1]*int(cnt) +vx.n[1])/(cnt1) ;
|
||||
n[2]=(vx.n[2]*int(cnt) +vx.n[2])/(cnt1) ;
|
||||
if(cnt==255) cnt=1;
|
||||
else ++cnt;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline bool Normalize(int thr)
|
||||
{
|
||||
assert(cnt>0);
|
||||
if(cnt<thr)
|
||||
{
|
||||
(*this) = Zero();
|
||||
return false;
|
||||
}
|
||||
v= v/cnt; // gli altri membri sono gia' normalizzati
|
||||
cnt=255;
|
||||
// b=true; inutile!
|
||||
return true;
|
||||
}
|
||||
|
||||
bool IsZero() const { return v==0; }
|
||||
|
||||
static const SVoxel &Zero() {
|
||||
static SVoxel tt(0,false,Point3f(0,0,0),0);
|
||||
return tt;
|
||||
}
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,132 @@
|
||||
/****************************************************************************
|
||||
* VCGLib o o *
|
||||
* Visual and Computer Graphics Library o o *
|
||||
* _ O _ *
|
||||
* Copyright(C) 2004-2016 \/)\/ *
|
||||
* 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 __TRI_EDGE_COLLAPSE_MC__
|
||||
#define __TRI_EDGE_COLLAPSE_MC__
|
||||
namespace vcg{
|
||||
namespace tri{
|
||||
|
||||
class TriEdgeCollapseMCParameter : public BaseParameterClass
|
||||
{
|
||||
public:
|
||||
Box3f bb;
|
||||
bool preserveBBox;
|
||||
float areaThr;
|
||||
void SetDefaultParams()
|
||||
{
|
||||
bb.SetNull();
|
||||
preserveBBox=true;
|
||||
areaThr=0;
|
||||
}
|
||||
|
||||
TriEdgeCollapseMCParameter() {SetDefaultParams();}
|
||||
};
|
||||
|
||||
|
||||
|
||||
template<class MCTriMesh, class VertexPair, class MYTYPE >
|
||||
// Specialized Simplification classes for removing all small pieces on meshes.
|
||||
class MCTriEdgeCollapse: public tri::TriEdgeCollapse< MCTriMesh, VertexPair, MYTYPE> {
|
||||
|
||||
public:
|
||||
typedef typename MCTriMesh::VertexPointer VertexPointer;
|
||||
typedef typename MCTriMesh::FaceType FaceType;
|
||||
typedef typename MCTriMesh::VertexType::CoordType CoordType;
|
||||
typedef typename MCTriMesh::VertexType::ScalarType ScalarType;
|
||||
|
||||
inline MCTriEdgeCollapse( const VertexPair &p, int mark, BaseParameterClass *pp)
|
||||
{
|
||||
this->localMark = mark;
|
||||
this->pos=p;
|
||||
this->_priority = ComputePriority(pp);
|
||||
}
|
||||
|
||||
|
||||
// The priority is simply the edge lenght,
|
||||
// but we consider collapsing edges that lies on one plane of the MC grid.
|
||||
virtual inline ScalarType ComputePriority(BaseParameterClass *_pp)
|
||||
{
|
||||
TriEdgeCollapseMCParameter *pp=(TriEdgeCollapseMCParameter *)_pp;
|
||||
const CoordType & p0 = this->pos.V(0)->cP();
|
||||
const CoordType & p1 = this->pos.V(1)->cP();
|
||||
|
||||
int diffCnt=0;
|
||||
if( (p0[0] != p1[0]) ) diffCnt++;
|
||||
if( (p0[1] != p1[1]) ) diffCnt++;
|
||||
if( (p0[2] != p1[2]) ) diffCnt++;
|
||||
|
||||
// non MC plane collapse return highest cost
|
||||
// if(diffCnt>2) return this->_priority=std::numeric_limits<float>::max() ;
|
||||
if(pp->preserveBBox)
|
||||
{
|
||||
const Box3f &bb=pp->bb;
|
||||
// collapse on the bbox border. Avoid it.
|
||||
if(p0[0]==bb.min[0] || p0[0]==bb.max[0]) return this->_priority=std::numeric_limits<float>::max() ;
|
||||
if(p0[1]==bb.min[1] || p0[1]==bb.max[1]) return this->_priority=std::numeric_limits<float>::max() ;
|
||||
if(p0[2]==bb.min[2] || p0[2]==bb.max[2]) return this->_priority=std::numeric_limits<float>::max() ;
|
||||
if(p1[0]==bb.min[0] || p1[0]==bb.max[0]) return this->_priority=std::numeric_limits<float>::max() ;
|
||||
if(p1[1]==bb.min[1] || p1[1]==bb.max[1]) return this->_priority=std::numeric_limits<float>::max() ;
|
||||
if(p1[2]==bb.min[2] || p1[2]==bb.max[2]) return this->_priority=std::numeric_limits<float>::max() ;
|
||||
}
|
||||
return this->_priority=Distance(p0,p1);
|
||||
}
|
||||
|
||||
inline void Execute(MCTriMesh &m,BaseParameterClass *)
|
||||
{
|
||||
const CoordType & p0 = this->pos.V(0)->cP();
|
||||
const CoordType & p1 = this->pos.V(1)->cP();
|
||||
std::vector<VertexPointer> starVec0;
|
||||
std::vector<VertexPointer> starVec1;
|
||||
// int count0=0,count1=0;
|
||||
|
||||
vcg::face::VVStarVF<FaceType>(this->pos.V(0),starVec0);
|
||||
// for(size_t i=0;i<starVec.size();++i)
|
||||
// {
|
||||
// if( (p0[0]==starVec[i]->cP()[0]) ) count0++;
|
||||
// if( (p0[1]==starVec[i]->cP()[1]) ) count0++;
|
||||
// if( (p0[2]==starVec[i]->cP()[2]) ) count0++;
|
||||
// }
|
||||
vcg::face::VVStarVF<FaceType>(this->pos.V(1),starVec1);
|
||||
// for(size_t i=0;i<starVec.size();++i)
|
||||
// {
|
||||
// if( (p1[0]==starVec[i]->cP()[0]) ) count1++;
|
||||
// if( (p1[1]==starVec[i]->cP()[1]) ) count1++;
|
||||
// if( (p1[2]==starVec[i]->cP()[2]) ) count1++;
|
||||
// }
|
||||
CoordType MidPoint=(p0+p1)/2.0;
|
||||
|
||||
if(starVec0.size()>starVec1.size()) MidPoint=p0;
|
||||
if(starVec0.size()<starVec1.size()) MidPoint=p1;
|
||||
|
||||
// assert( (p0[0]==p1[0]) ||
|
||||
// (p0[1]==p1[1]) ||
|
||||
// (p0[2]==p1[2]) );
|
||||
// DoCollapse(m, this->pos, MidPoint);
|
||||
vcg::tri::EdgeCollapser<MCTriMesh,VertexPair>::Do(m, this->pos, MidPoint);
|
||||
}
|
||||
|
||||
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,210 @@
|
||||
/****************************************************************************
|
||||
* VCGLib o o *
|
||||
* Visual and Computer Graphics Library o o *
|
||||
* _ O _ *
|
||||
* Copyright(C) 2004-2016 \/)\/ *
|
||||
* 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 __VOXEL_H__
|
||||
#define __VOXEL_H__
|
||||
|
||||
namespace vcg {
|
||||
|
||||
// Stato di un voxel
|
||||
|
||||
// B() dice se ci sono dati in uno stadio usabile.
|
||||
// Cnt() dice quanti ce ne sono stati sommati (per la normalizzazione)
|
||||
|
||||
// b==false cnt==0 totalmente non inzializzato (Zero)
|
||||
// b==false cnt >0 da normalizzare
|
||||
// b==true cnt==0 gia' normalizzato
|
||||
// b==true cnt >0 Errore!!!
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
|
||||
template<class SCALAR_TYPE=float>
|
||||
class Voxel
|
||||
{
|
||||
public:
|
||||
typedef SCALAR_TYPE scalar;
|
||||
|
||||
Voxel(SCALAR_TYPE vv, bool bb, Point3<scalar> nn, short _cnt) {v=vv;b=bb;n=nn;cnt=_cnt;}
|
||||
Voxel(SCALAR_TYPE vv, Point3<scalar> nn, scalar qq) {v=vv;b=true;n=nn;cnt=0;q=qq;}
|
||||
|
||||
const Point3<scalar> &N() const { return n; }
|
||||
|
||||
void SetN(const Point3<scalar> &nn) { n=nn; }
|
||||
const scalar &V() const { return v; }
|
||||
|
||||
void SetV(const scalar &vv) { v=vv; }
|
||||
|
||||
const scalar &Q() const { return q; }
|
||||
|
||||
void SetQ(const scalar &qq) { q=qq; }
|
||||
|
||||
|
||||
bool B() const {return b;};
|
||||
void SetB(bool val) {b=val;}
|
||||
int Cnt() const {return cnt;}
|
||||
void SetCnt(int val) {cnt=val;}
|
||||
inline void Blend( Voxel const & vx, scalar w)
|
||||
{
|
||||
float w1=1.0-w;
|
||||
v=v*w1+vx.v*w;
|
||||
q=q*w1+vx.q*w;
|
||||
n=n*w1+vx.n*w;
|
||||
//return *this;
|
||||
}
|
||||
|
||||
inline Voxel & operator += ( Voxel const & vx)
|
||||
{
|
||||
assert(!b);
|
||||
if(cnt==0)
|
||||
{
|
||||
v=vx.v;
|
||||
q=vx.q;
|
||||
n=vx.n;
|
||||
cnt=1;
|
||||
b=false;
|
||||
}
|
||||
else
|
||||
{
|
||||
v+=vx.v;
|
||||
q+=vx.q;
|
||||
n+=vx.n;
|
||||
++cnt;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline bool Normalize(int thr)
|
||||
{
|
||||
assert(cnt>0);
|
||||
assert(!B());
|
||||
if(cnt<thr)
|
||||
{
|
||||
(*this) = Zero();
|
||||
return false;
|
||||
}
|
||||
v/=cnt;
|
||||
q/=cnt;
|
||||
n/=cnt;
|
||||
cnt=0;
|
||||
b=true;
|
||||
return true;
|
||||
}
|
||||
|
||||
static const Voxel &Zero() {
|
||||
static Voxel tt(0,false,Point3f(0,0,0),0);
|
||||
return tt;
|
||||
}
|
||||
void Merge(const Voxel &VOX)
|
||||
{
|
||||
v=(v*q+VOX.Q()*VOX.v)/(q+VOX.Q());
|
||||
n=(n*q+VOX.n*VOX.Q())/(q+VOX.Q());
|
||||
q=q+VOX.Q();
|
||||
}
|
||||
|
||||
void Set(const Voxel &VOX)
|
||||
{
|
||||
v=VOX.v;
|
||||
n=VOX.n;
|
||||
q=VOX.q;
|
||||
}
|
||||
|
||||
protected:
|
||||
bool b;
|
||||
short cnt;
|
||||
scalar v;
|
||||
scalar q;
|
||||
Point3<SCALAR_TYPE> n;
|
||||
|
||||
};
|
||||
|
||||
|
||||
class Voxelfc :public Voxel<float>
|
||||
{
|
||||
public:
|
||||
|
||||
Voxelfc(float vv, bool bb, Point3f nn, short _cnt) :Voxel<float>(vv,bb,nn,_cnt){}
|
||||
Voxelfc(float vv, Point3f nn, scalar qq) :Voxel<float>(vv,nn,qq) {}
|
||||
Voxelfc(float vv, Point3f nn, scalar qq,Color4b cc) :Voxel<float>(vv,nn,qq)
|
||||
{
|
||||
c[0]=cc[0];
|
||||
c[1]=cc[1];
|
||||
c[2]=cc[2];
|
||||
}
|
||||
|
||||
inline bool Normalize(int thr)
|
||||
{
|
||||
if(cnt>=thr) c/=cnt;
|
||||
return Voxel<float>::Normalize(thr);
|
||||
}
|
||||
|
||||
static const Voxelfc &Zero() {
|
||||
static Voxelfc tt(0,false,Point3f(0,0,0),0);
|
||||
return tt;
|
||||
}
|
||||
|
||||
void Merge(const Voxelfc &VOX)
|
||||
{
|
||||
c=( c*q + VOX.C()*VOX.Q() )/(q+VOX.Q());
|
||||
Voxel<float>::Merge(VOX);
|
||||
}
|
||||
|
||||
void Set(const Voxelfc &VOX)
|
||||
{
|
||||
Voxel<float>::Set(VOX);
|
||||
c=VOX.c;
|
||||
}
|
||||
|
||||
const float &C(const int i) const { return c[i]; }
|
||||
const Point3f &C() const { return c; }
|
||||
void SetC(const Point3f &cc) { c=cc; }
|
||||
Color4b C4b() const
|
||||
{
|
||||
static Color4b cc;
|
||||
cc=Color4b(c[0],c[1],c[2],255);
|
||||
return cc;
|
||||
}
|
||||
inline void Blend( Voxelfc const & vx, scalar w)
|
||||
{
|
||||
float w1=1.0-w;
|
||||
v=v*w1+vx.v*w;
|
||||
q=q*w1+vx.q*w;
|
||||
n=n*w1+vx.n*w;
|
||||
c=c*w1+vx.c*w;
|
||||
//return *this;
|
||||
}
|
||||
|
||||
inline Voxelfc & operator += ( Voxelfc const & vx)
|
||||
{
|
||||
Voxel<float>::operator +=(vx);
|
||||
if(cnt==1) c =vx.c;
|
||||
else c+=vx.c;
|
||||
return *this;
|
||||
}
|
||||
|
||||
private:
|
||||
Point3f c;
|
||||
};
|
||||
}
|
||||
#endif
|
||||
Reference in new issue
Block a user