#include "nxsbuild.h" #include #include using namespace nxs; using namespace vcg; using namespace std; void nxs::RemapVertices(Crude &crude, VertRemap &vert_remap, VFile &face_remap, vector &patch_verts) { for(unsigned int i = 0; i < crude.Faces(); i++) { Crude::Face &face = crude.GetFace(i); unsigned int patch = face_remap[i]; for(int k = 0; k < 3; k++) { set pp; vert_remap.GetValues(face[k], pp); if(!pp.count(patch)) { vert_remap.Insert(face[k], patch); patch_verts[patch]++; } } } } void nxs::NexusAllocate(Crude &crude, Nexus &nexus, VFile &face_remap, vector &patch_faces, vector &patch_verts) { nexus.index.resize(patch_faces.size()); unsigned int totchunks = 0; //now that we know various sizes, lets allocate space for(unsigned int i = 0; i < nexus.index.size(); i++) { Nexus::Entry &entry = nexus.index[i]; if(patch_faces[i] == 0 || patch_verts[i] == 0) cerr << "Warning! Empty patch.\n"; entry.patch_start = totchunks; entry.patch_size = Patch::ChunkSize(nexus.signature, patch_verts[i], patch_faces[i]); totchunks += entry.patch_size; entry.border_start = 0xffffffff; entry.nvert = patch_verts[i]; entry.nface = 0; entry.error = 0; } nexus.patches.Resize(totchunks); //now we sort the faces into the patches (but still using absolute indexing //instead of relative indexing for(unsigned int i = 0; i < crude.face.Size(); i++) { Crude::Face &face = crude.face[i]; unsigned int npatch = face_remap[i]; Nexus::Entry &entry = nexus.index[npatch]; //TODO this is slow because we have to initialize patch. //just get patch.start. Patch patch = nexus.GetPatch(npatch); Crude::Face *faces = (Crude::Face *)patch.start; faces[entry.nface] = face; entry.nface++; } } void nxs::NexusFill(Crude &crude, Nexus &nexus, VertRemap &vert_remap, VFile &border_remap) { //finally for every patch we collect the vertices //and fill the patch. //we need to remember start and size in border_remap; // vector border_start; // vector border_size; for(unsigned int i = 0; i < nexus.index.size(); i++) { Patch patch = nexus.GetPatch(i); Nexus::Entry &entry = nexus.index[i]; //make a copy of faces (we need to write there :P) Crude::Face *faces = new Crude::Face[patch.nf]; memcpy(faces, (Crude::Face *)patch.start, patch.nf * sizeof(Crude::Face)); //collect all vertices we need. //TODO an hash_map would be faster? unsigned int count = 0; map remap; for(unsigned int k = 0; k < patch.nf; k++) { Crude::Face &face = faces[k]; for(int j = 0; j < 3; j++) { if(!remap.count(face[j])) { assert(count < patch.nv); Point3f &v = crude.vert[face[j]]; patch.VertBegin()[remap.size()] = v; entry.sphere.Add(v); remap[face[j]] = count++; } patch.FaceBegin()[k*3 + j] = remap[face[j]]; } } assert(count == remap.size()); assert(entry.nvert == remap.size()); //record start of border: entry.border_start = border_remap.Size(); //TODO hash_set? set border_patches; map::iterator m; for(m = remap.begin(); m != remap.end(); m++) { RemapLink link; link.abs_vert = (*m).first; link.rel_vert = (*m).second; vert_remap.GetValues(link.abs_vert, border_patches); assert(border_patches.size() >= 1); if(border_patches.size() == 1) continue; //its not a border set::iterator s; for(s = border_patches.begin(); s != border_patches.end(); s++) { if((*s) == i) continue; link.patch = *s; border_remap.PushBack(link); } } //and number of borders: entry.border_used = border_remap.Size() - entry.border_start; delete []faces; } //we can now update bounding sphere. for(unsigned int i = 0; i < nexus.index.size(); i++) nexus.sphere.Add(nexus.index[i].sphere); } void nxs::NexusFixBorder(Nexus &nexus, VFile &border_remap) { //and last convert RemapLinks into Links nexus.borders.Resize(border_remap.Size() * 2); //* 2 is to accomodate future borders for(unsigned int i = 0; i < nexus.index.size(); i++) { Nexus::Entry &local = nexus.index[i]; local.border_start *= 2; local.border_size = local.border_used * 2; } for(unsigned int i = 0; i < nexus.index.size(); i++) { Nexus::Entry &local = nexus.index[i]; unsigned int remap_start = local.border_start/2; //* 2 is to accomodate future borders // K is the main iterator (where we write to in nexus.borders) for(unsigned int k = 0; k < local.border_used; k++) { RemapLink start_link = border_remap[k + remap_start]; assert(start_link.rel_vert < local.nvert); Nexus::Entry &remote = nexus.index[start_link.patch]; bool found = false; unsigned int remote_remap_start = remote.border_start/2; for(unsigned int j = 0; j < remote.border_used; j++) { RemapLink end_link = border_remap[j + remote_remap_start]; assert(end_link.rel_vert < remote.nvert); if(start_link.abs_vert == end_link.abs_vert && end_link.patch == i) { //found the match assert(!found); nexus.borders[k + local.border_start] = Link(start_link.rel_vert, end_link.rel_vert, start_link.patch); found = true; } } assert(nexus.borders[k + local.border_start].start_vert < local.nvert); assert(found); } } nexus.borders.Flush(); //Checking border consistency: /* for(unsigned int i = 0; i < nexus.index.size(); i++) { Border border = nexus.GetBorder(i); Nexus::Entry &entry = nexus.index[i]; for(unsigned int k = 0; k < border.Size(); k++) { Link &link = border[k]; if(link.start_vert >= entry.nvert) { cerr << "K: " << k << endl; cerr << "patch: " << i << " nvert: " << entry.nvert << " startv: " << link.start_vert << endl; cerr << "bstart: " << entry.border_start << "bsize: " << entry.border_size << endl; } assert(link.end_patch < nexus.index.size()); assert(link.start_vert < entry.nvert); Nexus::Entry &remote = nexus.index[link.end_patch]; assert(link.end_vert < remote.nvert); } }*/ }