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