#include #include #include "nexus.h" using namespace std; using namespace vcg; using namespace nxs; Nexus::Nexus(): index_file(NULL) {} Nexus::~Nexus() { Close(); } bool Nexus::Create(const string &file, Signature sig) { index_file = fopen((file + ".nxs").c_str(), "wb+"); if(!index_file) { cerr << "Could not create file: " << file << ".nxs\n"; return false; } signature = sig; totvert = 0; totface = 0; sphere = Sphere3f(); index.clear(); //Important: chunk_size must be 1 so that i can use Region in VFile. if(!patches.Create(file + ".nxp", 1)) { cerr << "Could not create file: " << file << ".nxp" << endl; return false; } if(!borders.Create(file + ".nxb", 1)) { cerr << "Could not create file: " << file << ".nxb" << endl; return false; } history.clear(); return true; } bool Nexus::Load(const string &file) { index_file = fopen((file + ".nxs").c_str(), "rb+"); if(!index_file) return false; unsigned int readed; readed = fread(&signature, sizeof(unsigned int), 1, index_file); if(!readed) return false; 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; unsigned int size; //size of index readed = fread(&size, sizeof(unsigned int), 1, index_file); if(!readed) return false; index.resize(size); readed = fread(&index[0], sizeof(Entry), size, index_file); if(readed != size) return false; //history size; fread(&size, sizeof(unsigned int), 1, index_file); vector 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++]; } if(!patches.Load(file + ".nxp", 1)) return false; if(!borders.Load(file + ".nxb", 1)) return false; return true; } void Nexus::Close() { if(!index_file) return; rewind(index_file); fwrite(&signature, sizeof(unsigned int), 1, index_file); fwrite(&totvert, sizeof(unsigned int), 1, index_file); fwrite(&totface, sizeof(unsigned int), 1, index_file); fwrite(&sphere, sizeof(Sphere3f), 1, index_file); unsigned int size = index.size(); //size of index fwrite(&size, sizeof(unsigned int), 1, index_file); fwrite(&(index[0]), sizeof(Entry), size, index_file); vector 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); fclose(index_file); index_file = NULL; patches.Close(); borders.Close(); } Patch Nexus::GetPatch(unsigned int patch, bool flush) { Entry &entry = index[patch]; Chunk *start = patches.GetRegion(entry.patch_start, entry.patch_used,flush); return Patch(signature, start, entry.nvert, entry.nface); } Border Nexus::GetBorder(unsigned int patch, bool flush) { Entry &entry = index[patch]; Link *start = borders.GetRegion(entry.border_start, entry.border_size,flush); return Border(start, entry.border_used, entry.border_size); } unsigned int Nexus::AddPatch(unsigned int nvert, unsigned int nface, unsigned int nbord) { Entry entry; entry.patch_start = patches.Size(); entry.patch_size = Patch::ChunkSize(signature, nvert, nface); entry.patch_used = entry.patch_size; entry.border_start = borders.Size(); entry.border_size = nbord; entry.border_used = 0; entry.nvert = nvert; entry.nface = nface; patches.Resize(patches.Size() + entry.patch_size); borders.Resize(borders.Size() + nbord); index.push_back(entry); totvert += nvert; totface += nface; return index.size() -1; } void Nexus::Join(const std::set &patches, std::vector &newvert, std::vector &newface, std::vector &newbord) { map > remap; set newborders; set erased; for(int u = 0; u < history.size(); u++) for(int e = 0; e < history[u].erased.size(); e++) erased.insert(history[u].erased[e]); set::const_iterator i; for(i = patches.begin(); i != patches.end(); i++) { unsigned int patch = *i; Nexus::Entry &entry = index[patch]; remap[*i].resize(entry.nvert, 0xffffffff); } unsigned int vcount = 0; unsigned int fcount = 0; unsigned int bcount = 0; for(i = patches.begin(); i != patches.end(); i++) { unsigned int patch = *i; vector &vmap = remap[*i]; Nexus::Entry &entry = index[patch]; fcount += entry.nface; for(unsigned int k = 0; k < entry.nvert; k++) { if(vmap[k] == 0xffffffff) { //first time vmap[k] = vcount++; } } Border border = GetBorder(patch); for(unsigned int k = 0; k < border.Size(); k++) { 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 //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; } //internal if(remap[link.end_patch][link.end_vert] == 0xffffffff) { //first time remap[link.end_patch][link.end_vert] = vmap[link.start_vert]; } } } newvert.resize(vcount); newface.resize(fcount*3); newbord.resize(0); fcount = 0; for(i = patches.begin(); i != patches.end(); i++) { Patch patch = GetPatch(*i); vector &vmap = remap[*i]; for(unsigned int i = 0; i < patch.nv; i++) { assert(vmap[i] < vcount); newvert[vmap[i]] = patch.Vert(i); } for(unsigned int i = 0; i < patch.nf; i++) { unsigned short *face = patch.Face(i); if(patch.Vert(face[0]) == patch.Vert(face[1]) || patch.Vert(face[0]) == patch.Vert(face[2]) || patch.Vert(face[1]) == patch.Vert(face[2])) { cerr << "MALEDETTO!" << endl; Point3f &v0 = patch.Vert(face[0]); Point3f &v1 = patch.Vert(face[1]); Point3f &v2 = patch.Vert(face[2]); cerr << "V0: " << v0[0] << " " << v0[1] << " " << v0[2] << endl; cerr << "V1: " << v1[0] << " " << v1[1] << " " << v1[2] << endl; cerr << "V2: " << v2[0] << " " << v2[1] << " " << v2[2] << endl; } if(patch.Face(i)[0] == patch.Face(i)[1] || patch.Face(i)[0] == patch.Face(i)[2] || patch.Face(i)[1] == patch.Face(i)[2]) { cerr << "Damn: " << i << endl; cerr << patch.Face(i)[0] << " " << patch.Face(i)[1] << patch.Face(i)[2] << endl; } } for(unsigned int i = 0; i < patch.nf; i++) for(int k = 0; k < 3; k++) newface[fcount++] = vmap[patch.Face(i)[k]]; } assert(fcount == newface.size()); set::iterator b; for(b = newborders.begin(); b != newborders.end(); b++) newbord.push_back(*b); return; } void Nexus::Unify(float threshold) { //TODO what if colors or normals or strips? //TODO update totvert unsigned int duplicated = 0; unsigned int degenerate = 0; for(unsigned int p = 0; p < index.size(); p++) { Nexus::Entry &entry = index[p]; Patch patch = GetPatch(p); unsigned int vcount = 0; map vertices; vector remap; remap.resize(patch.nv); for(unsigned int i = 0; i < patch.nv; i++) { Point3f &point = patch.Vert(i); if(!vertices.count(point)) vertices[point] = vcount++; else duplicated++; remap[i] = vertices[point]; } assert(vertices.size() <= patch.nv); if(vertices.size() == patch.nv) //no need to unify continue; vector newvert; newvert.resize(vertices.size()); map::iterator k; for(k = vertices.begin(); k != vertices.end(); k++) { newvert[(*k).second] = (*k).first; } vector newface; //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] && 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]]); } else { degenerate++; } } //rewrite patch now. entry.nvert = newvert.size(); entry.nface = newface.size()/3; patch.Init(signature, entry.nvert, entry.nface); memcpy(patch.VertBegin(), &(newvert[0]), entry.nvert*sizeof(Point3f)); memcpy(patch.FaceBegin(), &(newface[0]), entry.nface*3*sizeof(short)); //fix patch borders now set 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::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]; } } } } //finally: there may be duplicated borders for(unsigned int p = 0; p < index.size(); p++) { Border border = GetBorder(p); set 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]); } } totvert -= duplicated; if(duplicated) cerr << "Found " << duplicated << " duplicated vertices" << endl; if(degenerate) cerr << "Found " << degenerate << " degenerate face while unmifying\n"; }