vcglib/apps/nexus/nexus.cpp

377 lines
11 KiB
C++
Raw Normal View History

2004-07-02 15:00:02 +02:00
#include <iostream>
2004-09-17 17:25:59 +02:00
#include <assert.h>
2004-07-02 15:00:02 +02:00
#include "nexus.h"
using namespace std;
using namespace vcg;
using namespace nxs;
Nexus::Nexus(): index_file(NULL) {}
Nexus::~Nexus() {
Close();
}
2004-10-10 19:19:42 +02:00
bool Nexus::Create(const string &file, Signature sig, unsigned int c_size) {
2004-07-02 15:00:02 +02:00
index_file = fopen((file + ".nxs").c_str(), "wb+");
if(!index_file) {
cerr << "Could not create file: " << file << ".nxs\n";
return false;
}
2004-09-16 16:25:16 +02:00
signature = sig;
2004-07-02 15:00:02 +02:00
totvert = 0;
totface = 0;
sphere = Sphere3f();
2004-09-16 16:25:16 +02:00
index.clear();
2004-07-02 15:00:02 +02:00
2004-10-10 19:19:42 +02:00
chunk_size = c_size;
2004-10-08 16:46:26 +02:00
if(!patches.Create(file + ".nxp", signature, chunk_size)) {
2004-07-02 15:00:02 +02:00
cerr << "Could not create file: " << file << ".nxp" << endl;
return false;
}
2004-10-08 16:46:26 +02:00
//Important: chunk_size must be 1 so that i can use Region in VFile.
2004-07-04 16:26:46 +02:00
if(!borders.Create(file + ".nxb", 1)) {
cerr << "Could not create file: " << file << ".nxb" << endl;
2004-07-02 15:00:02 +02:00
return false;
}
2004-09-16 16:25:16 +02:00
history.clear();
2004-07-02 15:00:02 +02:00
return true;
}
2004-10-08 16:46:26 +02:00
bool Nexus::Load(const string &file, bool readonly) {
2004-07-02 15:00:02 +02:00
index_file = fopen((file + ".nxs").c_str(), "rb+");
if(!index_file) return false;
unsigned int readed;
2004-09-16 16:25:16 +02:00
readed = fread(&signature, sizeof(unsigned int), 1, index_file);
if(!readed) return false;
2004-07-02 15:00:02 +02:00
readed = fread(&totvert, sizeof(unsigned int), 1, index_file);
if(!readed) return false;
readed = fread(&totface, sizeof(unsigned int), 1, index_file);
if(!readed) return false;
readed = fread(&sphere, sizeof(Sphere3f), 1, index_file);
if(!readed) return false;
2004-10-08 16:46:26 +02:00
readed = fread(&chunk_size, sizeof(unsigned int), 1, index_file);
if(!readed) return false;
2004-07-02 15:00:02 +02:00
unsigned int size; //size of index
readed = fread(&size, sizeof(unsigned int), 1, index_file);
if(!readed) return false;
index.resize(size);
2004-10-08 16:46:26 +02:00
readed = fread(&index[0], sizeof(PatchInfo), size, index_file);
2004-07-02 15:00:02 +02:00
if(readed != size) return false;
2004-10-08 16:46:26 +02:00
patches.ReadEntries(index_file);
borders.ReadEntries(index_file);
2004-09-16 16:25:16 +02:00
//history size;
fread(&size, sizeof(unsigned int), 1, index_file);
vector<unsigned int> buffer;
buffer.resize(size);
fread(&(buffer[0]), sizeof(unsigned int), size, index_file);
//number of history updates
size = buffer[0];
history.resize(size);
unsigned int pos = 1;
for(unsigned int i = 0; i < size; i++) {
unsigned int erased = buffer[pos++];
unsigned int created = buffer[pos++];
history[i].erased.resize(erased);
history[i].created.resize(created);
for(unsigned int e = 0; e < erased; e++)
history[i].erased[e] = buffer[pos++];
for(unsigned int e = 0; e < created; e++)
history[i].created[e] = buffer[pos++];
}
2004-10-08 16:46:26 +02:00
//TODO support readonly
if(!patches.Load(file + ".nxp", signature, chunk_size, readonly))
return false;
2004-07-04 16:26:46 +02:00
if(!borders.Load(file + ".nxb", 1)) return false;
2004-07-02 15:00:02 +02:00
return true;
}
2004-10-09 19:37:45 +02:00
void Nexus::Close() {
2004-10-10 19:19:42 +02:00
patches.Close();
borders.Close();
2004-07-02 15:00:02 +02:00
if(!index_file) return;
rewind(index_file);
2004-09-16 16:25:16 +02:00
fwrite(&signature, sizeof(unsigned int), 1, index_file);
2004-07-02 15:00:02 +02:00
fwrite(&totvert, sizeof(unsigned int), 1, index_file);
fwrite(&totface, sizeof(unsigned int), 1, index_file);
fwrite(&sphere, sizeof(Sphere3f), 1, index_file);
2004-10-08 16:46:26 +02:00
fwrite(&chunk_size, sizeof(unsigned int), 1, index_file);
2004-07-02 15:00:02 +02:00
unsigned int size = index.size(); //size of index
fwrite(&size, sizeof(unsigned int), 1, index_file);
2004-10-08 16:46:26 +02:00
fwrite(&(index[0]), sizeof(PatchInfo), size, index_file);
patches.WriteEntries(index_file);
borders.WriteEntries(index_file);
2004-09-16 16:25:16 +02:00
vector<unsigned int> buffer;
buffer.push_back(history.size());
for(unsigned int i = 0; i < history.size(); i++) {
Update &update = history[i];
buffer.push_back(update.erased.size());
buffer.push_back(update.created.size());
for(unsigned int e = 0; e < update.erased.size(); e++)
buffer.push_back(update.erased[e]);
for(unsigned int e = 0; e < update.created.size(); e++)
buffer.push_back(update.created[e]);
}
size = buffer.size();
fwrite(&size, sizeof(unsigned int), 1, index_file);
fwrite(&(buffer[0]), sizeof(unsigned int), size, index_file);
2004-07-02 15:00:02 +02:00
fclose(index_file);
2004-07-30 15:18:25 +02:00
index_file = NULL;
2004-07-02 15:00:02 +02:00
}
2004-10-08 16:46:26 +02:00
Patch &Nexus::GetPatch(unsigned int patch, bool flush) {
assert(patch < index.size());
PatchInfo &info = index[patch];
return patches.GetPatch(patch, info.nvert, info.nface, flush);
2004-07-04 16:26:46 +02:00
}
2004-10-01 18:54:57 +02:00
Border Nexus::GetBorder(unsigned int patch, bool flush) {
2004-10-08 16:46:26 +02:00
PatchInfo &info = index[patch];
return borders.GetBorder(patch);
2004-07-04 16:26:46 +02:00
}
unsigned int Nexus::AddPatch(unsigned int nvert, unsigned int nface,
unsigned int nbord) {
2004-10-08 16:46:26 +02:00
PatchInfo info;
info.nvert = nvert;
info.nface = nface;
2004-07-04 16:26:46 +02:00
2004-10-08 16:46:26 +02:00
patches.AddPatch(nvert, nface);
borders.AddBorder(nbord);
index.push_back(info);
2004-08-27 02:38:34 +02:00
totvert += nvert;
totface += nface;
2004-07-04 16:26:46 +02:00
return index.size() -1;
}
2004-10-08 16:46:26 +02:00
2004-08-27 02:38:34 +02:00
void Nexus::Join(const std::set<unsigned int> &patches,
2004-07-05 17:49:39 +02:00
std::vector<Point3f> &newvert,
2004-07-04 16:26:46 +02:00
std::vector<unsigned int> &newface,
2004-07-05 17:49:39 +02:00
std::vector<Link> &newbord) {
2004-07-04 16:26:46 +02:00
map<unsigned int, vector<unsigned int> > remap;
2004-09-17 17:25:59 +02:00
set<Link> newborders;
set<unsigned int> erased;
2004-10-09 19:37:45 +02:00
for(unsigned int u = 0; u < history.size(); u++)
for(unsigned int e = 0; e < history[u].erased.size(); e++)
2004-09-17 17:25:59 +02:00
erased.insert(history[u].erased[e]);
2004-07-04 16:26:46 +02:00
2004-10-09 19:37:45 +02:00
set<unsigned int>::const_iterator patch_idx;
for(patch_idx = patches.begin(); patch_idx != patches.end(); patch_idx++) {
unsigned int patch = *patch_idx;
2004-10-08 16:46:26 +02:00
PatchInfo &entry = index[patch];
2004-10-09 19:37:45 +02:00
remap[patch].resize(entry.nvert, 0xffffffff);
2004-07-04 16:26:46 +02:00
}
2004-09-17 17:25:59 +02:00
2004-07-04 16:26:46 +02:00
unsigned int vcount = 0;
unsigned int fcount = 0;
unsigned int bcount = 0;
2004-10-09 19:37:45 +02:00
for(patch_idx = patches.begin(); patch_idx != patches.end(); patch_idx++) {
unsigned int patch = *patch_idx;
vector<unsigned int> &vmap = remap[patch];
2004-09-17 17:25:59 +02:00
2004-10-08 16:46:26 +02:00
PatchInfo &entry = index[patch];
2004-07-04 16:26:46 +02:00
fcount += entry.nface;
for(unsigned int k = 0; k < entry.nvert; k++) {
2004-09-17 17:25:59 +02:00
if(vmap[k] == 0xffffffff) { //first time
2004-10-09 19:37:45 +02:00
vmap[k] = vcount++;
2004-07-04 16:26:46 +02:00
}
}
Border border = GetBorder(patch);
for(unsigned int k = 0; k < border.Size(); k++) {
2004-09-17 17:25:59 +02:00
Link link = border[k];
if(link.IsNull()) continue;
assert(link.start_vert < entry.nvert);
assert(vmap[link.start_vert] != 0xffffffff);
if(!remap.count(link.end_patch)) { //external
2004-10-09 19:37:45 +02:00
//test if erased in history... in wich case we do not add border
if(!erased.count(link.end_patch)) {
link.start_vert = vmap[link.start_vert];
newborders.insert(link);
}
continue;
2004-09-17 17:25:59 +02:00
}
//internal
2004-10-09 19:37:45 +02:00
//TODO unsigned int &rmpv = remap[link.end_patch][link.end_vert];
2004-07-04 16:26:46 +02:00
if(remap[link.end_patch][link.end_vert] == 0xffffffff) { //first time
2004-10-09 19:37:45 +02:00
remap[link.end_patch][link.end_vert] = vmap[link.start_vert];
2004-07-04 16:26:46 +02:00
}
}
}
newvert.resize(vcount);
newface.resize(fcount*3);
2004-09-17 17:25:59 +02:00
newbord.resize(0);
2004-07-04 16:26:46 +02:00
fcount = 0;
2004-10-09 19:37:45 +02:00
for(patch_idx = patches.begin(); patch_idx != patches.end(); patch_idx++) {
Patch patch = GetPatch(*patch_idx);
vector<unsigned int> &vmap = remap[*patch_idx];
assert(vmap.size() == patch.nv);
for(unsigned int i = 0; i < vmap.size(); i++) {
2004-09-17 17:25:59 +02:00
assert(vmap[i] < vcount);
2004-07-04 16:26:46 +02:00
newvert[vmap[i]] = patch.Vert(i);
2004-09-17 17:25:59 +02:00
}
2004-10-09 19:37:45 +02:00
2004-10-06 18:40:47 +02:00
for(unsigned int i = 0; i < patch.nf; i++)
2004-10-09 19:37:45 +02:00
for(int k = 0; k < 3; k++) {
//TODO remove this check.
if(patch.Face(i)[k] >= vmap.size()) {
cerr << "Face overflow: " << patch.Face(i)[k] << endl;
exit(0);
}
assert(patch.Face(i)[k] < vmap.size());
newface[fcount++] = vmap[patch.Face(i)[k]];
}
2004-07-04 16:26:46 +02:00
}
2004-10-09 19:37:45 +02:00
2004-10-06 18:40:47 +02:00
assert(fcount == newface.size());
2004-09-17 17:25:59 +02:00
set<Link>::iterator b;
for(b = newborders.begin(); b != newborders.end(); b++)
newbord.push_back(*b);
2004-07-05 17:49:39 +02:00
return;
2004-07-02 15:00:02 +02:00
}
2004-09-17 17:25:59 +02:00
void Nexus::Unify(float threshold) {
//TODO what if colors or normals or strips?
//TODO update totvert
unsigned int duplicated = 0;
2004-10-06 18:40:47 +02:00
unsigned int degenerate = 0;
2004-09-17 17:25:59 +02:00
for(unsigned int p = 0; p < index.size(); p++) {
2004-10-08 16:46:26 +02:00
PatchInfo &entry = index[p];
2004-09-17 17:25:59 +02:00
Patch patch = GetPatch(p);
unsigned int vcount = 0;
map<Point3f, unsigned short> vertices;
2004-10-06 18:40:47 +02:00
2004-09-17 17:25:59 +02:00
vector<unsigned short> remap;
remap.resize(patch.nv);
2004-10-06 18:40:47 +02:00
2004-09-17 17:25:59 +02:00
for(unsigned int i = 0; i < patch.nv; i++) {
Point3f &point = patch.Vert(i);
2004-10-06 18:40:47 +02:00
if(!vertices.count(point))
2004-09-17 17:25:59 +02:00
vertices[point] = vcount++;
2004-10-06 18:40:47 +02:00
else
2004-09-17 17:25:59 +02:00
duplicated++;
remap[i] = vertices[point];
}
assert(vertices.size() <= patch.nv);
if(vertices.size() == patch.nv) //no need to unify
continue;
vector<Point3f> newvert;
newvert.resize(vertices.size());
map<Point3f, unsigned short>::iterator k;
for(k = vertices.begin(); k != vertices.end(); k++) {
newvert[(*k).second] = (*k).first;
}
vector<unsigned short> newface;
2004-10-06 18:40:47 +02:00
//check no degenerate faces get created.
for(unsigned int f = 0; f < entry.nface; f++) {
unsigned short *face = patch.Face(f);
if(face[0] != face[1] && face[1] != face[2] && face[0] != face[2] &&
2004-10-09 19:37:45 +02:00
newvert[remap[face[0]]] != newvert[remap[face[1]]] &&
newvert[remap[face[0]]] != newvert[remap[face[2]]] &&
newvert[remap[face[1]]] != newvert[remap[face[2]]]) {
newface.push_back(remap[face[0]]);
newface.push_back(remap[face[1]]);
newface.push_back(remap[face[2]]);
2004-10-06 18:40:47 +02:00
} else {
2004-10-09 19:37:45 +02:00
degenerate++;
2004-10-06 18:40:47 +02:00
}
}
2004-09-17 17:25:59 +02:00
//rewrite patch now.
entry.nvert = newvert.size();
2004-10-06 18:40:47 +02:00
entry.nface = newface.size()/3;
2004-09-17 17:25:59 +02:00
patch.Init(signature, entry.nvert, entry.nface);
memcpy(patch.VertBegin(), &(newvert[0]), entry.nvert*sizeof(Point3f));
2004-10-06 18:40:47 +02:00
memcpy(patch.FaceBegin(), &(newface[0]), entry.nface*3*sizeof(short));
2004-10-09 19:37:45 +02:00
//testiamo il tutto... TODO remove this of course
for(unsigned int i =0; i < patch.nf; i++) {
for(int k =0 ; k < 3; k++)
if(patch.Face(i)[k] >= patch.nv) {
cerr <<" Unify has problems\n";
exit(0);
}
}
2004-10-06 18:40:47 +02:00
2004-09-17 17:25:59 +02:00
//fix patch borders now
set<unsigned int> close; //bordering pathes
Border border = GetBorder(p);
for(unsigned int b = 0; b < border.Size(); b++) {
if(border[b].IsNull()) continue;
close.insert(border[b].end_patch);
border[b].start_vert = remap[border[b].start_vert];
}
set<unsigned int>::iterator c;
for(c = close.begin(); c != close.end(); c++) {
Border bord = GetBorder(*c);
for(unsigned int b = 0; b < bord.Size(); b++) {
if(bord[b].IsNull()) continue;
if(bord[b].end_patch == p) {
bord[b].end_vert = remap[bord[b].end_vert];
}
}
}
}
2004-10-08 16:46:26 +02:00
//TODO: better to compact directly borders than setting them null.
2004-09-17 17:25:59 +02:00
//finally: there may be duplicated borders
for(unsigned int p = 0; p < index.size(); p++) {
Border border = GetBorder(p);
set<Link> links;
for(unsigned int b = 0; b < border.Size(); b++) {
if(border[b].IsNull()) continue;
if(links.count(border[b]))
border[b] = Link();
else
links.insert(border[b]);
}
}
2004-10-06 18:40:47 +02:00
2004-09-17 17:25:59 +02:00
totvert -= duplicated;
2004-10-06 18:40:47 +02:00
if(duplicated)
cerr << "Found " << duplicated << " duplicated vertices" << endl;
if(degenerate)
cerr << "Found " << degenerate << " degenerate face while unmifying\n";
2004-09-17 17:25:59 +02:00
}