diff --git a/apps/nexus/crude.cpp b/apps/nexus/crude.cpp index 7defc2ae..9cf0b875 100644 --- a/apps/nexus/crude.cpp +++ b/apps/nexus/crude.cpp @@ -24,6 +24,9 @@ History $Log: not supported by cvs2svn $ +Revision 1.2 2004/07/02 13:08:11 ponchio +Changed extension to .cri, crv, crf + Revision 1.1 2004/06/24 14:32:45 ponchio Moved from wrap/nexus @@ -54,9 +57,10 @@ bool Crude::Create(const std::string &file, unsigned int nv, unsigned int nf) { Resize(nv, nf); return true; } -bool Crude::Load(const std::string &file) { - if(!vert.Load(file + ".crv")) return false; - if(!face.Load(file + ".crf")) return false; + +bool Crude::Load(const std::string &file, bool rdonly) { + if(!vert.Load(file + ".crv", rdonly)) return false; + if(!face.Load(file + ".crf", rdonly)) return false; fp = fopen((file + ".cri").c_str(), "rb+"); if(!fp) return false; @@ -90,6 +94,13 @@ unsigned int Crude::Faces() { return nface; } +void Crude::SetVertex(unsigned int i, Point3f &f) { + Point3f &p = vert[i]; + p[0] = f[0]; + p[1] = f[1]; + p[2] = f[2]; +} + void Crude::SetVertex(unsigned int i, float *f) { Point3f &p = vert[i]; p[0] = f[0]; @@ -97,19 +108,25 @@ void Crude::SetVertex(unsigned int i, float *f) { p[2] = f[2]; } -Point3f &Crude::GetVertex(unsigned int i) { +Point3f Crude::GetVertex(unsigned int i) { return vert[i]; } -Crude::Face &Crude::GetFace(unsigned int i) { +Crude::Face Crude::GetFace(unsigned int i) { return face[i]; } - void Crude::SetFace(unsigned int i, unsigned int *f) { - Face &ff = face[i]; - ff[0] = f[0]; - ff[1] = f[1]; - ff[2] = f[2]; - } - +void Crude::SetFace(unsigned int i, Face &f) { + Face &ff = face[i]; + ff[0] = f[0]; + ff[1] = f[1]; + ff[2] = f[2]; +} +void Crude::SetFace(unsigned int i, unsigned int *f) { + Face &ff = face[i]; + ff[0] = f[0]; + ff[1] = f[1]; + ff[2] = f[2]; +} + vcg::Point3f Crude::GetBari(unsigned int i) { Point3f bari(0, 0, 0); Face &f = face[i]; diff --git a/apps/nexus/crude.h b/apps/nexus/crude.h index 033f7fa5..c0aeb88c 100644 --- a/apps/nexus/crude.h +++ b/apps/nexus/crude.h @@ -24,6 +24,9 @@ History $Log: not supported by cvs2svn $ +Revision 1.4 2004/07/05 15:49:38 ponchio +Windows (DevCpp, mingw) port. + Revision 1.3 2004/07/04 15:25:33 ponchio Backup (work in progress) @@ -72,17 +75,19 @@ public: bool Create(const std::string &file, unsigned int nvert = 0, unsigned int nface = 0); - bool Load(const std::string &file); + bool Load(const std::string &file, bool rdonly = false); void Close(); void Resize(unsigned int nvert, unsigned int nface); unsigned int Vertices(); unsigned int Faces(); - vcg::Point3f &GetVertex(unsigned int i); + vcg::Point3f GetVertex(unsigned int i); + void SetVertex(unsigned int i, vcg::Point3f &p); void SetVertex(unsigned int i, float *p); - Face &GetFace(unsigned int i); + Face GetFace(unsigned int i); + void SetFace(unsigned int i, Face &f); void SetFace(unsigned int i, unsigned int *f); vcg::Point3f GetBari(unsigned int i); diff --git a/apps/nexus/mfile.h b/apps/nexus/mfile.h index d84f2034..415e2914 100644 --- a/apps/nexus/mfile.h +++ b/apps/nexus/mfile.h @@ -1,18 +1,19 @@ #ifndef NXS_MFILE_H #define NXS_MFILE_H - -#include "file.h" #include #include +#include "file.h" +#include "nxstypes.h" + namespace nxs { -#ifdef WIN32 + /*#ifdef WIN32 typedef __int64 int64; #else typedef unsigned long long int64; -#endif +#endif*/ #define MFILE_MAX_SIZE (1<<30) diff --git a/apps/nexus/nxstypes.h b/apps/nexus/nxstypes.h new file mode 100644 index 00000000..c2bd0af5 --- /dev/null +++ b/apps/nexus/nxstypes.h @@ -0,0 +1,14 @@ +#ifndef NXS_TYPES_H +#define NXS_TYPES_H + +#ifdef WIN32 +typedef __int64 int64; +#else +typedef unsigned long long int64; +//typedef unsigned long long uint64; +#endif + +typedef int int32; +typedef unsigned int uint32; + +#endif diff --git a/apps/nexus/remapping.cpp b/apps/nexus/remapping.cpp new file mode 100644 index 00000000..a5354ba9 --- /dev/null +++ b/apps/nexus/remapping.cpp @@ -0,0 +1,334 @@ +#include + +#include "remapping.h" +#include "watch.h" + + +using namespace std; +using namespace vcg; +using namespace nxs; + +bool BlockIndex::Save(const string &file) { + FILE *fp = fopen(file.c_str(), "wb+"); + if(!fp) { + cerr << "Could not save: " << file << endl; + return false; + } + unsigned int nsize = size(); + fwrite(&nsize, sizeof(unsigned int), 1, fp); + fwrite(&*begin(), sizeof(BlockEntry), nsize, fp); + fclose(fp); + return true; +} + +bool BlockIndex::Load(const string &file) { + FILE *fp = fopen(file.c_str(), "rb"); + if(!fp) { + cerr << "Could not load: " << file << endl; + return false; + } + unsigned int nsize; + fread(&nsize, sizeof(unsigned int), 1, fp); + resize(nsize); + fread(&*begin(), sizeof(BlockEntry), nsize, fp); + fclose(fp); + return true; +} + +void nxs::Remap(VChain &chain, + VFile &points, + VFile &remap, + BlockIndex &index, + unsigned int target_size, + unsigned int min_size, + unsigned int max_size, + float scaling, + int steps) { + + chain.push_back(VPartition()); + BuildPartition(chain.back(), points, target_size, min_size, max_size, steps); + + + + chain.push_back(VPartition()); + BuildPartition(chain.back(), points, + (int)(target_size/scaling), min_size, max_size, steps); + + + + VPartition &finepart = chain[0]; + finepart.Init(); + cerr << "Fine size: " << finepart.size() << endl; + + VPartition &coarsepart = chain[1]; + coarsepart.Init(); + cerr << "Coarse size: " << coarsepart.size() << endl; + + typedef map, unsigned int> FragIndex; + + FragIndex patches; + + unsigned int totpatches = 0; + vector count; + + Point3f bari; + for(unsigned int i = 0; i < points.Size(); i++) { + bari = points[i]; + + unsigned int fine = finepart.Locate(bari); + unsigned int coarse = coarsepart.Locate(bari); + + unsigned int patch; + + if(!patches.count(make_pair(coarse, fine))) { + patch = totpatches; + patches[make_pair(coarse, fine)] = totpatches++; + } else + patch = patches[make_pair(coarse, fine)]; + + remap[i] = patch; + + while(count.size() <= patch) + count.push_back(0); + count[patch]++; + } + + cerr << "Prune faces...\n"; + + //prune faces (now only 0 faces); + unsigned int new_totpatches = 0; + vector patch_remap; + for(unsigned int i = 0; i < totpatches; i++) { + //if below threshold (and can join faces) + // if(count[i] < min_size) + if(count[i] == 0) + patch_remap.push_back(-1); + else + patch_remap.push_back(new_totpatches++); + + if(count[i] > 32000) { + //TODO do something to reduce patch size... :P + cerr << "Found a patch too big... sorry\n"; + exit(0); + } + } + + + cerr << "BUilding fragmenbts\n"; + + //building fragments + FragIndex::iterator f; + for(f = patches.begin(); f != patches.end(); f++) { + unsigned int coarse = (*f).first.first; + unsigned int fine = (*f).first.second; + unsigned int oldpatch = (*f).second; + assert(oldpatch < patch_remap.size()); + unsigned int patch = patch_remap[oldpatch]; + if(patch != -1) //not deleted... + chain.oldfragments[coarse].insert(patch); + } + + cerr << "remapping faces again\n"; + //remapping faces + index.resize(new_totpatches); + for(unsigned int i = 0; i < remap.Size(); i++) { + unsigned int patch = remap[i]; +#ifdef CONTROLS + if(patch == 0xffffffff) { + cerr << "RESIGH\n"; + exit(0); + } + if(patch_remap[patch] == -1) {//must relocate this thing.... + //TODO + cerr << "Could not do this\n"; + exit(0); + } +#endif + + + unsigned int newpatch = patch_remap[patch]; + assert(newpatch < index.size()); + assert(newpatch >= 0); + remap[i] = newpatch; + BlockEntry &entry = index[newpatch]; + entry.size++; + } + + cerr << "fixing offsets in index\n"; + //Fixing offset + int64 offset = 0; + for(unsigned int i = 0; i < index.size(); i++) { + index[i].offset = offset; + offset += index[i].size; + } + +} + + +void nxs::BuildPartition(VPartition &part, + VFile &points, + unsigned int target_size, + unsigned int min_size, + unsigned int max_size, + int steps) { + + //TODO: improve quality of patches and implement threshold. + unsigned int ncells = points.Size()/target_size; + srand(0); + + for(unsigned int i = 0; i < points.Size(); i++) { + int f = (int)(target_size * (float)rand()/(RAND_MAX + 1.0)); + if(f == 2) { + Point3f &point = points[i]; + part.push_back(point); + } + } + + //TODO! Check for duplicates (use the closest :P) + part.Init(); + + Report report; + vector centroids; + vector counts; + + for(int step = 0; step < steps; step++) { + cerr << "Optimization step: " << step+1 << "/" << steps << endl; + + centroids.clear(); + counts.clear(); + centroids.resize(part.size(), Point3f(0, 0, 0)); + counts.resize(part.size(), 0); + + report.Init(points.Size()); + + for(unsigned int v = 0; v < points.Size(); v++) { + report.Step(v); + + unsigned int target = part.Locate(points[v]); + centroids[target] += points[v]; + counts[target]++; + } + + for(unsigned int v = 0; v < centroids.size(); v++) + if(counts[v] != 0) + centroids[v]/= counts[v]; + + if(step == steps-1) { + if(!Optimize(part, target_size, min_size, max_size, + centroids, counts, false)) + step--; + } else + Optimize(part, target_size, min_size, max_size, + centroids, counts, true); + } +} + +int nxs::GetBest(VPartition &part, unsigned int seed, + vector &mark, + vector &counts) { + + vector nears; + vector dists; + int nnear = 7; + if(part.size() < 7) nnear = part.size()/2; + if(!nnear) return -1; + + part.Closest(part[seed], nnear, nears, dists); + int best = -1; + int bestcount = -1; + int bestdist = -1; + + for(int k = 0; k < nnear; k++) { + int c = nears[k]; + if(c == seed) continue; + assert(c >= 0); + assert(c < part.size()); + if(mark[c]) continue; + + if(bestcount < 0 || + (counts[c] < bestcount)) { + best = c; + bestcount = counts[c]; + } + } + return best; +} + +bool nxs::Optimize(VPartition &part, + unsigned int target_size, + unsigned int min_size, + unsigned int max_size, + vector ¢roids, + vector &counts, + bool join) { + + unsigned int failed = 0; + vector seeds; + vector mark; + mark.resize(part.size(), false); + + //first pass we check only big ones + for(unsigned int i = 0; i < part.size(); i++) { + if(counts[i] > max_size || counts[i] > 2 * target_size) { + failed++; + float radius; + + if(part.size() == 1) + radius = 0.00001; + else + radius = part.Radius(i); + + if(radius == 0) { + cerr << "Radius zero???\n"; + exit(0); + } + radius /= 4; + seeds.push_back(centroids[i] + Point3f(1, -1, 1) * radius); + seeds.push_back(centroids[i] + Point3f(-1, 1, 1) * radius); + seeds.push_back(centroids[i] + Point3f(-1, -1, -1) * radius); + seeds.push_back(centroids[i] + Point3f(1, 1, -1) * radius); + mark[i]; + } + } + + if(join) { + for(unsigned int i = 0; i < part.size(); i++) { + if(mark[i] || counts[i] >= min_size) continue; + + failed++; + int best = GetBest(part, i, mark, counts); + if(best < 0) { + cerr << "Best not found! while looking for: " << i << "\n"; + continue; + } + assert(mark[best] == false); + mark[best] = true; + mark[i] = true; + seeds.push_back((part[i] + part[best])/2); + } + } + + for(unsigned int i = 0; i < part.size(); i++) { + if(mark[i]) continue; + if(counts[i] == 0) continue; + if(join) { + // if(counts[i] < min_size) { + // cerr << "Could not fix: " << i << endl; + // } else { + part[i] = centroids[i]; + // } + } + seeds.push_back(part[i]); + } + + part.clear(); + for(unsigned int i = 0; i < seeds.size(); i++) + part.push_back(seeds[i]); + + if(part.size() == 0) { + cerr << "OOOPS i accidentally deleted all seeds... backup :P\n"; + part.push_back(Point3f(0,0,0)); + } + part.Init(); + return failed == 0; +} diff --git a/apps/nexus/remapping.h b/apps/nexus/remapping.h new file mode 100644 index 00000000..0aef8bae --- /dev/null +++ b/apps/nexus/remapping.h @@ -0,0 +1,55 @@ +#ifndef NXS_REMAPPING_H +#define NXS_REMAPPING_H + +#include +#include +#include "nxstypes.h" +#include "vchain.h" +#include "vfile.h" + +namespace nxs { + + struct BlockEntry { + BlockEntry(int64 o = 0, unsigned int s = 0): offset(o), size(s) {} + int64 offset; + unsigned int size; + }; + + class BlockIndex: public std::vector { + public: + bool Save(const std::string &file); + bool Load(const std::string &file); + }; + + void Remap(VChain &chain, + VFile &points, + VFile &remap, + BlockIndex &index, + unsigned int target_size, + unsigned int min_size, + unsigned int max_size, + float scaling, + int step); + + void BuildPartition(VPartition &part, + VFile &points, + unsigned int target_size, + unsigned int min_size, + unsigned int max_size, + int steps); + + //removes small or really big patches. + bool Optimize(VPartition &part, + unsigned int target_size, + unsigned int min_size, + unsigned int max_size, + std::vector ¢roids, + std::vector &counts, + bool join); + + int GetBest(VPartition &part, unsigned int seed, + std::vector &mark, + std::vector &counts); +} + +#endif diff --git a/apps/nexus/vchain.cpp b/apps/nexus/vchain.cpp new file mode 100644 index 00000000..f04f849d --- /dev/null +++ b/apps/nexus/vchain.cpp @@ -0,0 +1,100 @@ +#include "vchain.h" +#include +#include + +using namespace std; +using namespace vcg; +using namespace nxs; + +bool VChain::Save(const string &file) { + FILE *fp = fopen(file.c_str(), "wb+"); + if(!fp) { + cerr << "Could not save vchain data.\n"; + return false; + } + + unsigned int nlevels = size(); + fwrite(&nlevels, sizeof(unsigned int), 1, fp); + for(int i = 0; i < nlevels; i++) { + VPartition &level = operator[](i); + unsigned int npoints = level.size(); + fwrite(&npoints, sizeof(unsigned int), 1, fp); + fwrite(&(level[0]), sizeof(Point3f), npoints, fp); + } + //writing fragments + + unsigned int nfrag = newfragments.size(); + fwrite(&nfrag, sizeof(unsigned int), 1, fp); + + std::map >::iterator i; + for(i = newfragments.begin(); i != newfragments.end(); i++) { + unsigned int n = (*i).second.size(); + fwrite(&((*i).first), sizeof(unsigned int), 1, fp); + fwrite(&n, sizeof(unsigned int), 1, fp); + set::iterator k; + for(k = (*i).second.begin(); k != (*i).second.end(); k++) + fwrite(&*k, sizeof(unsigned int), 1, fp); + } + nfrag = oldfragments.size(); + fwrite(&nfrag, sizeof(unsigned int), 1, fp); + + for(i = oldfragments.begin(); i != oldfragments.end(); i++) { + unsigned int n = (*i).second.size(); + fwrite(&((*i).first), sizeof(unsigned int), 1, fp); + fwrite(&n, sizeof(unsigned int), 1, fp); + set::iterator k; + for(k = (*i).second.begin(); k != (*i).second.end(); k++) + fwrite(&*k, sizeof(unsigned int), 1, fp); + } + fclose(fp); + return true; +} + +bool VChain::Load(const string &file) { + FILE *fp = fopen(file.c_str(), "rb"); + if(!fp) { + cerr << "Could not load vchain data\n"; + return false; + } + unsigned int nlevels; + fread(&nlevels, sizeof(unsigned int), 1, fp); + for(int i = 0; i < nlevels; i++) { + push_back(VPartition()); + VPartition &level = back(); + + unsigned int npoints; + fread(&npoints, sizeof(unsigned int), 1, fp); + level.resize(npoints); + fread(&(level[0]), sizeof(Point3f), npoints, fp); + level.Init(); + } + //reading fragments + unsigned int nfrag; + fread(&nfrag, sizeof(unsigned int), 1, fp); + for(unsigned int i = 0; i < nfrag; i++) { + unsigned int p, n; + fread(&p, sizeof(unsigned int), 1, fp); + set &s = newfragments[p]; + fread(&n, sizeof(unsigned int), 1, fp); + for(unsigned int k = 0; k < n; k++) { + unsigned int j; + fread(&j, sizeof(unsigned int), 1, fp); + s.insert(j); + } + } + + fread(&nfrag, sizeof(unsigned int), 1, fp); + for(unsigned int i = 0; i < nfrag; i++) { + unsigned int p, n; + fread(&p, sizeof(unsigned int), 1, fp); + set &s = oldfragments[p]; + fread(&n, sizeof(unsigned int), 1, fp); + for(unsigned int k = 0; k < n; k++) { + unsigned int j; + fread(&j, sizeof(unsigned int), 1, fp); + s.insert(j); + } + } + fclose(fp); + return true; +} diff --git a/apps/nexus/vchain.h b/apps/nexus/vchain.h new file mode 100644 index 00000000..163fc480 --- /dev/null +++ b/apps/nexus/vchain.h @@ -0,0 +1,21 @@ +#ifndef NXS_VCHAIN_H +#define NXS_VCHAIN_H + +#include +#include +#include +#include "vpartition.h" + +namespace nxs { + +class VChain: public std::vector { + public: + bool Save(const std::string &file); + bool Load(const std::string &file); + + std::map > newfragments; + std::map > oldfragments; +}; + +} +#endif diff --git a/apps/nexus/vfile.h b/apps/nexus/vfile.h index 3fe2ea85..45c99cc1 100644 --- a/apps/nexus/vfile.h +++ b/apps/nexus/vfile.h @@ -24,6 +24,9 @@ History $Log: not supported by cvs2svn $ +Revision 1.16 2004/11/28 04:12:04 ponchio +winsockapi include problem + Revision 1.15 2004/11/18 18:30:14 ponchio Using baricenters... lotsa changes. @@ -147,7 +150,7 @@ template class VFile: public MFile { return MFile::Create(filename); } - bool Load(const std:: string &filename, + bool Load(const std:: string &filename, bool rdonly = false, unsigned int _chunk_size = 4096/sizeof(T), unsigned int _queue_size = 1000) { @@ -156,7 +159,7 @@ template class VFile: public MFile { chunk_size = _chunk_size; queue_size = _queue_size; - if(!MFile::Load(filename)) return false; + if(!MFile::Load(filename, rdonly)) return false; n_elements = size/sizeof(T); return true; } diff --git a/apps/nexus/voronoinxs.cpp b/apps/nexus/voronoinxs.cpp index 38da39f3..43fe9abe 100644 --- a/apps/nexus/voronoinxs.cpp +++ b/apps/nexus/voronoinxs.cpp @@ -24,78 +24,6 @@ History $Log: not supported by cvs2svn $ -Revision 1.24 2004/11/28 07:58:49 ponchio -*** empty log message *** - -Revision 1.23 2004/11/28 01:23:26 ponchio -Fixing borders... let's hope. - -Revision 1.22 2004/11/18 18:30:15 ponchio -Using baricenters... lotsa changes. - -Revision 1.21 2004/11/03 16:31:38 ponchio -Trying to fix big patches. - -Revision 1.20 2004/10/30 20:17:03 ponchio -Fixed big patches problem. - -Revision 1.19 2004/10/22 10:37:32 ponchio -Split is now in fragment. - -Revision 1.18 2004/10/21 13:40:16 ponchio -Debugging. - -Revision 1.17 2004/10/21 12:22:21 ponchio -Small changes. - -Revision 1.16 2004/10/19 01:23:02 ponchio -Daily backup (fragment...) - -Revision 1.15 2004/10/15 11:41:03 ponchio -Tests and small changes. - -Revision 1.14 2004/10/10 17:19:42 ponchio -Added compression and debugged. - -Revision 1.13 2004/10/09 17:32:25 ponchio -Ram buffer option added (last) - -Revision 1.12 2004/10/09 17:29:04 ponchio -Ram buffer option added (again) - -Revision 1.11 2004/10/09 17:22:57 ponchio -Ram buffer option added. - -Revision 1.10 2004/10/09 16:51:36 ponchio -Windows porting small changes. - -Revision 1.9 2004/10/08 15:12:04 ponchio -Working version (maybe) - -Revision 1.8 2004/10/06 16:40:47 ponchio -Fixed degenerate faces. - -Revision 1.7 2004/10/04 16:49:54 ponchio -Daily backup. Preparing for compression. - -Revision 1.6 2004/10/01 16:54:57 ponchio -Daily backup. - -Revision 1.5 2004/09/30 00:27:42 ponchio -Lot of changes. Backup. - -Revision 1.4 2004/09/21 00:53:23 ponchio -Lotsa changes. - -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). - -Revision 1.1 2004/08/26 18:03:48 ponchio -First draft. - ****************************************************************************/ @@ -106,58 +34,119 @@ First draft. #endif #include -#include -using namespace std; +#include "nxstypes.h" #include "crude.h" -#include "nexus.h" - -#include "voronoichain.h" -#include "vert_remap.h" - +#include "remapping.h" #include "decimate.h" -#include "fragment.h" -#include "nxsbuild.h" -#include "watch.h" -#include "nxsdispatcher.h" -#include +using namespace std; using namespace vcg; using namespace nxs; +/*struct PIndex { + int64 offset; + unsigned int lenght; +}; -void BuildFragment(Nexus &nexus, VoronoiPartition &part, - set &patches, - Fragment &fragment); +class FaceIndex: public std::vector {};*/ -void SaveFragment(Nexus &nexus, VoronoiChain &chain, - Fragment &fragin, - Fragment &fragout); -void ReverseHistory(vector &history); +void usage() { + cerr << "Usage: voronoinxs [options]\n" + " Options:\n" + " -f N: use N faces per patch (default 1000, max 32000)\n" + " -t N: mini faces per patch (default 200)\n" + " -l N: number of levels\n" + " -s F: scaling factor (0 < F < 1, default 0.5)\n" + " -o N: number of optimization steps\n" + " -d : decimation method: quadric, cluster. (default quadric)\n" + " -b N: ram buffer size (in bytes)\n" + " -p N: which fase perform:\n" + " 0) Remap faces\n" + " 1) Sort faces\n" + " 2) Build patches\n" + " 3) Build borders\n" + " 4) Build levels\n\n" + " If you use the step option, all other parameters MUST stay the same\n\n"; -void TestBorders(Nexus &nexus); -void TestPatches(Nexus &nexus); +} -unsigned int current_level; -vector patch_levels; +void FirstStep(const string &crudefile, const string &output, + unsigned int patch_size, unsigned int patch_threshold, + float scaling, unsigned int optimization_steps) { + Crude crude; + + if(!crude.Load(crudefile, true)) { + cerr << "Could not open crude input: " << crudefile << endl; + exit(0); + } + + if(patch_size > crude.vert.Size()/2) { + cerr << "Patch size too big: " << patch_size << " * 2 > " + << crude.vert.Size() << endl; + exit(0); + } + + if(patch_threshold == 0xffffffff) + patch_threshold = patch_size/4; + + + VChain vchain; + + VFile face_remap; + if(!face_remap.Create(output + ".rmf")) { + cerr << "Could not create remap files: " << output << ".rmf\n"; + exit(0); + } + face_remap.Resize(crude.Faces()); + + VFile baricenters; + if(!baricenters.Create(output + string(".bvr"))) { + cerr << "Could not create temporary baricenters file\n"; + exit(0); + } + baricenters.Resize(crude.Faces()); + for(unsigned int i = 0; i < crude.Faces(); i++) { + baricenters[i] = crude.GetBari(i); + } + + BlockIndex face_index; + + Remap(vchain, baricenters, face_remap, face_index, + patch_size, patch_threshold, 65000, scaling, + optimization_steps); + + if(!vchain.Save(output + ".vchain")) { + cerr << "Could not save file: " << output << ".vchain\n"; + exit(0); + } + if(!face_index.Save(output + ".rmi")) { + cerr << "Could not save file: " << output << ".rmi\n"; + exit(0); + } + + baricenters.Delete(); +} int main(int argc, char *argv[]) { + + /* Parameters: */ + unsigned int patch_size = 1000; //step 0 + unsigned int patch_threshold = 0xffffffff; //Step 0 + float scaling = 0.5; //step 0, 4 + unsigned int optimization_steps = 5; //step 0, 4 - Decimation decimation = CLUSTER; - unsigned int patch_size = 1000; - unsigned int patch_threshold = 0xffffffff; - unsigned int optimization_steps = 5; - bool stop_after_remap = false; - bool skip_remap = false; - unsigned int max_level = 0xffffffff; - float scaling = 0.5; - unsigned int ram_buffer = 128000000; - unsigned int chunk_size = 1024; + Decimation decimation = CLUSTER; //step 4 + unsigned int max_level = 0xffffffff; //step 4 + unsigned int ram_buffer = 128000000; //step 2, 3, 4 + unsigned int chunk_size = 1024; //step 2, 3, 4 + int step = -1; //means all of them. + int option; - while((option = getopt(argc, argv, "f:t:l:s:d:rko:b:c:")) != EOF) { + while((option = getopt(argc, argv, "f:t:l:s:d:o:b:c:p:")) != EOF) { switch(option) { case 'f': patch_size = atoi(optarg); if(patch_size == 0 || patch_size > 32000) { @@ -193,9 +182,8 @@ int main(int argc, char *argv[]) { return -1; } break; - case 'r': stop_after_remap = true; break; - case 'k': skip_remap = true; break; case 'o': optimization_steps = atoi(optarg); break; + case 'p': step = atoi(optarg); break; case 'b': ram_buffer = atoi(optarg); if(ram_buffer == 0) { cerr << "Invalid ram buffer: " << optarg << endl; @@ -213,586 +201,17 @@ int main(int argc, char *argv[]) { } } - //Test that there are still 2 arguments - if(optind != argc - 2) { - cerr << "Usage: " << argv[0] << " [options]\n"; - cerr << " Options:\n"; - cerr << " -f N: use N faces per patch (default 1000, max 32000)\n"; - 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"; - cerr << " -o N: nomber of optimization steps\n"; - cerr << " -d : decimation method: quadric, cluster. (default quadric)\n"; - cerr << " -b N: ram buffer size (in bytes)\n"; - cerr << " -r : stop after remapping fase\n"; - cerr << " -k : skip remapping fase\n"; + if(optind != argc -2) { + usage(); return -1; } - - Crude crude; - if(!crude.Load(argv[optind])) { - cerr << "Could not open crude input: " << argv[optind] << endl; - return -1; - } - - if(patch_size > crude.vert.Size()/2) { - cerr << "Patch size too big: " << patch_size << " * 2 > " << crude.vert.Size() - << endl; - return -1; - } - + string crudefile = argv[optind]; string output = argv[optind+1]; - Nexus nexus; - nexus.patches.SetRamBufferSize(ram_buffer); - if(!nexus.Create(output, NXS_FACES, chunk_size)) { - cerr << "Could not create nexus output: " << output << endl; - return -1; - } + if(step < 0 || step == 0) + FirstStep(crudefile, output, patch_size, patch_threshold, + scaling, optimization_steps); - - if(patch_threshold == 0xffffffff) - patch_threshold = patch_size/4; - - VoronoiChain vchain(patch_size, patch_threshold); - // vchain.scaling = scaling; - - //Now building level 0 of the Nexus - - VFile face_remap; - VertRemap vert_remap; - VFile border_remap; - VFile baricenters; - vector patch_faces; - vector patch_verts; - - if(skip_remap) { - if(!face_remap.Load(output + ".rmf")) { - cerr << "Could not cload remap files: " << output << ".rmf\n"; - return -1; - } - - if(!vert_remap.Load(output)) { - cerr << "Could not load remap file: " << output << ".rmv and .rmb\n"; - return -1; - } - - if(!border_remap.Load(output + string(".tmp"))) { - cerr << "Could not load temporary border remap file\n"; - return -1; - } - - if(!baricenters.Load(output + string(".bvr"))) { - cerr << "Could not create temporary baricenters file\n"; - return -1; - } - //fine, coarse, patch_faces, patch_vert - FILE *fp = fopen((output + ".remap").c_str(), "rb"); - if(!fp) { - cerr << "Could not open remapping info\n"; - return -1; - } - unsigned int fine_size, coarse_size, pfaces_size, pvert_size; - fread(&fine_size, sizeof(unsigned int), 1, fp); - fread(&coarse_size, sizeof(unsigned int), 1, fp); - fread(&pfaces_size, sizeof(unsigned int), 1, fp); - fread(&pvert_size, sizeof(unsigned int), 1, fp); - vchain.levels.push_back(VoronoiPartition()); - vchain.levels.push_back(VoronoiPartition()); - VoronoiPartition &fine = vchain.levels[0]; - VoronoiPartition &coarse = vchain.levels[1]; - cerr << "fine_size: " << fine_size << endl; - cerr << "coarse_size: " << fine_size << endl; - fine.resize(fine_size); - fread(&(fine[0]), sizeof(Point3f), fine_size, fp); - fine.Init(); - coarse.resize(coarse_size); - fread(&(coarse[0]), sizeof(Point3f), coarse_size, fp); - coarse.Init(); - patch_faces.resize(pfaces_size); - fread(&(patch_faces[0]), sizeof(unsigned int), pvert_size, fp); - patch_verts.resize(pvert_size); - fread(&(patch_verts[0]), sizeof(unsigned int), pvert_size, fp); - - unsigned int nfrag; - fread(&nfrag, sizeof(unsigned int), 1, fp); - for(unsigned int i = 0; i < nfrag; i++) { - unsigned int p, n; - fread(&p, sizeof(unsigned int), 1, fp); - set &s = vchain.newfragments[p]; - fread(&n, sizeof(unsigned int), 1, fp); - for(unsigned int k = 0; k < n; k++) { - unsigned int j; - fread(&j, sizeof(unsigned int), 1, fp); - s.insert(j); - } - - } - - fread(&nfrag, sizeof(unsigned int), 1, fp); - for(unsigned int i = 0; i < nfrag; i++) { - unsigned int p, n; - fread(&p, sizeof(unsigned int), 1, fp); - set &s = vchain.oldfragments[p]; - fread(&n, sizeof(unsigned int), 1, fp); - for(unsigned int k = 0; k < n; k++) { - unsigned int j; - fread(&j, sizeof(unsigned int), 1, fp); - s.insert(j); - } - - } - - fclose(fp); - - } else { - if(!face_remap.Create(output + ".rmf")) { - cerr << "Could not create remap files: " << output << ".rmf\n"; - return -1; - } - face_remap.Resize(crude.Faces()); - - if(!vert_remap.Create(output)) { - cerr << "Could not create remap file: " << output << ".rmv and .rmb\n"; - return -1; - } - vert_remap.Resize(crude.Vertices()); - - if(!border_remap.Create(output + string(".tmp"))) { - cerr << "Could not create temporary border remap file\n"; - return -1; - } - - if(!baricenters.Create(output + string(".bvr"))) { - cerr << "Could not create temporary baricenters file\n"; - return -1; - } - baricenters.Resize(crude.Faces()); - - //TODO use some smarter rule :P - for(unsigned int i = 0; i < crude.Faces(); i++) { - baricenters[i] = crude.GetBari(i); - } - /* BUILDING FIRST LEVEL */ - - //Remapping faces and vertices using level 0 and 1 of the chain - cerr << "Remapping faces.\n"; - - - vchain.RemapFaces(baricenters, face_remap, patch_faces, - scaling, optimization_steps); - - cerr << "Remapping vertices.\n"; - - patch_verts.resize(patch_faces.size(), 0); - RemapVertices(crude, vert_remap, face_remap, patch_verts); - } - - if(stop_after_remap) { - //fine, coarse, patch_faces, patch_vert - FILE *fp = fopen((output + ".remap").c_str(), "wb+"); - if(!fp) { - cerr << "Could not create remapping info\n"; - return -1; - } - VoronoiPartition &fine = vchain.levels[0]; - VoronoiPartition &coarse = vchain.levels[1]; - - unsigned int fine_size = fine.size(); - unsigned int coarse_size = coarse.size(); - unsigned int pfaces_size = patch_faces.size(); - unsigned int pvert_size = patch_verts.size(); - fwrite(&fine_size, sizeof(unsigned int), 1, fp); - fwrite(&coarse_size, sizeof(unsigned int), 1, fp); - fwrite(&pfaces_size, sizeof(unsigned int), 1, fp); - fwrite(&pvert_size, sizeof(unsigned int), 1, fp); - - fwrite(&(fine[0]), sizeof(Point3f), fine_size, fp); - fwrite(&(coarse[0]), sizeof(Point3f), coarse_size, fp); - fwrite(&(patch_faces[0]), sizeof(unsigned int), pvert_size, fp); - fwrite(&(patch_verts[0]), sizeof(unsigned int), pvert_size, fp); - - unsigned int nfrag = vchain.newfragments.size(); - fwrite(&nfrag, sizeof(unsigned int), 1, fp); - std::map >::iterator i; - for(i = vchain.newfragments.begin(); i != vchain.newfragments.end(); i++) { - unsigned int n = (*i).second.size(); - fwrite(&((*i).first), sizeof(unsigned int), 1, fp); - fwrite(&n, sizeof(unsigned int), 1, fp); - set::iterator k; - for(k = (*i).second.begin(); k != (*i).second.end(); k++) - fwrite(&*k, sizeof(unsigned int), 1, fp); - } - nfrag = vchain.oldfragments.size(); - fwrite(&nfrag, sizeof(unsigned int), 1, fp); - for(i = vchain.oldfragments.begin(); i != vchain.oldfragments.end(); i++) { - unsigned int n = (*i).second.size(); - fwrite(&((*i).first), sizeof(unsigned int), 1, fp); - fwrite(&n, sizeof(unsigned int), 1, fp); - set::iterator k; - for(k = (*i).second.begin(); k != (*i).second.end(); k++) - fwrite(&*k, sizeof(unsigned int), 1, fp); - } - fclose(fp); - return 0; - } - - - - cerr << "Allocating space\n"; - //allocate chunks for patches and copy faces (absoklute indexing) into them. - NexusAllocate(crude, nexus, face_remap, patch_faces, patch_verts); - - cerr << "Filling first level\n"; - face_remap.Flush(); - vert_remap.all.Flush(); - vert_remap.borders.buffer.Flush(); - border_remap.Flush(); - baricenters.Flush(); - //insert vertices and remap faces, prepare borders - NexusFill(crude, nexus, vert_remap, border_remap); - - //Now face_remap, vert_remap, border_remap can be deleted! - face_remap.Delete(); - vert_remap.Delete(); - border_remap.Delete(); - baricenters.Delete(); - - - - //filling history - Nexus::Update update; - for(unsigned int i = 0; i < nexus.index.size(); i++) { - update.created.push_back(i); - patch_levels.push_back(0); - } - nexus.history.push_back(update); - - //unify vertices otherwise you may get cracks. - nexus.Unify(); - nexus.patches.FlushAll(); - - /* BUILDING OTHER LEVELS */ - - Report report; - Dispatcher dispatcher(&nexus, &vchain); - dispatcher.mode = decimation; - dispatcher.scaling = scaling; - if(!dispatcher.Init("servers.txt")) { - cerr << "Could not parse server file: " << "servers.txt" - << " proceding locally\n"; - } - - unsigned int oldoffset = 0; - for(unsigned int level = 1; level < max_level; level++) { - current_level = level; - cerr << "Level: " << level << endl; - - unsigned int newoffset = nexus.index.size(); - vchain.BuildLevel(nexus, oldoffset, scaling, optimization_steps); - - report.Init(vchain.oldfragments.size(), 1); - unsigned int fcount = 0; - map >::iterator fragment; - for(fragment = vchain.oldfragments.begin(); - fragment != vchain.oldfragments.end(); fragment++) { - report.Step(fcount++); - - Fragment *fragin = new Fragment; - BuildFragment(nexus, vchain.levels[level+1], - (*fragment).second, *fragin); - - dispatcher.SendFragment(fragin); - - - /* - //this can be executed on a remote host - - //TODO move this part to remote.... - vector newvert; - vector newface; - vector newbord; - Join(fragin, newvert, newface, newbord); - - float error = Decimate(decimation, - (unsigned int)((newface.size()/3) * scaling), - newvert, newface, newbord); - Fragment fragout; - fragout.error = error; - fragout.id = fragin.id; - fragout.seeds = fragin.seeds; - fragout.seeds_id = fragin.seeds_id; - Split(fragout, newvert, newface, newbord);//, vchain.levels[level+1]); - - - SaveFragment(nexus, vchain, fragin, fragout); - */ - dispatcher.processmsgs(); - } - //TODO porcata!!!! - while(dispatcher.frags.size()) { - // cerr << "frags: " << dispatcher.frags.size() << endl; - dispatcher.processmsgs(); - } - - report.Finish(); - - if(vchain.oldfragments.size() == 1) break; - - vchain.oldfragments = vchain.newfragments; - oldoffset = newoffset; - } - - //last level clean history: - update.created.clear(); - update.erased.clear(); - map >::iterator fragment; - for(fragment = vchain.newfragments.begin(); - fragment != vchain.newfragments.end(); fragment++) { - set &fcells = (*fragment).second; - set::iterator s; - for(s = fcells.begin(); s != fcells.end(); s++) - update.erased.push_back(*s); - } - nexus.history.push_back(update); - ReverseHistory(nexus.history); - - // TestBorders(nexus); - nexus.Close(); - - //TODO remove vert_remap, face_remap, border_remap return 0; } -pt::mutex nlock; - -void BuildFragment(Nexus &nexus, VoronoiPartition &part, - set &patches, - Fragment &fragment) { - - set::iterator f; - for(f = patches.begin(); f != patches.end(); f++) { - fragment.pieces.push_back(NxsPatch()); - NxsPatch &nxs = fragment.pieces.back(); - nxs.patch = *f; - - Patch &patch = nexus.GetPatch(*f); - Border border = nexus.GetBorder(*f); - - for(unsigned int k = 0; k < patch.nf; k++) { - assert(patch.Face(k)[0] != patch.Face(k)[1]); - assert(patch.Face(k)[0] != patch.Face(k)[2]); - assert(patch.Face(k)[1] != patch.Face(k)[2]); - } - - - nxs.vert.resize(patch.nv); - nxs.face.resize(patch.nf * 3); - memcpy(&*nxs.vert.begin(), patch.VertBegin(), patch.nv * sizeof(Point3f)); - memcpy(&*nxs.face.begin(), patch.FaceBegin(), patch.nf * 3*sizeof(short)); - for(unsigned int i = 0; i < border.Size(); i++) { - Link &link = border[i]; - if(!link.IsNull() && - patch_levels[link.end_patch] == current_level-1) { - assert(link.end_patch != *f); - nxs.bord.push_back(link); - } - } - } - - set seeds; - vector nears; - vector dists; - int nnears = 10; - if(part.size() < 10) nnears = part.size(); - for(f = patches.begin(); f != patches.end(); f++) { - Point3f ¢er = nexus.index[*f].sphere.Center(); - part.Closest(center, nnears, nears, dists); - for(int i = 0; i < nnears; i++) - seeds.insert(nears[i]); - } - for(f = seeds.begin(); f != seeds.end(); f++) { - Point3f &p = part[*f]; - fragment.seeds.push_back(p); - fragment.seeds_id.push_back(*f); - } -} - - - -void SaveFragment(Nexus &nexus, VoronoiChain &chain, - Fragment &fragin, - Fragment &fragout) { - - set orig_patches; - - Nexus::Update update; - for(unsigned int i = 0; i < fragin.pieces.size(); i++) { - NxsPatch &patch = fragin.pieces[i]; - update.erased.push_back(patch.patch); - orig_patches.insert(patch.patch); - } - - vector patch_remap; - patch_remap.resize(fragout.pieces.size()); - - for(unsigned int i = 0; i < fragout.pieces.size(); i++) { - NxsPatch &patch = fragout.pieces[i]; - //TODO detect best parameter below for bordersize... - unsigned int bordsize = 6 * patch.bord.size(); - if(bordsize > 65500) bordsize = 65499; - unsigned int patch_idx = nexus.AddPatch(patch.vert.size(), - patch.face.size()/3, - bordsize); - patch_levels.push_back(current_level); - Nexus::PatchInfo &entry = nexus.index[patch_idx]; - entry.error = fragout.error; - - patch_remap[i] = patch_idx; - chain.newfragments[patch.patch].insert(patch_idx); - update.created.push_back(patch_idx); - } - - //here i put for every patch all its new links. - map > newlinks; - - for(unsigned int i = 0; i < fragout.pieces.size(); i++) { - NxsPatch &outpatch = fragout.pieces[i]; - unsigned int patch_idx = patch_remap[i]; - - for(unsigned int k = 0; k < outpatch.face.size(); k += 3) { - assert(k+2 < outpatch.face.size()); - assert(outpatch.face[k] != outpatch.face[k+1]); - assert(outpatch.face[k] != outpatch.face[k+2]); - assert(outpatch.face[k+1] != outpatch.face[k+2]); - } - - Patch &patch = nexus.GetPatch(patch_idx); - memcpy(patch.FaceBegin(), &outpatch.face[0], - outpatch.face.size() * sizeof(unsigned short)); - memcpy(patch.VertBegin(), &outpatch.vert[0], - outpatch.vert.size() * sizeof(Point3f)); - - Nexus::PatchInfo &entry = nexus.index[patch_idx]; - for(unsigned int v = 0; v < outpatch.vert.size(); v++) { - entry.sphere.Add(outpatch.vert[v]); - nexus.sphere.Add(outpatch.vert[v]); - } - - //remap internal borders - for(unsigned int k = 0; k < outpatch.bord.size(); k++) { - Link &link = outpatch.bord[k]; - if(link.end_patch >= (1<<31)) { //internal - link.end_patch = patch_remap[link.end_patch - (1<<31)]; - assert(link.end_patch != patch_remap[i]); - newlinks[patch_idx].insert(link); - } - } - //TODO not efficient! - //processing external borders - for(unsigned int l = 0; l < outpatch.bord.size(); l++) { - Link &link = outpatch.bord[l]; - if(link.end_patch >= (1<<31)) continue; - - unsigned short &start_vert = link.start_vert; - unsigned int &start_patch = patch_idx; - - //Adding vertical connection - newlinks[patch_idx].insert(link); - - Link up(link.end_vert, link.start_vert, patch_idx); - newlinks[link.end_patch].insert(up); - - Border cborder = nexus.GetBorder(link.end_patch); - for(unsigned int k = 0; k < cborder.Size(); k++) { - - Link &clink = cborder[k]; - assert(!clink.IsNull()); - - if(clink.start_vert != link.end_vert) continue; - if(patch_levels[clink.end_patch] < current_level-1) continue; - //boy i want only the external links! - if(orig_patches.count(clink.end_patch)) continue; - - unsigned short &end_vert = clink.end_vert; - unsigned int &end_patch = clink.end_patch; - - //TODO FIX THIS!!!! - assert(clink.end_patch != start_patch); - assert(clink.end_patch != link.end_patch); - - Link newlink; - - newlink.start_vert = start_vert; - newlink.end_vert = end_vert; - newlink.end_patch = end_patch; - - newlinks[patch_idx].insert(newlink); - - newlink.start_vert = end_vert; - newlink.end_vert = start_vert; - newlink.end_patch = start_patch; - - newlinks[end_patch].insert(newlink); - } - } - } - map >::iterator n; - for(n = newlinks.begin(); n != newlinks.end(); n++) { - set::iterator l; - unsigned int patch = (*n).first; - set &links = (*n).second; - Border border = nexus.GetBorder(patch); - unsigned int bstart = border.Size(); - - if(nexus.borders.ResizeBorder(patch, border.Size() + links.size())) - border = nexus.GetBorder(patch); - for(l = links.begin(); l != links.end(); l++) { - Link link = *l; - border[bstart++] = link; - } - } - nexus.history.push_back(update); -} - -void ReverseHistory(vector &history) { - std::reverse(history.begin(), history.end()); - vector::iterator i; - for(i = history.begin(); i != history.end(); i++) - swap((*i).erased, (*i).created); -} - -void TestPatches(Nexus &nexus) { - cerr << "TESTING PATCHES!!!!" << endl; - for(unsigned int p = 0; p < nexus.index.size(); p++) { - Patch &patch = nexus.GetPatch(p); - for(unsigned int i = 0; i < patch.nf; i++) - for(int k = 0; k < 3; k++) - if(patch.Face(i)[k] >= patch.nv) { - cerr << "Totface: " << patch.nf << endl; - cerr << "Totvert: " << patch.nv << endl; - cerr << "Face: " << i << endl; - cerr << "Val: " << patch.Face(i)[k] << endl; - exit(0); - } - } -} -void TestBorders(Nexus &nexus) { - //check border correctnes - nexus.borders.Flush(); - for(unsigned int i = 0; i < nexus.index.size(); i++) { - Border border = nexus.GetBorder(i); - for(unsigned int k = 0; k < border.Size(); k++) { - Link &link = border[k]; - if(link.IsNull()) continue; - if(link.end_patch >= nexus.index.size()) { - cerr << "Patch: " << i << endl; - cerr << "Bsize: " << border.Size() << endl; - cerr << "Bava: " << border.Available() << endl; - cerr << "K: " << k << endl; - cerr << "end: " << link.end_patch << endl; - } - assert(link.end_patch < nexus.index.size()); - } - } -} diff --git a/apps/nexus/vpartition.cpp b/apps/nexus/vpartition.cpp new file mode 100644 index 00000000..4d856470 --- /dev/null +++ b/apps/nexus/vpartition.cpp @@ -0,0 +1,116 @@ +/**************************************************************************** +* VCGLib o o * +* Visual and Computer Graphics Library o o * +* _ O _ * +* Copyright(C) 2004 \/)\/ * +* 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. * +* * +****************************************************************************/ +/**************************************************************************** + History + +$Log: not supported by cvs2svn $ + +****************************************************************************/ + +#include + +#include "vpartition.h" +#include + +using namespace std; +using namespace vcg; +using namespace nxs; + +void VPartition::Init() { + if(bd) delete bd; + buffer.resize(size() * 3); + for(unsigned int i = 0; i < size(); i++) { + for(int k = 0; k < 3; k++) + buffer[i*3+k] = operator[](i)[k]; + } + points.resize(size()); + for(unsigned int i = 0; i < size(); i++) { + points[i] = &buffer[i*3]; + } + bd = new ANNkd_tree(&*points.begin(), size(), 3); +} + +void VPartition::Closest(const vcg::Point3f &p, unsigned int nsize, + vector &nears, + vector &dist) { + double point[3]; + point[0] = p[0]; + point[1] = p[1]; + point[2] = p[2]; + + nears.resize(nsize); + dist.resize(nsize); + vector dists; + dists.resize(nsize); + bd->annkSearch(&point[0], nsize, &*nears.begin(), &*dists.begin()); + for(unsigned int i = 0; i < nsize; i++) + dist[i] = (float)dists[i]; +} + +void VPartition::Closest(const vcg::Point3f &p, + int &target, float &dist) { + double point[3]; + point[0] = p[0]; + point[1] = p[1]; + point[2] = p[2]; + double dists; + bd->annkSearch(&point[0], 1, &target, &dists, 1); + assert(target >= 0); + assert(target < size()); + + dist = (float)dists; +} + +int VPartition::Locate(const vcg::Point3f &p) { + + double point[3]; + point[0] = p[0]; + point[1] = p[1]; + point[2] = p[2]; + + int target = -1; + double dists; + bd->annkSearch(&point[0], 1, &target, &dists, 1); + + return target; +} + +float VPartition::Radius(unsigned int seed) { + assert(size() > 1); + int nears[2]; + double dists[2]; + + double point[3]; + Point3f &p = operator[](seed); + point[0] = p[0]; + point[1] = p[1]; + point[2] = p[2]; + + bd->annkSearch(&point[0], 2, nears, dists); + + if(dists[1] == 0) return 0.0f; + assert(nears[0] == seed); + assert(dists[0] == 0); + + return (float)sqrt(dists[1]); +} diff --git a/apps/nexus/vpartition.h b/apps/nexus/vpartition.h new file mode 100644 index 00000000..4b18f5a3 --- /dev/null +++ b/apps/nexus/vpartition.h @@ -0,0 +1,69 @@ +/**************************************************************************** +* VCGLib o o * +* Visual and Computer Graphics Library o o * +* _ O _ * +* Copyright(C) 2004 \/)\/ * +* 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. * +* * +****************************************************************************/ +/**************************************************************************** + History + +$Log: not supported by cvs2svn $ + +****************************************************************************/ + +#ifndef NXS_VPARTITION_H +#define NXS_VPARTITION_H + +#include +#include + +#include + + +//TODO provide a Sort function, to sort spatially the seeds. + +class ANNkd_tree; +class ANNbd_tree; +class ANNbruteForce; + +namespace nxs { + +class VPartition: public std::vector { + public: + VPartition(): bd(NULL) {} + void Init(); + int Locate(const vcg::Point3f &p); + + //looks for the min distance point from seed. + float Radius(unsigned int seed); + void Closest(const vcg::Point3f &p, unsigned int nsize, + std::vector &nears, + std::vector &dist); + void Closest(const vcg::Point3f &p, + int &target, float &dist); + + + + ANNkd_tree *bd; + std::vector buffer; + std::vector points; +}; + +} //namespace nxs +#endif