/**************************************************************************** * 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.26 2005/03/02 10:40:18 ponchio Extraction rewrittten (to fix recusive problems). Revision 1.25 2005/03/01 11:21:20 ponchio Added line intersection Revision 1.24 2005/02/22 14:20:44 ponchio debug and mostly vertex unifying across borders (still not perfect... :P) Revision 1.23 2005/02/22 10:38:10 ponchio Debug, cleaning and optimization. Revision 1.22 2005/02/21 17:55:36 ponchio debug debug debug Revision 1.21 2005/02/20 18:07:01 ponchio cleaning. Revision 1.20 2005/02/19 10:45:04 ponchio Patch generalized and small fixes. Revision 1.19 2005/02/18 13:04:12 ponchio Added patch reordering. Revision 1.18 2005/02/17 16:40:35 ponchio Optimized BuildLevels. Revision 1.17 2005/02/08 12:43:03 ponchio Added copyright ****************************************************************************/ #include #include #include #include #include //#include #include "nxsalgo.h" #include "extraction.h" #include "vpartition.h" #include "vfile.h" #include "nexus.h" #include "zcurve.h" #include "watch.h" #include #include using namespace std; using namespace nxs; using namespace vcg; void nxs::Connect(Nexus &nexus, std::vector< set > &close, float threshold) { VPartition grid; float max_radius = 0; for(unsigned int patch = 0; patch < nexus.size(); patch++) { Sphere3f &sphere = nexus[patch].sphere; grid.push_back(sphere.Center()); float r = sphere.Radius(); if(r > max_radius) max_radius = r; } grid.Init(); close.clear(); close.resize(nexus.size()); vector targets; vector dists; for(unsigned int patch = 0; patch < nexus.size(); patch++) { float radius = nexus[patch].sphere.Radius(); float max_distance = radius + max_radius + threshold; max_distance *= max_distance; grid.Closest(grid[patch], targets, dists, max_distance); for(unsigned int i = 0; i < targets.size(); i++) { unsigned int target = targets[i]; if(target == patch) continue; float dist = radius + nexus[target].sphere.Radius() + threshold; dist *= dist; if(dist >= dists[i]) { close[patch].insert(target); } } } //DOUBLECROSS CHECK for(unsigned int patch = 0; patch < nexus.size(); patch++) { set::iterator i; for(i = close[patch].begin(); i != close[patch].end(); i++) { if(!close[*i].count(patch)) { cerr << "Some problem width sphere intersection. Have alook.\n"; cerr << "Meanwhile i fix it.\n"; close[*i].insert(patch); } } } } void nxs::ComputeNormals(Nexus &nexus) { assert(nexus.signature.vnorm); assert(!nexus.borders.IsReadOnly()); //first calculate level 0 normals //I load all patches in a fragment //calculate normals //fix external borders getting from level below //first try naive approach just load neighborough get normals and //fix border with lower level vector levels; nexus.history.BuildLevels(levels); Report report(nexus.size(), 15); //TODO check level 0 is the finer one int current_level = 0; while(1) { int count = 0; for(unsigned int p = 0; p < nexus.size(); p++) { if(levels[p] != current_level) continue; count++; report.Step(p); Border &border = nexus.GetBorder(p); map > normals; normals[p] = vector(); for(unsigned int i = 0; i < border.Size(); i++) { Link &link = border[i]; if(levels[link.end_patch] == current_level) normals[link.end_patch] = vector(); } map >::iterator k; for(k = normals.begin(); k != normals.end(); k++) { Patch &patch = nexus.GetPatch((*k).first); vector &normal = (*k).second; normal.resize(patch.nv, Point3f(0, 0, 0)); if(nexus.signature.face == Signature::TRIANGLES) { for(unsigned int i = 0; i < patch.nf; i++) { unsigned short *f = patch.Face(i); Point3f &v0 = patch.Vert3f(f[0]); Point3f &v1 = patch.Vert3f(f[1]); Point3f &v2 = patch.Vert3f(f[2]); Point3f a = (v1 - v0); Point3f b = (v2 - v0); float n = a.Norm() * b.Norm(); if(n == 0) continue; Point3f norm = a^b; float rn = norm.Norm(); norm *= asin(rn/n)/n; normal[f[0]] += norm; normal[f[1]] += norm; normal[f[2]] += norm; } } else if(nexus.signature.face == Signature::STRIPS) { for(int i = 0; i < patch.nf - 2; i++) { unsigned short *f = patch.FaceBegin() + i; Point3f &v0 = patch.Vert3f(f[0]); Point3f &v1 = patch.Vert3f(f[1]); Point3f &v2 = patch.Vert3f(f[2]); Point3f a = (v1 - v0); Point3f b = (v2 - v0); float n = a.Norm() * b.Norm(); if(n == 0) continue; Point3f norm = a^b; float rn = norm.Norm(); norm *= asin(rn/n)/n; if(i%2) norm = -norm; normal[f[0]] += norm; normal[f[1]] += norm; normal[f[2]] += norm; } } else assert(0); } //now fix borders map > lowers; for(unsigned int i = 0; i < border.Size(); i++) { Link &link = border[i]; if(levels[link.end_patch] == current_level) { //TODO remove these asserts assert(normals[p].size() > link.start_vert); assert(normals.count(link.end_patch)); assert(normals[link.end_patch].size() > link.end_vert); normals[p][link.start_vert] += normals[link.end_patch][link.end_vert]; } else if (levels[link.end_patch] < current_level) { lowers[link.end_patch].push_back(link); } } map >::iterator s; for(s = lowers.begin(); s != lowers.end(); s++) { Patch &patch = nexus.GetPatch((*s).first); for(unsigned int i = 0; i < (*s).second.size(); i++) { Link &link = (*s).second[i]; if(nexus.signature.vnorm == Encodings::FLOAT3) normals[p][link.start_vert] = ((Point3f *)patch.VNormBegin())[link.end_vert]; else if(nexus.signature.vnorm == Encodings::SHORT4) { Point3f &nor = normals[p][link.start_vert]; short *n = ((short *)patch.VNormBegin()) + 4*link.end_vert; nor[0] = n[0]; nor[1] = n[1]; nor[2] = n[2]; } } } //copy and normalize Patch &patch = nexus.GetPatch(p); Entry &entry = nexus[p]; Point3f *norm = (Point3f *)patch.VNormBegin(); vector &newnormals = normals[p]; assert(newnormals.size() == patch.nv); for(unsigned int i = 0; i < patch.nv; i++) { newnormals[i].Normalize(); if(nexus.signature.vnorm == Encodings::SHORT4) { newnormals[i] *= 32766; short *np = ((short *)norm) + 4 * i; np[0] = (short)newnormals[i][0]; np[1] = (short)newnormals[i][1]; np[2] = (short)newnormals[i][2]; np[3] = 0; } else if(nexus.signature.vnorm == Encodings::FLOAT3) norm[i] = newnormals[i]; } } if(count == 0) break; current_level++; } } /*void nxs::ComputeNormals(Nexus &nexus) { assert(nexus.signature.vnorm); //setting borders readonly: assert(!nexus.borders.IsReadOnly()); nexus.borders.SetReadOnly(true); //TODO use a temporary file to store border normals unsigned int tmpb_offset = 0; vector tmpb_start; VFile tmpb; if(!tmpb.Create("tmpb.tmp")) { cerr << "Could not create temporary border file\n"; exit(0); } for(unsigned int p = 0; p < nexus.size(); p++) { Border &border = nexus.borders[p]; tmpb_start.push_back(tmpb_offset); tmpb_offset += border.Size(); } Point3f zero(0.0f, 0.0f, 0.0f); tmpb.Resize(tmpb_offset); for(unsigned int i = 0; i < tmpb.Size(); i++) tmpb[i] = zero; tmpb.Flush(); vector levels; nexus.history.BuildLevels(levels); //first step normals in the same patch. cerr << "First Step\n"; Report report(nexus.size(), 5); vector normals; for(unsigned int p = 0; p < nexus.size(); p++) { int current_level = levels[p]; report.Step(p); Patch &patch = nexus.GetPatch(p); normals.clear(); normals.resize(patch.nv, Point3f(0, 0, 0)); if(nexus.signature.face == Signature::TRIANGLES) for(unsigned int i = 0; i < patch.nf; i++) { unsigned short *f = patch.Face(i); Point3f &v0 = patch.Vert3f(f[0]); Point3f &v1 = patch.Vert3f(f[1]); Point3f &v2 = patch.Vert3f(f[2]); Point3f norm = (v1 - v0) ^ (v2 - v0); normals[f[0]] += norm; normals[f[1]] += norm; normals[f[2]] += norm; } if(nexus.signature.face == Signature::STRIPS) for(int i = 0; i < patch.nf - 2; i++) { unsigned short *f = patch.FaceBegin() + i; Point3f &v0 = patch.Vert3f(f[0]); Point3f &v1 = patch.Vert3f(f[1]); Point3f &v2 = patch.Vert3f(f[2]); Point3f norm = (v1 - v0) ^ (v2 - v0); if(i%2) norm = -norm; normals[f[0]] += norm; normals[f[1]] += norm; normals[f[2]] += norm; } if(nexus.signature.vnorm == Encodings::SHORT4) { short *n = (short *)patch.VNormBegin(); for(unsigned int i = 0; i < patch.nv; i++, n += 4) { Point3f &norm = normals[i]; norm.Normalize(); for(int k = 0; k < 3; k++) n[k] = (short)(norm[k] * 32766); n[3] = 0; } } else if(nexus.signature.vnorm == Encodings::FLOAT3) { Point3f *n = (Point3f *)patch.VNormBegin(); for(unsigned int i = 0; i < patch.nv; i++) { n[i] = normals[i]; n[i].Normalize(); } } Border &border = nexus.GetBorder(p); map > bnorm; map bcopy; unsigned int poff = tmpb_start[p]; for(unsigned int i = 0; i < border.Size(); i++) { Link &link = border[i]; if(link.IsNull()) continue; //this should never happen now. Point3f pt = normals[link.start_vert]; if(levels[link.end_patch] == current_level) { bnorm[link.end_patch][link.end_vert] = pt; tmpb[poff + i] += pt; } else if(levels[link.end_patch] > current_level) { bcopy[i] = link; } } map >::iterator k; for(k = bnorm.begin(); k != bnorm.end(); k++) { unsigned int patch = (*k).first; Border &rborder = nexus.GetBorder(patch); unsigned int offset = tmpb_start[patch]; for(unsigned int i = 0; i < rborder.Size(); i++) { Link &link = rborder[i]; //assert(!link.IsNull()); //TODO not accurate if(link.end_patch != p) continue; if((*k).second.count(link.start_vert)) tmpb[offset + i] += (*k).second[link.start_vert]; } } //Uncomment this only when links are ok! map::iterator j; for(j = bcopy.begin(); j != bcopy.end(); j++) { unsigned int b = (*j).first; Link link = (*j).second; Border &rborder = nexus.GetBorder(link.end_patch, false); unsigned int offset = tmpb_start[link.end_patch]; for(unsigned int i = 0; i < rborder.Size(); i++) { Link &rlink = rborder[i]; if(rlink.end_patch == p && rlink.start_vert == link.end_vert) { assert(rlink.end_vert == link.start_vert); tmpb[poff + b] = tmpb[offset + i]; } } } } //Second step unify normals across borders cerr << "Second step\n"; report.Init(nexus.size()); for(unsigned int p = 0; p < nexus.size(); p++) { report.Step(p); Patch &patch = nexus.GetPatch(p); Border &border = nexus.GetBorder(p); Point3f *normf = (Point3f *)patch.VNormBegin(); short *norms = (short *)patch.VNormBegin(); for(unsigned int i = 0; i < border.Size(); i++) { Link &link = border[i]; if(link.IsNull()) continue; unsigned int off = tmpb_start[p]; // Point3f &n = tmpb[off + i]; Point3f n = tmpb[off + i]; if(n == Point3f(0.0f,0.0f,0.0f)) continue; n.Normalize(); if(nexus.signature.vnorm == Encodings::SHORT4) { n *= 32766; short *np = norms + 4 * link.start_vert; np[0] = (short)n[0]; np[1] = (short)n[1]; np[2] = (short)n[2]; np[3] = 0; } else if(nexus.signature.vnorm == Encodings::FLOAT3) { normf[link.start_vert] = n; } } } tmpb.Close(); tmpb.Delete(); //TODO remove temporary file. nexus.borders.SetReadOnly(false); }*/ /* //TODO why i created this function? wonder...void nxs::Reorder(Signature &signature, Patch &patch) { vector remap; remap.resize(patch.nv, 0xffff); int nf = patch.nf; if(signature.face == Signature::TRIANGLES) nf *= 3; else if(signature.face != Signature::STRIPS) { assert(0); //mah... } //building remap unsigned short *f = patch.FaceBegin(); unsigned int count = 0; for(int i = 0; i < nf; i++) { assert(f[i] < remap.size()); if(remap[f[i]] == 0xffff) { remap[f[i]] = count++; } } //test no unreferenced vertices for(int i = 0; i < patch.nv; i++) if(remap[i] == 0xffff) remap[i] = i; //converting faces for(int i = 0; i < nf; i++) f[i] = remap[f[i]]; vector vert; vert.resize(patch.nv); memcpy(&*vert.begin(), patch.Vert3fBegin(), patch.nv * sizeof(Point3f)); for(int i = 0; i < patch.nv; i++) patch.Vert3f(remap[i]) = vert[i]; }*/ //TODO actually use threshold void nxs::Unify(vector &points, vector &faces, vector &remap, float threshold) { vector newfaces = faces; VPartition grid; for(unsigned int i = 0; i < points.size(); i++) grid.push_back(points[i]); grid.Init(); remap.resize(points.size()); vector targets; vector dists; points.clear(); unsigned int count = 0; for(unsigned int i = 0; i < grid.size(); i++) { grid.Closest(grid[i], targets, dists, threshold); if(targets.size() > 1) { unsigned int p; for(p = 0; p < targets.size(); p++) { if(targets[p] < i) { remap[i] = remap[targets[p]]; break; } } if(p < targets.size()) continue; } remap[i] = count++; points.push_back(grid[i]); } //fixing faces now faces.clear(); for(unsigned int i = 0; i < newfaces.size(); i += 3) { unsigned short f[3]; f[0] = remap[newfaces[i]]; f[1] = remap[newfaces[i+1]]; f[2] = remap[newfaces[i+2]]; if(f[0] == f[1] || f[0] == f[2] || f[1] == f[2]) continue; for(int k = 0; k < 3; k++) faces.push_back(f[k]); } } /*void nxs::Unify(Nexus &nexus, float threshold) { threshold = 0.00001; unsigned int duplicated = 0; unsigned int degenerate = 0; for(unsigned int p = 0; p < nexus.size(); p++) { if(levels[p] != current_level) continue; count++; report.Step(p); Border &border = nexus.GetBorder(p); map > normals; normals[p] = vector(); for(unsigned int i = 0; i < border.Size(); i++) { Link &link = border[i]; if(levels[link.end_patch] == current_level) normals[link.end_patch] = vector(); } map >::iterator k; for(k = normals.begin(); k != normals.end(); k++) { Patch &patch = nexus.GetPatch((*k).first); } } }*/ /* void nxs::Unify(Nexus &nexus, float threshold) { threshold = 0.001; //TODO what if colors or normals or strips? unsigned int duplicated = 0; unsigned int degenerate = 0; for(unsigned int p = 0; p < nexus.size(); p++) { Entry &entry = nexus[p]; Patch &patch = nexus.GetPatch(p); VPartition part; for(unsigned int i = 0; i < patch.nv; i++) { Point3f &point = patch.Vert3f(i); part.push_back(point); } part.Init(); unsigned int vcount = 0; vector remap; remap.resize(patch.nv); int targets[8]; double dists[8]; //TODO CRITICAL FIX this unifying routine. for(unsigned int i = 0; i < patch.nv; i++) { Point3f &point = patch.Vert3f(i); part.Closest(point, 8, targets, dists); int k = 0; for(k = 0; k < 8; k++) { if(dists[k] > threshold) { remap[i] = vcount++; break; } if(targets[k] < i) { remap[i] = remap[targets[k]]; duplicated++; break; } } if(k == 8) remap[i] = vcount++; } if(vcount == patch.nv) //no need to unify continue; vector newvert; newvert.resize(vcount); for(unsigned int i = 0; i < patch.nv; i++) newvert[remap[i]] = patch.Vert3f(i); 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(nexus.signature, entry.nvert, entry.nface); memcpy(patch.Vert3fBegin(), &(newvert[0]), entry.nvert*sizeof(Point3f)); memcpy(patch.FaceBegin(), &(newface[0]), entry.nface*3*sizeof(short)); //testiamo il tutto... TODO remove this of course #ifdef NDEBUG for(unsigned int i =0; i < patch.nf; i++) { for(int k =0 ; k < 3; k++) if(patch.Face(i)[k] >= patch.nv) { cerr <<" Unify has problems\n"; exit(0); } } #endif //TODO CRITICAL FIX unify vertices across borders..... HOW?????? //fix patch borders now set close; //bordering pathes Border &border = nexus.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 = nexus.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]; } } } } //better to compact directly borders than setting them null. //finally: there may be duplicated borders for(unsigned int p = 0; p < nexus.size(); p++) { Border &border = nexus.GetBorder(p); set links; for(unsigned int b = 0; b < border.Size(); b++) { Link &link = border[b]; assert(!link.IsNull()); //if(border[b].IsNull()) continue; links.insert(link); } int count = 0; for(set::iterator k = links.begin(); k != links.end(); k++) border[count++] = *k; nexus.borders[p].used = links.size(); } nexus.totvert -= duplicated; if(duplicated) cerr << "Found " << duplicated << " duplicated vertices" << endl; if(degenerate) cerr << "Found " << degenerate << " degenerate face while unmifying\n"; } */ void nxs::ZSort(Nexus &nexus, vector &forward, vector &backward) { //lets get a bounding box from the sphere: ZCurve zcurve; float r = nexus.sphere.Radius(); Point3f radius(r, r, r); zcurve.Set(nexus.sphere.Center()); zcurve.Add(nexus.sphere.Center() - radius); zcurve.Add(nexus.sphere.Center() + radius); vector levels; nexus.history.BuildLevels(levels); forward.clear(); vector< vector > entries; for(unsigned int i = 0; i < nexus.size(); i++) { int level = levels[i]; while(level >= entries.size()) entries.push_back(vector()); ZEntry e; e.id = i; e.pos = zcurve.Pos(nexus[i].sphere.Center()); entries[level].push_back(e); } for(unsigned int i = 0; i < entries.size(); i++) { vector &lev = entries[i]; std::sort(lev.begin(), lev.end()); for(unsigned int k = 0; k < lev.size(); k++) forward.push_back(lev[k].id); } backward.resize(forward.size()); for(unsigned int i = 0; i < backward.size(); i++) backward[forward[i]] = i; } bool nxs::LineIntersect(Nexus &nexus, Extraction &extraction, Line3f line, Point3f &hit) { //seguiamo la history; Point3f tmp; if(!Intersection(nexus.sphere, line, hit, tmp)) return false; bool found = false; float min_dist = -1; float bar1, bar2, dist; for(unsigned int i = 0; i < extraction.draw_size; i++) { unsigned int p = extraction.selected[i].id; if(!Intersection(nexus[p].sphere, line, hit, tmp)) continue; Patch &patch = nexus.GetPatch(p); if(nexus.signature.face == Signature::TRIANGLES) { for(unsigned int i = 0; i < patch.nf; i++) { unsigned short *f = patch.Face(i); Point3f &v0 = patch.Vert3f(f[0]); Point3f &v1 = patch.Vert3f(f[1]); Point3f &v2 = patch.Vert3f(f[2]); if(Intersection(line, v0, v1, v2, bar1, bar2, dist) && dist > 0 && (min_dist == -1 || min_dist > dist)) { hit = v0*(1-bar1-bar2) + v1*bar1 + v2*bar2; min_dist = dist; found = true; } } } else if(nexus.signature.face == Signature::STRIPS) { for(int i = 0; i < patch.nf - 2; i++) { unsigned short *f = patch.FaceBegin() + i; Point3f &v0 = patch.Vert3f(f[0]); Point3f &v1 = patch.Vert3f(f[1]); Point3f &v2 = patch.Vert3f(f[2]); if(Intersection(line, v0, v1, v2, bar1, bar2, dist) && dist > 0 && (min_dist == -1 || min_dist > dist)) { hit = v0*(1-bar1-bar2) + v1*bar1 + v2*bar2; min_dist = dist; found = true; } } } else assert(0); } return found; }