add vcglib
This commit is contained in:
1 parent
6f6c0c8eb7
commit
af8100f851
1537 files changed
+634197
No files matched your search
@@ -0,0 +1,17 @@
|
||||
cmake_minimum_required(VERSION 3.13)
|
||||
project (tridecimator)
|
||||
|
||||
if (VCG_HEADER_ONLY)
|
||||
set(SOURCES
|
||||
tridecimator.cpp
|
||||
${VCG_INCLUDE_DIRS}/wrap/ply/plylib.cpp)
|
||||
endif()
|
||||
|
||||
add_executable(tridecimator
|
||||
${SOURCES})
|
||||
|
||||
target_link_libraries(
|
||||
tridecimator
|
||||
PUBLIC
|
||||
vcglib
|
||||
)
|
||||
@@ -0,0 +1,75 @@
|
||||
|
||||
VCGLib http://www.vcglib.net
|
||||
Copyright(C) 2005-2006
|
||||
Visual Computing Lab http://vcg.isti.cnr.it
|
||||
ISTI - Italian National Research Council
|
||||
|
||||
|
||||
|
||||
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.
|
||||
|
||||
--- Synopsis ---
|
||||
|
||||
`tridecimator fileIn fileOut face_num [opt]`
|
||||
|
||||
Tridecimator is a commandline mesh simplifier based on a variant of the quadric error edge collapse strategy.
|
||||
It supports `PLY, OFF, OBJ` format for input and output and require a target number of faces.
|
||||
The following options are supported:
|
||||
|
||||
-e# QuadricError threshold (range [0,inf) default inf)
|
||||
-b# Boundary Weight (default .5)
|
||||
-p# Quality quadric Weight (default .5)
|
||||
-q# Quality threshold (range [0.0, 0.866], default .3 )
|
||||
-n# Normal threshold (degree range [0,180] default 90)
|
||||
-w# Quality weight factor (10)
|
||||
-E# Minimal admitted quadric value (default 1e-15, must be >0)
|
||||
-Q[y|n] Use or not Face Quality Threshold (default yes)
|
||||
-H[y|n] Use or not HardQualityCheck (default no)
|
||||
-N[y|n] Use or not Face Normal Threshold (default no)
|
||||
-P[y|n] Add or not QualityQuadric (default no)
|
||||
-A[y|n] Use or not Area Checking (default no)
|
||||
-O[y|n] Use or not vertex optimal placement (default yes)
|
||||
-S[y|n] Use or not Scale Independent quadric measure(default yes)
|
||||
-B[y|n] Preserve or not mesh boundary (default no)
|
||||
-T[y|n] Preserve or not Topology (default no)
|
||||
-W[y|n] Use or not per vertex Quality to weight the quadric error (default no)
|
||||
-C Before simplification, remove duplicate & unreferenced vertices
|
||||
|
||||
|
||||
This simplification tool employ a quadric error based edge collapse iterative approach.
|
||||
Each possible collapse is scored taking into account
|
||||
- its quadric error
|
||||
- its quadric boundary error
|
||||
- the normal variation caused by the collapse itself
|
||||
- the future quality (aspect ratio) of the triangles involved in the collapse
|
||||
|
||||
The simplification can ends when the desired number of triangles has been reached.
|
||||
|
||||
The 'Safe Heap Update' change the set of edges re-inserted in the heap
|
||||
after a collapse resulting in a vertex v; this option put back in the
|
||||
heap not only incident in the v, but all the edges of the triangles incident
|
||||
in v. It slows down a lot.
|
||||
|
||||
The 'Scale Independent quadric' is useful when you want simplify
|
||||
two different meshes at the same 'error'; otherwise the quadric
|
||||
error used in the heap is somewhat normalized and independent
|
||||
of the size of the mesh.
|
||||
|
||||
The Normal threshold avoid to make large changes in variation of the normal
|
||||
of the surfaces, but on the other hand it prevent the removal of small 'folded'
|
||||
triangles that can be already present. Therefore in most cases is not very useful.
|
||||
|
||||
Cleaning the mesh is mandatory for some input format like STL that always
|
||||
duplicates all the vertices.
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,197 @@
|
||||
// stuff to define the mesh
|
||||
#include <vcg/complex/complex.h>
|
||||
|
||||
// io
|
||||
#include <wrap/io_trimesh/import.h>
|
||||
#include <wrap/io_trimesh/export_ply.h>
|
||||
|
||||
// local optimization
|
||||
#include <vcg/complex/algorithms/local_optimization.h>
|
||||
#include <vcg/complex/algorithms/local_optimization/tri_edge_collapse_quadric.h>
|
||||
|
||||
using namespace vcg;
|
||||
using namespace tri;
|
||||
|
||||
/**********************************************************
|
||||
Mesh Classes for Quadric Edge collapse based simplification
|
||||
|
||||
For edge collpases we need verteses with:
|
||||
- V->F adjacency
|
||||
- per vertex incremental mark
|
||||
- per vertex Normal
|
||||
|
||||
|
||||
Moreover for using a quadric based collapse the vertex class
|
||||
must have also a Quadric member Q();
|
||||
Otherwise the user have to provide an helper function object
|
||||
to recover the quadric.
|
||||
|
||||
******************************************************/
|
||||
// The class prototypes.
|
||||
class MyVertex;
|
||||
class MyEdge;
|
||||
class MyFace;
|
||||
|
||||
struct MyUsedTypes: public UsedTypes<Use<MyVertex>::AsVertexType,Use<MyEdge>::AsEdgeType,Use<MyFace>::AsFaceType>{};
|
||||
|
||||
class MyVertex : public Vertex< MyUsedTypes,
|
||||
vertex::VFAdj,
|
||||
vertex::Coord3f,
|
||||
vertex::Mark,
|
||||
vertex::Qualityf,
|
||||
vertex::BitFlags >{
|
||||
public:
|
||||
vcg::math::Quadric<double> &Qd() {return q;}
|
||||
private:
|
||||
math::Quadric<double> q;
|
||||
};
|
||||
|
||||
class MyEdge : public Edge< MyUsedTypes> {};
|
||||
|
||||
typedef BasicVertexPair<MyVertex> VertexPair;
|
||||
|
||||
class MyFace : public Face< MyUsedTypes,
|
||||
face::VFAdj,
|
||||
face::VertexRef,
|
||||
face::BitFlags > {};
|
||||
|
||||
// the main mesh class
|
||||
class MyMesh : public vcg::tri::TriMesh<std::vector<MyVertex>, std::vector<MyFace> > {};
|
||||
|
||||
|
||||
class MyTriEdgeCollapse: public vcg::tri::TriEdgeCollapseQuadric< MyMesh, VertexPair, MyTriEdgeCollapse, QInfoStandard<MyVertex> > {
|
||||
public:
|
||||
typedef vcg::tri::TriEdgeCollapseQuadric< MyMesh, VertexPair, MyTriEdgeCollapse, QInfoStandard<MyVertex> > TECQ;
|
||||
typedef MyMesh::VertexType::EdgeType EdgeType;
|
||||
inline MyTriEdgeCollapse( const VertexPair &p, int i, BaseParameterClass *pp) :TECQ(p,i,pp){}
|
||||
};
|
||||
|
||||
void Usage()
|
||||
{
|
||||
printf(
|
||||
"---------------------------------\n"
|
||||
" TriDecimator 1.0 \n"
|
||||
" http://vcg.isti.cnr.it\n"
|
||||
" release date: " __DATE__
|
||||
"\n---------------------------------\n\n"
|
||||
"Copyright 2003-2016 Visual Computing Lab I.S.T.I. C.N.R.\n"
|
||||
"\nUsage: "\
|
||||
"tridecimator fileIn fileOut face_num [opt]\n"\
|
||||
"Where opt can be:\n"\
|
||||
" -e# QuadricError threshold (range [0,inf) default inf)\n"
|
||||
" -b# Boundary Weight (default .5)\n"
|
||||
" -p# Quality quadric Weight (default .5)\n"
|
||||
" -q# Quality threshold (range [0.0, 0.866], default .3 )\n"
|
||||
" -n# Normal threshold (degree range [0,180] default 90)\n"
|
||||
" -w# Quality weight factor (10)\n"
|
||||
" -E# Minimal admitted quadric value (default 1e-15, must be >0)\n"
|
||||
" -Q[y|n] Use or not Face Quality Threshold (default yes)\n"
|
||||
" -H[y|n] Use or not HardQualityCheck (default no)\n"
|
||||
" -N[y|n] Use or not Face Normal Threshold (default no)\n"
|
||||
" -P[y|n] Add or not QualityQuadric (default no)\n"
|
||||
" -A[y|n] Use or not Area Checking (default no)\n"
|
||||
" -O[y|n] Use or not vertex optimal placement (default yes)\n"
|
||||
" -S[y|n] Use or not Scale Independent quadric measure(default yes) \n"
|
||||
" -B[y|n] Preserve or not mesh boundary (default no)\n"
|
||||
" -T[y|n] Preserve or not Topology (default no)\n"
|
||||
" -W[y|n] Use or not per vertex Quality to weight the quadric error (default no)\n"
|
||||
" -C Before simplification, remove duplicate & unreferenced vertices\n"
|
||||
);
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
int main(int argc ,char**argv)
|
||||
{
|
||||
if(argc<4) Usage();
|
||||
|
||||
MyMesh mesh;
|
||||
|
||||
int FinalSize=atoi(argv[3]);
|
||||
int err=vcg::tri::io::Importer<MyMesh>::Open(mesh,argv[1]);
|
||||
if(err)
|
||||
{
|
||||
printf("Unable to open mesh %s : '%s'\n",argv[1],vcg::tri::io::Importer<MyMesh>::ErrorMsg(err));
|
||||
exit(-1);
|
||||
}
|
||||
printf("mesh loaded %d %d \n",mesh.vn,mesh.fn);
|
||||
|
||||
TriEdgeCollapseQuadricParameter qparams;
|
||||
qparams.QualityThr =.3;
|
||||
double TargetError=std::numeric_limits<double >::max();
|
||||
bool CleaningFlag =false;
|
||||
// parse command line.
|
||||
for(int i=4; i < argc;)
|
||||
{
|
||||
if(argv[i][0]=='-')
|
||||
switch(argv[i][1])
|
||||
{
|
||||
case 'Q' : if(argv[i][2]=='y') { qparams.QualityCheck = true; printf("Using Quality Checking\n"); }
|
||||
else { qparams.QualityCheck = false; printf("NOT Using Quality Checking\n"); } break;
|
||||
case 'H' : if(argv[i][2]=='y') { qparams.HardQualityCheck = true; printf("Using HardQualityCheck Checking\n"); }
|
||||
else { qparams.HardQualityCheck = false; printf("NOT Using HardQualityCheck Checking\n"); } break;
|
||||
case 'N' : if(argv[i][2]=='y') { qparams.NormalCheck = true; printf("Using Normal Deviation Checking\n"); }
|
||||
else { qparams.NormalCheck = false; printf("NOT Using Normal Deviation Checking\n"); } break;
|
||||
case 'A' : if(argv[i][2]=='y') { qparams.AreaCheck = true; printf("Using Area Checking\n"); }
|
||||
else { qparams.AreaCheck = false; printf("NOT Using Area Checking\n"); } break;
|
||||
case 'O' : if(argv[i][2]=='y') { qparams.OptimalPlacement = true; printf("Using OptimalPlacement\n"); }
|
||||
else { qparams.OptimalPlacement = false; printf("NOT Using OptimalPlacement\n");} break;
|
||||
case 'S' : if(argv[i][2]=='y') { qparams.ScaleIndependent = true; printf("Using ScaleIndependent\n"); }
|
||||
else { qparams.ScaleIndependent = false; printf("NOT Using ScaleIndependent\n"); } break;
|
||||
case 'B' : if(argv[i][2]=='y') { qparams.PreserveBoundary = true; printf("Preserving Boundary\n"); }
|
||||
else { qparams.PreserveBoundary = false; printf("NOT Preserving Boundary\n"); } break;
|
||||
case 'T' : if(argv[i][2]=='y') { qparams.PreserveTopology = true; printf("Preserving Topology\n"); }
|
||||
else { qparams.PreserveTopology = false; printf("NOT Preserving Topology\n"); } break;
|
||||
case 'P' : if(argv[i][2]=='y') { qparams.QualityQuadric = true; printf("Adding Quality Quadrics\n"); }
|
||||
else { qparams.QualityQuadric = false; printf("NOT Adding Quality Quadrics\n"); } break;
|
||||
case 'W' : if(argv[i][2]=='y') { qparams.QualityWeight = true; printf("Using per vertex Quality as Weight\n"); }
|
||||
else { qparams.QualityWeight = false; printf("NOT Using per vertex Quality as Weight\n"); } break;
|
||||
case 'p' : qparams.QualityQuadricWeight = atof(argv[i]+2); printf("Setting QualityQuadricWeight factor to %f\n",atof(argv[i]+2)); break;
|
||||
case 'w' : qparams.QualityWeightFactor = atof(argv[i]+2); printf("Setting Quality Weight factor to %f\n",atof(argv[i]+2)); break;
|
||||
case 'q' : qparams.QualityThr = atof(argv[i]+2); printf("Setting Quality Thr to %f\n",atof(argv[i]+2)); break;
|
||||
case 'h' : qparams.HardQualityThr = atof(argv[i]+2); printf("Setting HardQuality Thr to %f\n",atof(argv[i]+2)); break;
|
||||
case 'n' : qparams.NormalThrRad = math::ToRad(atof(argv[i]+2)); printf("Setting Normal Thr to %f deg\n",atof(argv[i]+2)); break;
|
||||
case 'b' : qparams.BoundaryQuadricWeight = atof(argv[i]+2); printf("Setting Boundary Weight to %f\n",atof(argv[i]+2)); break;
|
||||
case 'E' : qparams.QuadricEpsilon = atof(argv[i]+2); printf("Setting QuadricEpsilon to %f\n",atof(argv[i]+2)); break;
|
||||
case 'e' : TargetError = atof(argv[i]+2); printf("Setting TargetError to %g\n",atof(argv[i]+2)); break;
|
||||
case 'C' : CleaningFlag=true; printf("Cleaning mesh before simplification\n"); break;
|
||||
|
||||
default : printf("Unknown option '%s'\n", argv[i]);
|
||||
exit(0);
|
||||
}
|
||||
i++;
|
||||
}
|
||||
|
||||
if(CleaningFlag){
|
||||
int dup = tri::Clean<MyMesh>::RemoveDuplicateVertex(mesh);
|
||||
int unref = tri::Clean<MyMesh>::RemoveUnreferencedVertex(mesh);
|
||||
printf("Removed %i duplicate and %i unreferenced vertices from mesh \n",dup,unref);
|
||||
}
|
||||
|
||||
|
||||
printf("reducing it to %i\n",FinalSize);
|
||||
|
||||
vcg::tri::UpdateBounding<MyMesh>::Box(mesh);
|
||||
|
||||
// decimator initialization
|
||||
vcg::LocalOptimization<MyMesh> DeciSession(mesh,&qparams);
|
||||
|
||||
int t1=clock();
|
||||
DeciSession.Init<MyTriEdgeCollapse>();
|
||||
int t2=clock();
|
||||
printf("Initial Heap Size %i\n",int(DeciSession.h.size()));
|
||||
|
||||
DeciSession.SetTargetSimplices(FinalSize);
|
||||
DeciSession.SetTimeBudget(0.5f);
|
||||
DeciSession.SetTargetOperations(100000);
|
||||
if(TargetError< std::numeric_limits<float>::max() ) DeciSession.SetTargetMetric(TargetError);
|
||||
|
||||
while(DeciSession.DoOptimization() && mesh.fn>FinalSize && DeciSession.currMetric < TargetError)
|
||||
printf("Current Mesh size %7i heap sz %9i err %9g \n",mesh.fn, int(DeciSession.h.size()),DeciSession.currMetric);
|
||||
|
||||
int t3=clock();
|
||||
printf("mesh %d %d Error %g \n",mesh.vn,mesh.fn,DeciSession.currMetric);
|
||||
printf("\nCompleted in (%5.3f+%5.3f) sec\n",float(t2-t1)/CLOCKS_PER_SEC,float(t3-t2)/CLOCKS_PER_SEC);
|
||||
vcg::tri::io::ExporterPLY<MyMesh>::Save(mesh,argv[2]);
|
||||
return 0;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
|
||||
TARGET = tridecimator
|
||||
DEPENDPATH += ../..
|
||||
INCLUDEPATH += . ../.. ../../eigenlib
|
||||
CONFIG += console stl c++11 debug_and_release
|
||||
TEMPLATE = app
|
||||
HEADERS +=
|
||||
SOURCES += tridecimator.cpp ../../wrap/ply/plylib.cpp
|
||||
|
||||
|
||||
# Mac specific Config required to avoid to make application bundles
|
||||
CONFIG -= app_bundle
|
||||
Reference in new issue
Block a user