Fixed degenerate faces.

This commit is contained in:
Federico Ponchio 2004-10-06 16:40:47 +00:00
parent fcfab2d616
commit 4dc937e514
5 changed files with 91 additions and 324 deletions

View File

@ -17,7 +17,7 @@
//#include "border.h"
#include "decimate.h"
//#include <wrap/io_trimesh/export_ply.h>
#include <wrap/io_trimesh/export_ply.h>
using namespace vcg;
using namespace tri;
@ -59,11 +59,10 @@ float nxs::Decimate(Decimation mode,
vector<Link> &newbord,
vector<int> &vert_remap) {
//Temporary test:
for(unsigned int i = 0; i < newface.size(); i+= 3) {
assert(newface[i*3] != newface[i*3+1]);
assert(newface[i*3] != newface[i*3+2]);
assert(newface[i*3+1] != newface[i*3+2]);
assert(newface[i] != newface[i+1]);
assert(newface[i] != newface[i+2]);
assert(newface[i+1] != newface[i+2]);
}
MyMesh mesh;
@ -81,7 +80,7 @@ float nxs::Decimate(Decimation mode,
MyFace face;
face.ClearFlags();
for(int k = 0; k < 3; k++) {
assert(newface[i+k] < mesh.vn);
assert(newface[i+k] < mesh.vert.size());
face.V(k) = &mesh.vert[newface[i+k]];
}
mesh.face.push_back(face);
@ -92,57 +91,18 @@ float nxs::Decimate(Decimation mode,
for(unsigned int i = 0; i < newbord.size(); i++)
mesh.vert[newbord[i].start_vert].ClearW();
// int FinalSize = mesh.face.size()/2;
// if(FinalSize > target_faces) FinalSize = target_faces;
/* if(target_faces == 2404) {
vcg::tri::io::ExporterPLY<MyMesh>::Save(mesh, "bum");
}*/
printf("mesh loaded %d %d \n",mesh.vn,mesh.fn);
printf("reducing it to %i\n", target_faces);
// if(target_faces == 1446)
// vcg::tri::io::ExporterPLY<MyMesh>::Save(mesh, "ribum.ply");
/*
int t0=clock();
vcg::tri::UpdateTopology<MyMesh>::VertexFace(mesh);
int t1=clock();
vcg::LocalOptimization<MyMesh> DeciSession(mesh);
MyTriEdgeCollapse::SetDefaultParams();
DeciSession.Init<MyTriEdgeCollapse>();
FinalSize = mesh.fn - FinalSize; //number of faces to remove
FinalSize/=2; //Number of vertices to remove
DeciSession.SetTargetOperations(FinalSize);
DeciSession.DoOptimization();
float error = DeciSession.currMetric/4;//1; //get error;
int t3=clock();
*/
float error;
if(mode == CLUSTER)
error = Cluster(mesh, target_faces);
else
error = Quadric(mesh, target_faces);
/* printf(" vol %d \n lkv %d \n lke %d \n lkf %d \n ood %d\n bor %d\n ",
MyTriEdgeCollapse::FailStat::Volume() ,
MyTriEdgeCollapse::FailStat::LinkConditionFace(),
MyTriEdgeCollapse::FailStat::LinkConditionEdge(),
MyTriEdgeCollapse::FailStat::LinkConditionVert(),
MyTriEdgeCollapse::FailStat::OutOfDate() ,
MyTriEdgeCollapse::FailStat::Border()
);*/
// printf("Completed in %i+%i+%i msec\n",t1-t0,t2-t1,t3-t2);
// printf("mesh %d %d \n",mesh.vn,mesh.fn);
//recort vert start.
newvert.clear();
newface.clear();
@ -158,10 +118,8 @@ float nxs::Decimate(Decimation mode,
for(unsigned int i = 0; i < mesh.face.size(); i++) {
MyFace &face = mesh.face[i];
if(face.IsD()) continue;
for(int k = 0; k < 3; k++) {
assert(vert_remap[face.V(k) - vert_start] != -1);
for(int k = 0; k < 3; k++)
newface.push_back(vert_remap[face.V(k) - vert_start]);
}
}
for(unsigned int i = 0; i < newbord.size(); i++) {
@ -172,9 +130,9 @@ float nxs::Decimate(Decimation mode,
//Temporary test again:
for(unsigned int i = 0; i < newface.size(); i+= 3) {
assert(newface[i*3] != newface[i*3+1]);
assert(newface[i*3] != newface[i*3+2]);
assert(newface[i*3+1] != newface[i*3+2]);
assert(newface[i] != newface[i+1]);
assert(newface[i] != newface[i+2]);
assert(newface[i+1] != newface[i+2]);
}
return error;
@ -243,6 +201,8 @@ float Cluster(MyMesh &mesh, unsigned int target_faces) {
part.SetBox(box);
part.Init();
cerr << "inited points\n";
vector<Point3f> centroid;
vector<unsigned int> count;
for(unsigned int i = 0; i < 3; i++) {
@ -266,12 +226,16 @@ float Cluster(MyMesh &mesh, unsigned int target_faces) {
mesh.vert[remap[i]].P() = part[i].p;
}
cerr << "remapping faces\n";
float error = 0;
//rimappiamo le facce.....
for(unsigned int i = 0; i < mesh.face.size(); i++) {
MyFace &face = mesh.face[i];
for(int k = 0; k < 3; k++) {
unsigned int target = part.Locate(face.V(k)->cP());
assert(target < remap.size());
assert(remap[target] < mesh.vert.size());
MyVertex &vert = mesh.vert[remap[target]];
float dist = Distance(vert.cP(), face.V(k)->cP());
@ -281,6 +245,7 @@ float Cluster(MyMesh &mesh, unsigned int target_faces) {
}
}
cerr << "Deleting faces\n";
for(unsigned int i = 0; i < mesh.face.size(); i++) {
MyFace &face = mesh.face[i];
assert(!face.IsD());
@ -294,6 +259,8 @@ float Cluster(MyMesh &mesh, unsigned int target_faces) {
mesh.fn--;
}
}
cerr << "deleting vertices\n";
for(unsigned int i = 0; i < mesh.vert.size(); i++)
if(!mesh.vert[i].IsV() && mesh.vert[i].IsW()) {

View File

@ -185,7 +185,6 @@ void Nexus::Join(const std::set<unsigned int> &patches,
Nexus::Entry &entry = index[patch];
fcount += entry.nface;
// assert(fcount < 0xffff);
for(unsigned int k = 0; k < entry.nvert; k++) {
if(vmap[k] == 0xffffffff) { //first time
vmap[k] = vcount++;
@ -224,57 +223,45 @@ void Nexus::Join(const std::set<unsigned int> &patches,
fcount = 0;
for(i = patches.begin(); i != patches.end(); i++) {
Patch patch = GetPatch(*i);
// Border border = GetBorder(*i);
vector<unsigned int> &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++) {
for(int k = 0; k < 3; k++) {
newface[3*fcount + k] = vmap[patch.Face(i)[k]];
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;
}
assert(patch.Face(i)[0] != patch.Face(i)[1]);
assert(patch.Face(i)[0] != patch.Face(i)[2]);
assert(patch.Face(i)[1] != patch.Face(i)[2]);
assert(newface[3*fcount + 0] != newface[3*fcount + 1]);
assert(newface[3*fcount + 0] != newface[3*fcount + 2]);
assert(newface[3*fcount + 1] != newface[3*fcount + 2]);
fcount++;
assert(fcount *3 <= newface.size());
}
/* for(unsigned int i = 0; i < border.Size(); i++) {
Link link = border[i];
if(patches.count(link.end_patch)) continue;
link.start_vert = vmap[link.start_vert];
newbord.push_back(link);*/
/* if(remap.count(link.end_patch)) continue;
Link newlink = link;
newlink.start_vert = vmap[link.start_vert];
newbord[bcount++] = newlink;*/
// }
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<Link>::iterator b;
for(b = newborders.begin(); b != newborders.end(); b++)
newbord.push_back(*b);
/* unsigned int newentry = AddPatch(vcount, fcount, bcount);
Patch newpatch = GetPatch(newentry);
Border newborder = GetBorder(newentry);
memcpy(newpatch.VertBegin(), &(newvert)[0],
newvert.size() * sizeof(Point3f));
memcpy(newpatch.FaceBegin(), &(newface)[0],
newface.size() * sizeof(unsigned short));
memcpy(&(newborder[0]), &(newbord[0]),
newbord.size() * sizeof(Link));*/
return;
}
@ -283,23 +270,25 @@ 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<Point3f, unsigned short> vertices;
vector<unsigned short> remap;
remap.resize(patch.nv);
// map<unsigned short, unsigned short> remap;
for(unsigned int i = 0; i < patch.nv; i++) {
Point3f &point = patch.Vert(i);
if(!vertices.count(point)) {
if(!vertices.count(point))
vertices[point] = vcount++;
} else {
else
duplicated++;
}
remap[i] = vertices[point];
}
@ -316,17 +305,29 @@ void Nexus::Unify(float threshold) {
vector<unsigned short> newface;
newface.resize(patch.nf * 3);
for(unsigned int f = 0; f < newface.size(); f++)
newface[f] = remap[patch.FaceBegin()[f]];
//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(unsigned short));
memcpy(patch.FaceBegin(), &(newface[0]), entry.nface*3*sizeof(short));
//fix patch borders now
set<unsigned int> close; //bordering pathes
Border border = GetBorder(p);
@ -350,8 +351,6 @@ void Nexus::Unify(float threshold) {
//finally: there may be duplicated borders
for(unsigned int p = 0; p < index.size(); p++) {
Border border = GetBorder(p);
//Nexus::Entry &entry = index[p];
set<Link> links;
for(unsigned int b = 0; b < border.Size(); b++) {
if(border[b].IsNull()) continue;
@ -361,7 +360,10 @@ void Nexus::Unify(float threshold) {
links.insert(border[b]);
}
}
totvert -= duplicated;
// cout << "Found " << duplicated << " duplicated vertices" << endl;
if(duplicated)
cerr << "Found " << duplicated << " duplicated vertices" << endl;
if(degenerate)
cerr << "Found " << degenerate << " degenerate face while unmifying\n";
}

View File

@ -362,7 +362,6 @@ Patch &NexusMt::LoadPatch(unsigned int p) {
if(ram_used > ram_size * 1.5)
FlushRam();
cerr << "Ram: " << ram_used << endl;
return *(sgurz.patch);
}

View File

@ -106,12 +106,11 @@ void nxs::NexusFill(Crude &crude,
//TODO an hash_map would be faster?
unsigned int count = 0;
map<unsigned int, unsigned short> 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);
@ -119,10 +118,6 @@ void nxs::NexusFill(Crude &crude,
}
patch.FaceBegin()[k*3 + j] = remap[face[j]];
}
//test for degenerate faces.
assert(patch.FaceBegin()[k*3] != patch.FaceBegin()[k*3+1]);
assert(patch.FaceBegin()[k*3] != patch.FaceBegin()[k*3+2]);
assert(patch.FaceBegin()[k*3+1] != patch.FaceBegin()[k*3+2]);
}
assert(count == remap.size());
assert(entry.nvert == remap.size());
@ -157,6 +152,16 @@ void nxs::NexusFill(Crude &crude,
//we can now update bounding sphere.
for(unsigned int i = 0; i < nexus.index.size(); i++)
nexus.sphere.Add(nexus.index[i].sphere);
//test no duplicated faces:
/* for(unsigned int i = 0; i < nexus.index.size(); i++) {
Patch patch = nexus.GetPatch(i);
for(unsigned int k = 0; k < patch.nf; k++) {
assert(patch.Face(k)[0] != patch.Face(k)[1]);
assert(patch.Face(k)[0] != patch.Face(k)[2]);
assert(patch.Face(k)[1] != patch.Face(k)[2]);
}
}*/
}
void nxs::NexusFixBorder(Nexus &nexus,
@ -194,19 +199,19 @@ void nxs::NexusFixBorder(Nexus &nexus,
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);
// 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);
// 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);
// assert(nexus.borders[k + local.border_start].start_vert < local.nvert);
// assert(found);
}
}
nexus.borders.Flush();

View File

@ -24,6 +24,9 @@
History
$Log: not supported by cvs2svn $
Revision 1.7 2004/10/04 16:49:54 ponchio
Daily backup. Preparing for compression.
Revision 1.6 2004/10/01 16:54:57 ponchio
Daily backup.
@ -282,7 +285,6 @@ int main(int argc, char *argv[]) {
nexus.Join((*fragment).second, newvert, newface, newbord);
//simplyfy mesh
vector<int> vert_remap;
float error = Decimate(decimation,
@ -319,17 +321,6 @@ int main(int argc, char *argv[]) {
}
nexus.history.push_back(update);
ReverseHistory(nexus.history);
//debug:
/* for(unsigned int i = 0; i < nexus.history.size(); i++) {
Nexus::Update &update = nexus.history[i];
cerr << "created:";
for(unsigned int c = 0; c < update.created.size(); c++)
cerr << " " << update.created[c];
cerr << "\nerased:";
for(unsigned int c = 0; c < update.erased.size(); c++)
cerr << " " << update.erased[c];
cerr << "\n\n";
}*/
//Clean up:
nexus.Close();
@ -338,203 +329,6 @@ int main(int argc, char *argv[]) {
return 0;
}
/*void RemapVertices(Crude &crude,
VertRemap &vert_remap,
VFile<unsigned int> &face_remap,
vector<unsigned int> &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<unsigned int> pp;
vert_remap.GetValues(face[k], pp);
if(!pp.count(patch)) {
vert_remap.Insert(face[k], patch);
patch_verts[patch]++;
}
}
}
}*/
/*void NexusAllocate(Crude &crude,
Nexus &nexus,
VFile<unsigned int> &face_remap,
vector<unsigned int> &patch_faces,
vector<unsigned int> &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 NexusFill(Crude &crude,
Nexus &nexus,
VertRemap &vert_remap,
VFile<RemapLink> &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<unsigned int> border_start;
// vector<unsigned int> 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<unsigned int, unsigned short> 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<unsigned int> border_patches;
map<unsigned int, unsigned short>::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<unsigned int>::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 NexusFixBorder(Nexus &nexus,
VFile<RemapLink> &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();
} */
void NexusSplit(Nexus &nexus, VoronoiChain &vchain,
unsigned int level,
vector<Point3f> &newvert,