432 lines
13 KiB
C++
432 lines
13 KiB
C++
/****************************************************************************
|
|
* 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 <set>
|
|
#include <iostream>
|
|
|
|
#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<Point3f> &newvert,
|
|
vector<unsigned int> &newface,
|
|
vector<BigLink> &newbord) {
|
|
|
|
map<unsigned int, unsigned int> patch_remap;
|
|
vector<unsigned int> 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<unsigned int> remap;
|
|
remap.resize(totvert, 0xffffffff);
|
|
|
|
//TODO what if totvert > 1<<22?
|
|
//todo we really need a set?
|
|
// set<Link> 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<Point3f> &vert = in.pieces[i].vert;
|
|
vector<unsigned short> &face = in.pieces[i].face;
|
|
vector<Link> &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<BigLink> newborders;
|
|
for(unsigned int i = 0; i < in.pieces.size(); i++) {
|
|
unsigned int offset = offsets[i];
|
|
vector<Link> &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<Point3f> &vert = in.pieces[i].vert;
|
|
vector<unsigned short> &face = in.pieces[i].face;
|
|
vector<Link> &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<BigLink>::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<Point3f> &newvert,
|
|
vector<unsigned int> &newface,
|
|
vector<BigLink> &newbord) {
|
|
|
|
unsigned int nseeds = out.seeds.size();
|
|
vector<Point3f> &seeds = out.seeds;
|
|
vector<unsigned int> &seeds_id = out.seeds_id;
|
|
//preliminary count
|
|
vector<unsigned int> 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<Point3f> newseeds;
|
|
vector<unsigned int> 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<int> > vert_remap;
|
|
vector< vector<int> > face_remap;
|
|
|
|
vector<int> vert_count;
|
|
vector<int> 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<int> &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<int> &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<int> &v_remap = vert_remap[seed];
|
|
|
|
assert(vert_count[seed] > 0);
|
|
vector<Point3f> &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<int> &f_remap = face_remap[seed];
|
|
|
|
vector<unsigned short> &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<Link> &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<int> &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<Point3f> 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;
|
|
}
|