00001
00002 #include <vcg/complex/complex.h>
00003
00004
00005 #include <wrap/io_trimesh/import.h>
00006 #include <wrap/io_trimesh/export_ply.h>
00007
00008
00009 #include <vcg/complex/algorithms/local_optimization.h>
00010 #include <vcg/complex/algorithms/local_optimization/tri_edge_collapse_quadric.h>
00011
00012 using namespace vcg;
00013 using namespace tri;
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031 class MyVertex;
00032 class MyEdge;
00033 class MyFace;
00034
00035 struct MyUsedTypes: public UsedTypes<Use<MyVertex>::AsVertexType,Use<MyEdge>::AsEdgeType,Use<MyFace>::AsFaceType>{};
00036
00037 class MyVertex : public Vertex< MyUsedTypes,
00038 vertex::VFAdj,
00039 vertex::Coord3f,
00040 vertex::Normal3f,
00041 vertex::Mark,
00042 vertex::BitFlags >{
00043 public:
00044 vcg::math::Quadric<double> &Qd() {return q;}
00045 private:
00046 math::Quadric<double> q;
00047 };
00048
00049 class MyEdge : public Edge< MyUsedTypes> {};
00050
00051 typedef BasicVertexPair<MyVertex> VertexPair;
00052
00053 class MyFace : public Face< MyUsedTypes,
00054 face::VFAdj,
00055 face::VertexRef,
00056 face::BitFlags > {};
00057
00058
00059 class MyMesh : public vcg::tri::TriMesh<std::vector<MyVertex>, std::vector<MyFace> > {};
00060
00061
00062 class MyTriEdgeCollapse: public vcg::tri::TriEdgeCollapseQuadric< MyMesh, VertexPair, MyTriEdgeCollapse, QInfoStandard<MyVertex> > {
00063 public:
00064 typedef vcg::tri::TriEdgeCollapseQuadric< MyMesh, VertexPair, MyTriEdgeCollapse, QInfoStandard<MyVertex> > TECQ;
00065 typedef MyMesh::VertexType::EdgeType EdgeType;
00066 inline MyTriEdgeCollapse( const VertexPair &p, int i, BaseParameterClass *pp) :TECQ(p,i,pp){}
00067 };
00068
00069 void Usage()
00070 {
00071 printf(
00072 "---------------------------------\n"
00073 " TriSimp V.1.0 \n"
00074 " http://vcg.isti.cnr.it\n"
00075 " http://vcg.sourceforge.net\n"
00076 " release date: "__DATE__"\n"
00077 "---------------------------------\n\n"
00078 "TriDecimator 1.0 \n"__DATE__"\n"
00079 "Copyright 2003-2012 Visual Computing Lab I.S.T.I. C.N.R.\n"
00080 "\nUsage: "\
00081 "tridecimator fileIn fileOut face_num [opt]\n"\
00082 "Where opt can be:\n"\
00083 " -e# QuadricError threshold (range [0,inf) default inf)\n"
00084 " -b# Boundary Weight (default .5)\n"
00085 " -q# Quality threshold (range [0.0, 0.866], default .3 )\n"
00086 " -n# Normal threshold (degree range [0,180] default 90)\n"
00087 " -E# Minimal admitted quadric value (default 1e-15, must be >0)\n"
00088 " -Q[y|n] Use or not Quality Threshold (default yes)\n"
00089 " -N[y|n] Use or not Normal Threshold (default no)\n"
00090 " -A[y|n] Use or not Area Weighted Quadrics (default yes)\n"
00091 " -O[y|n] Use or not vertex optimal placement (default yes)\n"
00092 " -S[y|n] Use or not Scale Independent quadric measure(default yes) \n"
00093 " -B[y|n] Preserve or not mesh boundary (default no)\n"
00094 " -T[y|n] Preserve or not Topology (default no)\n"
00095 " -H[y|n] Use or not Safe Heap Update (default no)\n"
00096 " -P Before simplification, remove duplicate & unreferenced vertices\n"
00097 );
00098 exit(-1);
00099 }
00100
00101
00102 MyMesh mesh;
00103
00104 int main(int argc ,char**argv){
00105 if(argc<4) Usage();
00106
00107 int FinalSize=atoi(argv[3]);
00108
00109 int err=vcg::tri::io::Importer<MyMesh>::Open(mesh,argv[1]);
00110 if(err)
00111 {
00112 printf("Unable to open mesh %s : '%s'\n",argv[1],vcg::tri::io::Importer<MyMesh>::ErrorMsg(err));
00113 exit(-1);
00114 }
00115 printf("mesh loaded %d %d \n",mesh.vn,mesh.fn);
00116
00117 TriEdgeCollapseQuadricParameter qparams;
00118 qparams.QualityThr =.3;
00119 float TargetError=std::numeric_limits<float>::max();
00120 bool CleaningFlag =false;
00121
00122 for(int i=4; i < argc;)
00123 {
00124 if(argv[i][0]=='-')
00125 switch(argv[i][1])
00126 {
00127 case 'H' : qparams.SafeHeapUpdate=true; printf("Using Safe heap option\n"); break;
00128 case 'Q' : if(argv[i][2]=='y') { qparams.QualityCheck = true; printf("Using Quality Checking\n"); }
00129 else { qparams.QualityCheck = false; printf("NOT Using Quality Checking\n"); } break;
00130 case 'N' : if(argv[i][2]=='y') { qparams.NormalCheck = true; printf("Using Normal Deviation Checking\n"); }
00131 else { qparams.NormalCheck = false; printf("NOT Using Normal Deviation Checking\n"); } break;
00132 case 'O' : if(argv[i][2]=='y') { qparams.OptimalPlacement = true; printf("Using OptimalPlacement\n"); }
00133 else { qparams.OptimalPlacement = false; printf("NOT Using OptimalPlacement\n"); } break;
00134 case 'S' : if(argv[i][2]=='y') { qparams.ScaleIndependent = true; printf("Using ScaleIndependent\n"); }
00135 else { qparams.ScaleIndependent = false; printf("NOT Using ScaleIndependent\n"); } break;
00136 case 'B' : if(argv[i][2]=='y') { qparams.PreserveBoundary = true; printf("Preserving Boundary\n"); }
00137 else { qparams.PreserveBoundary = false; printf("NOT Preserving Boundary\n"); } break;
00138 case 'T' : if(argv[i][2]=='y') { qparams.PreserveTopology = true; printf("Preserving Topology\n"); }
00139 else { qparams.PreserveTopology = false; printf("NOT Preserving Topology\n"); } break;
00140 case 'q' : qparams.QualityThr = atof(argv[i]+2); printf("Setting Quality Thr to %f\n",atof(argv[i]+2)); break;
00141 case 'n' : qparams.NormalThrRad = math::ToRad(atof(argv[i]+2)); printf("Setting Normal Thr to %f deg\n",atof(argv[i]+2)); break;
00142 case 'b' : qparams.BoundaryWeight = atof(argv[i]+2); printf("Setting Boundary Weight to %f\n",atof(argv[i]+2)); break;
00143 case 'e' : TargetError = float(atof(argv[i]+2)); printf("Setting TargetError to %g\n",atof(argv[i]+2)); break;
00144 case 'P' : CleaningFlag=true; printf("Cleaning mesh before simplification\n"); break;
00145
00146 default : printf("Unknown option '%s'\n", argv[i]);
00147 exit(0);
00148 }
00149 i++;
00150 }
00151
00152
00153
00154 if(CleaningFlag){
00155 int dup = tri::Clean<MyMesh>::RemoveDuplicateVertex(mesh);
00156 int unref = tri::Clean<MyMesh>::RemoveUnreferencedVertex(mesh);
00157 printf("Removed %i duplicate and %i unreferenced vertices from mesh \n",dup,unref);
00158 }
00159
00160
00161 printf("reducing it to %i\n",FinalSize);
00162
00163 vcg::tri::UpdateBounding<MyMesh>::Box(mesh);
00164
00165
00166 vcg::LocalOptimization<MyMesh> DeciSession(mesh,&qparams);
00167
00168 int t1=clock();
00169 DeciSession.Init<MyTriEdgeCollapse>();
00170 int t2=clock();
00171 printf("Initial Heap Size %i\n",int(DeciSession.h.size()));
00172
00173 DeciSession.SetTargetSimplices(FinalSize);
00174 DeciSession.SetTimeBudget(0.5f);
00175 if(TargetError< std::numeric_limits<float>::max() ) DeciSession.SetTargetMetric(TargetError);
00176
00177 while(DeciSession.DoOptimization() && mesh.fn>FinalSize && DeciSession.currMetric < TargetError)
00178 printf("Current Mesh size %7i heap sz %9i err %9g \r",mesh.fn, int(DeciSession.h.size()),DeciSession.currMetric);
00179
00180 int t3=clock();
00181 printf("mesh %d %d Error %g \n",mesh.vn,mesh.fn,DeciSession.currMetric);
00182 printf("\nCompleted in (%i+%i) msec\n",t2-t1,t3-t2);
00183
00184 vcg::tri::io::ExporterPLY<MyMesh>::Save(mesh,argv[2]);
00185 return 0;
00186
00187 }