From 51f13ef53c1ff4cb29ca0f0a6adf1a00cf92b943 Mon Sep 17 00:00:00 2001 From: ponchio Date: Tue, 21 Sep 2004 00:53:23 +0000 Subject: [PATCH] Lotsa changes. --- apps/nexus/decimate.cpp | 20 ++- apps/nexus/pchain.h | 6 +- apps/nexus/pvoronoi.cpp | 5 +- apps/nexus/pvoronoi.h | 6 +- apps/nexus/voronoichain.cpp | 273 ++++++++++++++++++++++++++++++------ apps/nexus/voronoichain.h | 25 ++-- apps/nexus/voronoinxs.cpp | 57 ++++++-- 7 files changed, 321 insertions(+), 71 deletions(-) diff --git a/apps/nexus/decimate.cpp b/apps/nexus/decimate.cpp index 37f5c39b..b58c26f5 100644 --- a/apps/nexus/decimate.cpp +++ b/apps/nexus/decimate.cpp @@ -45,7 +45,14 @@ using namespace tri; using namespace nxs; using namespace std; -void Cluster(MyMesh &mesh, unsigned int target_faces); +float Clustering(unsigned int target_faces, + vector &newvert, + vector &newface, + vector &newbord, + vector &vert_remap) { +} + +float Cluster(MyMesh &mesh, unsigned int target_faces); float Decimate(unsigned int target_faces, vector &newvert, @@ -128,8 +135,9 @@ float Decimate(unsigned int target_faces, FinalSize = mesh.fn - FinalSize; //number of faces to remove FinalSize/=2; //Number of vertices to remove DeciSession.SetTargetOperations(FinalSize); - DeciSession.DoOptimization(); - float error = 1; //get error; + // DeciSession.DoOptimization(); + float error = Cluster(mesh, target_faces); + // float error = DeciSession.currMetric/4;//1; //get error; int t3=clock(); /* printf(" vol %d \n lkv %d \n lke %d \n lkf %d \n ood %d\n bor %d\n ", @@ -176,7 +184,7 @@ float Decimate(unsigned int target_faces, return error; } -void Cluster(MyMesh &mesh, unsigned int target_faces) { +float Cluster(MyMesh &mesh, unsigned int target_faces) { unsigned int starting = mesh.vn; cerr << "starting face: " << mesh.fn << endl; //veramente brutale @@ -200,6 +208,7 @@ void Cluster(MyMesh &mesh, unsigned int target_faces) { } } + float error = 0; cerr << "done" << endl; map >::iterator s; for(s = dist.begin(); s != dist.end(); s++) { @@ -214,6 +223,7 @@ void Cluster(MyMesh &mesh, unsigned int target_faces) { assert(!mesh.vert[source].IsD()); mesh.vert[source].SetD(); + error = (*s).first; remap[source] = target; remap[target] = target; toremove -= 2; @@ -238,5 +248,5 @@ void Cluster(MyMesh &mesh, unsigned int target_faces) { } } cerr << "Ending faces: " << mesh.fn << endl; - + return error; } diff --git a/apps/nexus/pchain.h b/apps/nexus/pchain.h index 8195b4b1..b361941f 100644 --- a/apps/nexus/pchain.h +++ b/apps/nexus/pchain.h @@ -24,6 +24,9 @@ History $Log: not supported by cvs2svn $ +Revision 1.4 2004/08/27 00:39:28 ponchio +Rewrote. + Revision 1.3 2004/07/20 14:06:02 ponchio Changed filename saving. @@ -60,7 +63,8 @@ class PChain { virtual void RemapFaces(Crude &crude, VFile &face_remap, - std::vector &patch_faces) = 0; + std::vector &patch_faces, + float scaling, int steps) = 0; /* virtual unsigned int Levels() = 0; diff --git a/apps/nexus/pvoronoi.cpp b/apps/nexus/pvoronoi.cpp index 79a0155e..56792b3b 100644 --- a/apps/nexus/pvoronoi.cpp +++ b/apps/nexus/pvoronoi.cpp @@ -24,6 +24,9 @@ History $Log: not supported by cvs2svn $ +Revision 1.3 2004/08/27 00:39:28 ponchio +Rewrote. + Revision 1.2 2004/07/01 21:35:34 ponchio int -> Key @@ -50,7 +53,7 @@ using namespace nxs; bool Seed::Dist(const Point3f &point, float &mindist, Point3f &res) { - float newdist = Distance(p, point); + float newdist = Distance(p, point) * weight; if(newdist < mindist) { mindist = newdist; res = p; diff --git a/apps/nexus/pvoronoi.h b/apps/nexus/pvoronoi.h index c66f526a..44f7f923 100644 --- a/apps/nexus/pvoronoi.h +++ b/apps/nexus/pvoronoi.h @@ -24,6 +24,9 @@ History $Log: not supported by cvs2svn $ +Revision 1.5 2004/08/27 00:39:28 ponchio +Rewrote. + Revision 1.4 2004/07/20 14:17:51 ponchio *** empty log message *** @@ -113,6 +116,7 @@ namespace nxs { unsigned int count(unsigned int key); Seed &operator[](unsigned int key); void clear(); + void reload() { ug_seeds = all_seeds; ug.Set(ug_seeds); } unsigned int Locate(const vcg::Point3f &p); float Priority(const vcg::Point3f &p, unsigned int key); @@ -184,7 +188,7 @@ namespace nxs { return radius; } - private: + // private: vcg::Box3f bbox; vcg::GridStaticPtr< std::vector > ug; std::vector all_seeds; diff --git a/apps/nexus/voronoichain.cpp b/apps/nexus/voronoichain.cpp index bfffe5bf..15064e60 100644 --- a/apps/nexus/voronoichain.cpp +++ b/apps/nexus/voronoichain.cpp @@ -24,6 +24,9 @@ History $Log: not supported by cvs2svn $ +Revision 1.3 2004/09/17 15:25:09 ponchio +First working (hopefully) release. + Revision 1.2 2004/09/16 14:25:16 ponchio Backup. (lot of changes). @@ -41,40 +44,144 @@ using namespace std; using namespace vcg; using namespace nxs; -void VoronoiChain::Initialize(unsigned int psize, unsigned int pthreshold) { - patch_size = psize; - patch_threshold = pthreshold; -} -void VoronoiChain::Init(Crude &crude) { +void VoronoiChain::Init(Crude &crude, float scaling, int steps) { box = crude.GetBox(); - radius = VoronoiPartition::OptimalRadius(crude, patch_size); - float radius0 = radius; - float radius1 = radius * 1.4; - // float radius1 = VoronoiPartition::OptimalRadius(crude, patch_size*2); + box.Offset(box.max - box.min); + //how many cells do i need? + cerr << "scaling: " << scaling << endl; + unsigned int f_cells = crude.Faces() / mean_size; + unsigned int c_cells = (unsigned int)(scaling * f_cells); + + cerr << "mean size: " << mean_size << endl; + cerr << "f cells: " << f_cells << endl; + cerr << "c_cells: " << c_cells << endl; levels.push_back(VoronoiPartition()); levels.push_back(VoronoiPartition()); - VoronoiPartition &part0 = levels[0]; - VoronoiPartition &part1 = levels[1]; - part0.Init(crude.GetBox()); - part1.Init(crude.GetBox()); + VoronoiPartition &fine = levels[0]; + VoronoiPartition &coarse = levels[1]; - VFile::iterator iter; - for(iter = crude.vert.Begin(); iter != crude.vert.End(); ++iter) { - Point3f &v = *iter; - unsigned int target_patch; + fine.Init(box); + coarse.Init(box); - float dist = part0.Closest(v, target_patch); - if(dist >= radius0 || dist == -1) - part0.Add(v, radius0); + srand(0); + + vector fine_seeds; + vector coarse_seeds; - dist = part1.Closest(v, target_patch); - if(dist >= radius1 || dist == -1) - part1.Add(v, radius1); + float fine_vmean = mean_size/2; + float coarse_vmean = (mean_size/scaling)/2; + for(unsigned int i = 0; i < crude.Vertices(); i++) { + int f = (int)(fine_vmean*rand()/(RAND_MAX + 1.0)); + int c = (int)(coarse_vmean *rand()/(RAND_MAX + 1.0)); + if(f == 1) { + Point3f &point = crude.GetVertex(i); + fine_seeds.push_back(Seed(point, 1)); + } + if(c == 1) { + Point3f &point = crude.GetVertex(i); + coarse_seeds.push_back(Seed(point, 1)); + } } + cerr << "fine_seeds.size: " << fine_seeds.size() << endl; + cerr << "coarse_seeds.size: " << coarse_seeds.size() << endl; + fine.all_seeds = fine_seeds; + coarse.all_seeds = coarse_seeds; + fine.reload(); + coarse.reload(); //here goes some optimization pass. + //Fine optimization. + vector fcentroids; + vector fcount; + for(unsigned int i = 0; i < steps; i++) { + cerr << "Optimization step 0: " << i << "/" << steps << endl; + fcentroids.clear(); + fcount.clear(); + fcentroids.resize(fine.size(), Point3f(0, 0, 0)); + fcount.resize(fine.size(), 0); + + for(unsigned int v = 0; v < crude.Vertices(); v++) { + unsigned int ftarget; + float dist = fine.Closest(crude.vert[v], ftarget); + assert(ftarget != -1); + fcentroids[ftarget] += crude.vert[v]; + fcount[ftarget]++; + } + for(unsigned int v = 0; v < fine.size(); v++) { + assert(fcount[v] != 0); + + fine[v].p = fcentroids[v]/fcount[v]; + //0.3 is related to the fact is doubled the box size. + fine[v].weight = pow(fcount[v]/fine_vmean, 0.3f); + // fine.bbox.Add(fine[v].p); + } + // fine.Init(fine.bbox); + fine.reload(); + } + + //Coarse optimization + vector< map > ccentroids; + vector< map > ccount; + + for(unsigned int i = 0; i < steps; i++) { + cerr << "Optimization step 1: " << i << "/" << steps << endl; + ccentroids.clear(); + ccount.clear(); + ccentroids.resize(coarse.size()); + ccount.resize(coarse.size()); + + for(unsigned int v = 0; v < crude.Vertices(); v++) { + unsigned int ftarget; + float dist = fine.Closest(crude.vert[v], ftarget); + assert(ftarget != -1); + + unsigned int ctarget; + dist = coarse.Closest(crude.vert[v], ctarget); + assert(ctarget != -1); + + map ¢roids = ccentroids[ctarget]; + map &count = ccount[ctarget]; + + if(!centroids.count(ftarget)) + centroids[ftarget]= Point3f(0, 0, 0); + + if(!count.count(ftarget)) + count[ftarget] = 0; + + centroids[ftarget] += crude.vert[v]; + count[ftarget]++; + } + + for(unsigned int v = 0; v < coarse.size(); v++) { + + map ¢roids = ccentroids[v]; + map &count = ccount[v]; + + + coarse[v].p = Point3f(0, 0, 0); + float weight = 0; + unsigned int tot_size =0; + map::iterator k; + for(k = centroids.begin();k != centroids.end(); k++) { + unsigned int size = count[(*k).first]; + tot_size += size; + //coarse[v].p += (*k).second / (size * size); + //weight += 1/(float)size; + coarse[v].p += (*k).second / size; + weight += 1; + // coarse[v].p += (*k).second; + // weight += size; + } + assert(weight > 0); + coarse[v].p /= weight; + //TODO find a solution + // coarse[v].weight = pow(tot_size/coarse_vmean, 0.25f); + + } + coarse.reload(); + } } unsigned int VoronoiChain::Locate(unsigned int level, @@ -86,11 +193,11 @@ unsigned int VoronoiChain::Locate(unsigned int level, return fine + coarse * levels[level].size();*/ } -void VoronoiChain::RemapFaces(Crude &crude, - VFile &face_remap, - vector &patch_faces) { +void VoronoiChain::RemapFaces(Crude &crude, VFile &face_remap, + vector &patch_faces, + float scaling, int steps) { - Init(crude); + Init(crude, scaling, steps); //TODO: improve quality of patches and implement threshold. typedef map, unsigned int> FragIndex; @@ -115,7 +222,10 @@ void VoronoiChain::RemapFaces(Crude &crude, } else patch = patches[make_pair(coarse, fine)]; + //BEWARE unkomment this! face_remap[i] = patch; + //face_remap[i] = fine; + // face_remap[i] = coarse; if(patch_faces.size() <= patch) patch_faces.resize(patch+1, 0); patch_faces[patch]++; @@ -164,28 +274,109 @@ void VoronoiChain::RemapFaces(Crude &crude, patch_faces.resize(tot_patches); } -void VoronoiChain::BuildLevel(Nexus &nexus, unsigned int offset) { - unsigned int target_faces = (int)(patch_size * - pow(scaling, (float)levels.size())); - - float rad = radius * pow(sqrt(1/scaling), (float)levels.size()); +void VoronoiChain::BuildLevel(Nexus &nexus, unsigned int offset, + float scaling, int steps) { + // unsigned int target_faces = (int)(mean_size * + // pow(0.5f, (float)levels.size())); + unsigned int totface = 0; + for(unsigned int idx = offset; idx < nexus.index.size(); idx++) + totface += nexus.index[idx].nface; + levels.push_back(VoronoiPartition()); - VoronoiPartition &part = levels[levels.size()-1]; - part.Init(box); + VoronoiPartition &coarse = levels[levels.size()-1]; + VoronoiPartition &fine = levels[levels.size()-2]; + coarse.Init(box); + + fine.reload(); + + srand(0); + float coarse_vmean = (totface/2)/(fine.size() * scaling); + + cerr << "initing random seeds\n"; + + vector coarse_seeds; + for(unsigned int idx = offset; idx < nexus.index.size(); idx++) { Patch patch = nexus.GetPatch(idx); for(unsigned int i = 0; i < patch.nv; i++) { - Point3f &v = patch.Vert(i); - unsigned int target_patch; - - float dist = part.Closest(v, target_patch); - if(dist >= rad || dist == -1) - part.Add(v, rad); + int c = (int)(coarse_vmean*rand()/(RAND_MAX + 1.0)); + if(c == 1) { + Point3f &v = patch.Vert(i); + coarse_seeds.push_back(v); + } } } - cerr << "radius: " << rad << " ... cells: " << part.size() << endl; + if(coarse_seeds.size() == 0) + coarse_seeds.push_back(Point3f(0, 0, 0)); + coarse.all_seeds = coarse_seeds; + coarse.reload(); + +//Coarse optimization + vector< map > ccentroids; + vector< map > ccount; + + for(unsigned int step = 0; step < steps; step++) { + cerr << "Optimization step " << levels.size()-1 << ":" + << step << "/" << steps << endl; + ccentroids.clear(); + ccount.clear(); + ccentroids.resize(coarse.size()); + ccount.resize(coarse.size()); + + for(unsigned int idx = offset; idx < nexus.index.size(); idx++) { + Patch patch = nexus.GetPatch(idx); + + for(unsigned int i = 0; i < patch.nv; i++) { + Point3f &v = patch.Vert(i); + unsigned int ftarget; + float dist = fine.Closest(Point3f(1,1,1), ftarget); + + dist = fine.Closest(v, ftarget); + assert(ftarget != -1); + + unsigned int ctarget; + dist = coarse.Closest(v, ctarget); + assert(ctarget != -1); + + map ¢roids = ccentroids[ctarget]; + map &count = ccount[ctarget]; + + if(!centroids.count(ftarget)) + centroids[ftarget]= Point3f(0, 0, 0); + + if(!count.count(ftarget)) + count[ftarget] = 0; + + centroids[ftarget] += v; + count[ftarget]++; + } + } + + cerr << "recentring" << endl; + for(unsigned int v = 0; v < coarse.size(); v++) { + + map ¢roids = ccentroids[v]; + map &count = ccount[v]; + + coarse[v].p = Point3f(0, 0, 0); + float weight = 0; + unsigned int tot_size =0; + map::iterator k; + for(k = centroids.begin();k != centroids.end(); k++) { + unsigned int size = count[(*k).first]; + tot_size += size; + coarse[v].p += (*k).second / size; + weight += 1; + } + assert(weight > 0); + coarse[v].p /= weight; + //TODO find a solution! + // coarse[v].weight = pow(tot_size/coarse_vmean, 0.25f); + } + coarse.reload(); + } newfragments.clear(); //TODO add some optimization } diff --git a/apps/nexus/voronoichain.h b/apps/nexus/voronoichain.h index 8f35203a..5d242d56 100644 --- a/apps/nexus/voronoichain.h +++ b/apps/nexus/voronoichain.h @@ -24,6 +24,9 @@ History $Log: not supported by cvs2svn $ +Revision 1.2 2004/09/16 14:25:16 ponchio +Backup. (lot of changes). + Revision 1.1 2004/08/26 18:03:48 ponchio First draft. @@ -48,16 +51,23 @@ namespace nxs { class VoronoiChain: public PChain { public: - VoronoiChain():scaling(0.5), patch_size(1000), patch_threshold(300) {} - virtual ~VoronoiChain() {} - void Initialize(unsigned int psize, unsigned int pthreshold); - void Init(Crude &crude); + unsigned int mean_size; //mean number of faces per patch + unsigned int min_size; //minimum number of faces per patch (soft) + unsigned int max_size; //max number of faces per patch (hard); + VoronoiChain(unsigned int mean_s = 1000, + unsigned int min_s = 300, + unsigned int max_s = 32000): + mean_size(mean_s), min_size(min_s), max_size(max_s) {} + virtual ~VoronoiChain() {} + + void Init(Crude &crude, float scaling, int steps); virtual unsigned int Locate(unsigned int level, const vcg::Point3f &p); void RemapFaces(Crude &crude, VFile &face_remap, - std::vector &patch_faces); + std::vector &patch_faces, float scaling, + int steps); - void BuildLevel(Nexus &nexus, unsigned int offset); + void BuildLevel(Nexus &nexus, unsigned int offset, float scaling, int steps); std::vector levels; @@ -65,9 +75,6 @@ class VoronoiChain: public PChain { std::map > newfragments; std::map > oldfragments; // private: - float scaling; - unsigned int patch_size; - unsigned int patch_threshold; float radius; vcg::Box3f box; diff --git a/apps/nexus/voronoinxs.cpp b/apps/nexus/voronoinxs.cpp index 61bff6c0..a7bd37fc 100644 --- a/apps/nexus/voronoinxs.cpp +++ b/apps/nexus/voronoinxs.cpp @@ -24,6 +24,9 @@ History $Log: not supported by cvs2svn $ +Revision 1.3 2004/09/17 15:25:09 ponchio +First working (hopefully) release. + Revision 1.2 2004/09/16 14:25:16 ponchio Backup. (lot of changes). @@ -97,15 +100,20 @@ float Decimate(unsigned int target_faces, void ReverseHistory(vector &history); +enum Decimation { QUADRIC, CLUSTER }; + int main(int argc, char *argv[]) { + Decimation decimation = QUADRIC; unsigned int patch_size = 1000; unsigned int patch_threshold = 200; + unsigned int optimization_steps = 5; + bool stop_after_remap = false; unsigned int max_level = 0xffffffff; float scaling = 0.5; int option; - while((option = getopt(argc, argv, "f:t:l:s:")) != EOF) { + while((option = getopt(argc, argv, "f:t:l:s:d:ro:")) != EOF) { switch(option) { case 'f': patch_size = atoi(optarg); if(patch_size == 0 || patch_size > 32000) { @@ -131,12 +139,24 @@ int main(int argc, char *argv[]) { cerr << "Must be 0 < scaling < 1" << endl; } break; + case 'd': + if(!strcmp("quadric", optarg)) + decimation = QUADRIC; + else if(!strcmp("cluster", optarg)) + decimation = CLUSTER; + else { + cerr << "Unknown decimation method: " << optarg << endl; + return -1; + } + break; + case 'r': stop_after_remap = true; break; + case 'o': optimization_steps = atoi(optarg); break; default: cerr << "Unknown option: " << (char)option << endl; return -1; } } - //Test there are still 2 arguments + //Test that there are still 2 arguments if(optind != argc - 2) { cerr << "Usage: " << argv[0] << " [options]\n"; cerr << " Options:\n"; @@ -144,6 +164,7 @@ int main(int argc, char *argv[]) { cerr << " -t N: mini faces per patch (default 200)\n"; cerr << " -l N: number of levels\n"; cerr << " -s F: scaling factor (0 < F < 1, default 0.5)\n\n"; + cerr << " -d : decimation method: quadric, cluster. (default quadric)\n"; return -1; } @@ -154,23 +175,21 @@ int main(int argc, char *argv[]) { } if(patch_size > crude.vert.Size()/2) { - cerr << "Patch size too big: " << patch_size << " ~ " << crude.vert.Size() + cerr << "Patch size too big: " << patch_size << " * 2 > " << crude.vert.Size() << endl; return -1; } string output = argv[optind+1]; - Signature signature = HAS_FACES; Nexus nexus; - if(!nexus.Create(output, signature)) { + if(!nexus.Create(output, HAS_FACES)) { cerr << "Could not create nexus output: " << output << endl; return -1; } - VoronoiChain vchain; - vchain.Initialize(patch_size, patch_threshold); - vchain.scaling = scaling; + VoronoiChain vchain(patch_size, patch_threshold); + // vchain.scaling = scaling; //Now building level 0 of the Nexus @@ -200,12 +219,13 @@ int main(int argc, char *argv[]) { //Remapping faces and vertices using level 0 and 1 of the chain vector patch_faces; - vchain.RemapFaces(crude, face_remap, patch_faces); + vchain.RemapFaces(crude, face_remap, patch_faces, scaling, optimization_steps); vector patch_verts; patch_verts.resize(patch_faces.size(), 0); RemapVertices(crude, vert_remap, face_remap, patch_verts); + if(stop_after_remap) return 0; //allocate chunks for patches and copy faces (absoklute indexing) into them. NexusAllocate(crude, nexus, face_remap, patch_faces, patch_verts); @@ -231,8 +251,9 @@ int main(int argc, char *argv[]) { cerr << "Level: " << level << endl; unsigned int newoffset = nexus.index.size(); - vchain.BuildLevel(nexus, oldoffset); + vchain.BuildLevel(nexus, oldoffset, scaling, optimization_steps); + cerr << "Level built\n"; vector level_history; map >::iterator fragment; for(fragment = vchain.oldfragments.begin(); @@ -662,13 +683,24 @@ void NexusSplit(Nexus &nexus, VoronoiChain &vchain, Nexus::Entry &rentry = nexus.index[link.end_patch]; //TODO if !true reallocate borders. + + Border rborder = nexus.GetBorder(link.end_patch); if(rentry.border_used >= rentry.border_size) { cerr << "patch: " << link.end_patch << endl; cerr << "used: " << rentry.border_used << endl; cerr << "size: " << rentry.border_size << endl; + unsigned int start = nexus.borders.Size(); + nexus.borders.Resize(nexus.borders.Size() + 2 * rentry.border_size); + Link *tmp = new Link[rentry.border_size]; + memcpy(tmp, &rborder[0], sizeof(Link) * rentry.border_size); + rentry.border_start = start; + rentry.border_size *= 2; + rborder = nexus.GetBorder(link.end_patch); + memcpy(&rborder[0], tmp, sizeof(Link) * rentry.border_used); + delete []tmp; } assert(rentry.border_used < rentry.border_size); - Border rborder = nexus.GetBorder(link.end_patch); + Link &newlink = rborder[rentry.border_used++]; newlink.start_vert = link.end_vert; @@ -695,8 +727,7 @@ void NexusSplit(Nexus &nexus, VoronoiChain &vchain, Nexus::Entry &entry = nexus.index[patch_idx]; - // entry.error = error; - entry.error = level; + entry.error = error; Patch patch = nexus.GetPatch(patch_idx); memcpy(patch.FaceBegin(), &faces[0],