/**************************************************************************** * 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 $ Revision 1.9 2005/02/08 12:43:03 ponchio Added copyright ****************************************************************************/ #include #include #include "fragment.h" #include "border.h" #include "nxsalgo.h" //#include "pvoronoi.h" using namespace std; using namespace vcg; using namespace nxs; using namespace pt; void NxsPatch::Write(outstm *out) { out->write(&sphere, sizeof(Sphere3f)); out->write(&cone, sizeof(ANCone3f)); int vsize = vert.size(); int fsize = face.size(); int bsize = bord.size(); out->write(&patch, sizeof(unsigned int)); out->write(&vsize, sizeof(unsigned int)); out->write(&fsize, sizeof(unsigned int)); out->write(&bsize, sizeof(unsigned int)); out->write(&*vert.begin(), vert.size() * sizeof(Point3f)); out->write(&*face.begin(), face.size() * sizeof(unsigned short)); out->write(&*bord.begin(), bord.size() * sizeof(Link)); } void NxsPatch::Read(instm *in) { in->read(&sphere, sizeof(Sphere3f)); in->read(&cone, sizeof(ANCone3f)); int vsize; int fsize; int bsize; in->read(&patch, sizeof(unsigned int)); in->read(&vsize, sizeof(unsigned int)); in->read(&fsize, sizeof(unsigned int)); in->read(&bsize, sizeof(unsigned int)); vert.resize(vsize); face.resize(fsize); bord.resize(bsize); in->read(&*vert.begin(), vert.size() * sizeof(Point3f)); in->read(&*face.begin(), face.size() * sizeof(unsigned short)); in->read(&*bord.begin(), bord.size() * sizeof(Link)); } bool Fragment::Write(outstm *out) { try { out->write(&id, sizeof(unsigned int)); out->write(&error, sizeof(float)); unsigned int ssize = seeds.size(); out->write(&ssize, sizeof(unsigned int)); out->write(&*seeds.begin(), ssize * sizeof(Point3f)); out->write(&*seeds_id.begin(), ssize * sizeof(unsigned int)); unsigned int psize = pieces.size(); out->write(&psize, sizeof(unsigned int)); for(unsigned int i = 0; i < pieces.size(); i++) pieces[i].Write(out); return true; } catch (estream *e) { perr.putf("Error: %s\n", pconst(e->get_message())); delete e; return false; } } bool Fragment::Read(instm *in) { try { in->read(&id, sizeof(unsigned int)); in->read(&error, sizeof(float)); //TODO move this control to all read! unsigned int ssize; if(sizeof(int) != in->read(&ssize, sizeof(unsigned int))) return false; seeds.resize(ssize); seeds_id.resize(ssize); in->read(&*seeds.begin(), ssize * sizeof(Point3f)); in->read(&*seeds_id.begin(), ssize * sizeof(unsigned int)); unsigned int psize; in->read(&psize, sizeof(unsigned int)); pieces.resize(psize); for(unsigned int i = 0; i < psize; i++) { pieces[i].Read(in); } return true; } catch (estream *e) { perr.putf("Error: %s\n", pconst(e->get_message())); delete e; return false; } } void nxs::Join(Fragment &in, vector &newvert, vector &newface, vector &newbord) { map patch_remap; vector offsets; unsigned int totvert = 0; for(unsigned int i = 0; i < in.pieces.size(); i++) { offsets.push_back(totvert); patch_remap[in.pieces[i].patch] = i; totvert += in.pieces[i].vert.size(); } vector remap; remap.resize(totvert, 0xffffffff); //TODO what if totvert > 1<<22? //todo we really need a set? // set newborders; unsigned int vcount = 0; unsigned int fcount = 0; unsigned int bcount = 0; for(unsigned int i = 0; i < in.pieces.size(); i++) { unsigned int offset = offsets[i]; vector &vert = in.pieces[i].vert; vector &face = in.pieces[i].face; vector &bord = in.pieces[i].bord; for(unsigned int k = 0; k < face.size(); k+=3) { assert(face[k] != face[k+1]); assert(face[k] != face[k+2]); assert(face[k+1] != face[k+2]); } fcount += face.size()/3; for(unsigned int k = 0; k < vert.size(); k++) { assert(offset + k < remap.size()); if(remap[offset + k] == 0xffffffff) remap[offset + k] = vcount++; } for(unsigned int k = 0; k < bord.size(); k++) { Link link = bord[k]; if(link.IsNull()) continue; if(patch_remap.count(link.end_patch)) {//internal unsigned int idx = patch_remap[link.end_patch]; assert(link.end_patch != in.pieces[i].patch); unsigned int extoffset = offsets[idx]; assert(extoffset + link.end_vert < remap.size()); if(remap[extoffset + link.end_vert] == 0xffffffff) //first time remap[extoffset + link.end_vert] = remap[offset + link.start_vert]; } } } assert(vcount < (1<<16)); set newborders; for(unsigned int i = 0; i < in.pieces.size(); i++) { unsigned int offset = offsets[i]; vector &bord = in.pieces[i].bord; for(unsigned int k = 0; k < bord.size(); k++) { Link llink = bord[k]; if(llink.IsNull()) continue; if(!patch_remap.count(llink.end_patch)) {//external BigLink link; link.start_vert = remap[offset + llink.start_vert]; link.end_patch = in.pieces[i].patch; link.end_vert = llink.start_vert; newborders.insert(link); } } } newvert.resize(vcount); newface.resize(fcount*3); newbord.resize(newborders.size()); fcount = 0; for(unsigned int i = 0; i < in.pieces.size(); i++) { unsigned int offset = offsets[i]; vector &vert = in.pieces[i].vert; vector &face = in.pieces[i].face; vector &bord = in.pieces[i].bord; for(unsigned int i = 0; i < vert.size(); i++) { assert(offset + i < remap.size()); assert(remap[offset + i] < vcount); newvert[remap[offset + i]] = vert[i]; } for(unsigned int i = 0; i < face.size(); i++) { assert(offset + face[i] < remap.size()); assert(remap[offset + face[i]] < newvert.size()); assert(fcount < newface.size()); newface[fcount++] = remap[offset + face[i]]; } } set::iterator b; for(b = newborders.begin(); b != newborders.end(); b++) { newbord[bcount++] = *b; } for(unsigned int i = 0; i < newface.size(); i+= 3) { if(newface[i] == newface[i+1] || newface[i] == newface[i+2] || newface[i+1] == newface[i+2]) { cerr << "i: " << i << endl; for(unsigned int k = 0; k < newface.size(); k+=3) { cerr << k << ": " << newface[k] << " " << newface[k+1] << " " << newface[k+2] << endl; } exit(0); } } } void nxs::Split(Fragment &out, vector &newvert, vector &newface, vector &newbord) { unsigned int nseeds = out.seeds.size(); vector &seeds = out.seeds; vector &seeds_id = out.seeds_id; //preliminary count vector count; count.resize(nseeds, 0); for(unsigned int f = 0; f < newface.size(); f += 3) { Point3f bari = (newvert[newface[f]] + newvert[newface[f+1]] + newvert[newface[f+2]])/3; unsigned int seed = out.Locate(bari); assert(seed < nseeds); count[seed]++; } //pruning small patches float min_size = (newface.size()/3) / 20.0f; vector newseeds; vector newseeds_id; for(unsigned int seed = 0; seed < nseeds; seed++) { if(count[seed] > min_size) { newseeds.push_back(seeds[seed]); newseeds_id.push_back(seeds_id[seed]); } if(count[seed] > (1<<16)) { cerr << "Ooops a cell came too big... quitting\n"; exit(0); } } seeds = newseeds; seeds_id = newseeds_id; nseeds = seeds.size(); //if != -1 remap global index to cell index (first arg) vector< vector > vert_remap; vector< vector > face_remap; vector vert_count; vector face_count; vert_remap.resize(nseeds); face_remap.resize(nseeds); vert_count.resize(nseeds, 0); face_count.resize(nseeds, 0); for(unsigned int seed = 0; seed < nseeds; seed++) vert_remap[seed].resize(newvert.size(), -1); for(unsigned int f = 0; f < newface.size(); f += 3) { Point3f bari = (newvert[newface[f]] + newvert[newface[f+1]] + newvert[newface[f+2]])/3; unsigned int seed = out.Locate(bari); vector &f_remap = face_remap[seed]; f_remap.push_back(newface[f]); f_remap.push_back(newface[f+1]); f_remap.push_back(newface[f+2]); face_count[seed]++; vector &v_remap = vert_remap[seed]; for(int i = 0; i < 3; i++) if(v_remap[newface[f+i]] == -1) v_remap[newface[f+i]] = vert_count[seed]++; } //TODO assure no big ones. out.pieces.resize(nseeds); for(unsigned int seed = 0; seed != nseeds; seed++) { NxsPatch &patch = out.pieces[seed]; patch.patch = seeds_id[seed]; //vertices first vector &v_remap = vert_remap[seed]; assert(vert_count[seed] > 0); vector &verts = patch.vert; verts.resize(vert_count[seed]); for(unsigned int i = 0; i < newvert.size(); i++) { if(v_remap[i] != -1) verts[v_remap[i]] = newvert[i]; } //faces now vector &f_remap = face_remap[seed]; vector &faces = patch.face; faces.resize(face_count[seed]*3); for(unsigned int i = 0; i < f_remap.size(); i++) { assert(v_remap[f_remap[i]] != -1); faces[i] = v_remap[f_remap[i]]; } //borders last vector &bords = patch.bord; //process downward borders for(unsigned int i = 0; i < newbord.size(); i++) { BigLink link = newbord[i]; /* cerr << "Newbord: " << link.start_vert << " " << link.end_patch << " " << link.end_vert << endl;*/ if(v_remap[link.start_vert] == -1) continue; Link llink; llink.start_vert = v_remap[link.start_vert]; llink.end_patch = link.end_patch; llink.end_vert = link.end_vert; bords.push_back(llink); } //process internal borders; //TODO higly inefficient!!! for(unsigned int rseed = 0; rseed < nseeds; rseed++) { if(seed == rseed) continue; vector &vremapclose = vert_remap[rseed]; for(unsigned int i = 0; i < newvert.size(); i++) { if(v_remap[i] != -1 && vremapclose[i] != -1) { Link link; link.end_patch = rseed + (1<<31); link.start_vert = v_remap[i]; link.end_vert = vremapclose[i]; bords.push_back(link); } } } } //process Cone and sphere for(unsigned int seed = 0; seed != nseeds; seed++) { NxsPatch &patch = out.pieces[seed]; Sphere3f &sphere = patch.sphere; sphere.CreateTight(patch.vert.size(), &*patch.vert.begin()); //NORMALS CONE vector normals; for(unsigned int i = 0; i < patch.face.size(); i += 3) { unsigned short *f = &(patch.face[i]); Point3f &v0 = patch.vert[f[0]]; Point3f &v1 = patch.vert[f[1]]; Point3f &v2 = patch.vert[f[2]]; Point3f norm = (v1 - v0) ^ (v2 - v0); normals.push_back(norm.Normalize()); } patch.cone.AddNormals(normals, 0.99f); } } unsigned int Fragment::Locate(const Point3f &p) { float max_dist = 1e20f; unsigned int id = 0xffffffff; for(unsigned int i = 0; i < seeds.size(); i++) { float dist = Distance(seeds[i], p); if(dist < max_dist) { max_dist = dist; id = i; } } assert(id != 0xffffffff); return id; }