diff --git a/apps/nexus/normalscone.cpp b/apps/nexus/normalscone.cpp new file mode 100644 index 00000000..cd6e95af --- /dev/null +++ b/apps/nexus/normalscone.cpp @@ -0,0 +1,177 @@ +#include "normalscone.h" +#include + +using namespace std; +using namespace vcg; +using namespace nxs; + + +ANCone3f::ANCone3f() { + scaledNormal = Point3f(0,0,0); + frontAnchor = Point3f(0,0,0); + backAnchor = Point3f(0,0,0); +} + +bool ANCone3f::Frontface(const Point3f &viewPoint) { + Point3f d = frontAnchor - viewPoint; //Vector from viewPoint to frontAnchor. + float f = - d * scaledNormal; + if (f < 0.001 || f * f < d * d) + return false; + return true; +} + +bool ANCone3f::Backface(const Point3f &viewPoint) { + Point3f d = backAnchor - viewPoint; //Vector from viewPoint to frontAnchor. + float f = d * scaledNormal; + if (f < 0.001 || f * f < d * d) + return false; + return true; +} + +void ANCone3f::AddNormals(vector &normal, vector &area, float threshold) { + assert(normal.size() == area.size()); + scaledNormal = Point3f(0,0,0); + int count = 0; + vector::iterator i; + for(i = normal.begin(); i != normal.end(); i++) { + scaledNormal += *i; + count++; + } + scaledNormal /= count; + scaledNormal.Normalize(); + + double distr[50]; + for(int k = 0; k < 50; k++) + distr[k] = 0; + double tot_area = 0; + + vector::iterator j; + for(i = normal.begin(), j = area.begin(); i != normal.end(); i++, j++) { + int pos = (int)(49.0 * Angle(scaledNormal, *i)/M_PI); + if(pos < 0) continue; + assert(pos >=0 && pos < 50); + distr[pos] += *j; + tot_area += *j; + } + + float tot = 0; + int best; + for(best = 0; best < 50; best++) { + tot += distr[best]; + if(tot > threshold * tot_area) + break; + } + double alpha = M_PI * (best + 1) / 50; + if(alpha > M_PI/ 2 - 0.1) + scaledNormal = Point3f(0,0,0); + else + scaledNormal /= cos(M_PI/2 - alpha); +} + +void ANCone3f::AddNormals(vector &normal, float threshold) { + //assert(normal.size() > 0); + scaledNormal = Point3f(0,0,0); + int count = 0; + vector::iterator i; + for(i = normal.begin(); i != normal.end(); i++) { + Point3f norm = *i; + if(norm.Norm() < 0.00001) continue; + norm.Normalize(); + scaledNormal += norm; + count++; + } + scaledNormal /= count; + scaledNormal.Normalize(); + + int distr[50]; + for(int k = 0; k < 50; k++) + distr[k] =0; + + for(i = normal.begin(); i != normal.end(); i++) { + int pos = (int)(50.0 * Angle(scaledNormal, *i)/M_PI); + distr[pos]++; + } + int tot = 0; + int best; + // cerr << "Distr: "; + for(best = 0; best < 50; best++) { + // cerr << distr[best] << " "; + tot += distr[best]; + if(tot >= threshold * normal.size()) + break; + } + double alpha = M_PI * (best +1) / 50; + // cerr << "best: " << best << " alpha: " << alpha << endl; + if(alpha > M_PI/ 2) { + scaledNormal = Point3f(0,0,0); + } else { + scaledNormal /= cos(M_PI/2 - alpha); + } +} + +void ANCone3f::AddAnchors(vector &anchors) { + assert(anchors.size() > 0); + frontAnchor = anchors[0]; + backAnchor = anchors[0]; + + float fa = frontAnchor * scaledNormal; + float fb = -backAnchor * scaledNormal; + + vector::iterator i; + for(i = anchors.begin(); i != anchors.end(); i++) { + Point3f &anchor = *i; + float na = anchor * scaledNormal; + if(na < fa) { + frontAnchor = anchor; + fa = na; + } + if(-na < fb) { + backAnchor = anchor; + fb = -na; + } + } +} + +void NCone3s::Import(const ANCone3f &c) { + Point3f normal = c.scaledNormal; + float len = normal.Norm(); + if(len != 0) + normal /= len; + + assert(normal[0] <= 1 && normal[1] <= 1 && normal[2] <= 1); + assert(normal[0] >= -1 && normal[1] >= -1 && normal[2] >= -1); + n[0] = (short)(normal[0] * 32766); + n[1] = (short)(normal[1] * 32766); + n[2] = (short)(normal[2] * 32766); + //i want to rapresent number from 1 to 10 + if(len > 10.0f) len = 10.0f; + if(len < -10.0f) len = -10.0f; + n[3] = (short)(len * 3276); +} + + + + +bool NCone3s::Backface(const vcg::Sphere3f &sphere, + const vcg::Point3f &view) const { + vcg::Point3f norm(n[0]/32766.0f, n[1]/32766.0f, n[2]/32766.0f); + vcg::Point3f d = (sphere.Center() + norm * sphere.Radius()) - view; + norm *= n[3]/3276.0f; + + float f = d * norm; + if (f < 0.001 || f * f < d * d) + return false; + return true; +} + +bool NCone3s::Frontface(const vcg::Sphere3f &sphere, + const vcg::Point3f &view) const { + vcg::Point3f norm(n[0]/32766.0f, n[1]/32766.0f, n[2]/32766.0f); + vcg::Point3f d = (sphere.Center() - norm * sphere.Radius()) - view; + norm *= n[3]/3276.0f; + + float f = -d * norm; + if (f < 0.001 || f * f < d * d) + return false; + return true; +} diff --git a/apps/nexus/normalscone.h b/apps/nexus/normalscone.h new file mode 100644 index 00000000..af017531 --- /dev/null +++ b/apps/nexus/normalscone.h @@ -0,0 +1,53 @@ +#ifndef NXS_NORMALS_CONE_H +#define NXS_NORMALS_CONE_H + +#include + +#include +#include + +namespace nxs { + + + //anchored normal cone. + class ANCone3f { + public: + ANCone3f(); + + bool Frontface(const vcg::Point3f &viewPoint); + bool Backface(const vcg::Point3f &viewPoint); + + //threshold [0, 1]: percentage of normals to left out + void AddNormals(std::vector &normals, + float threshold = 1.0f); + void AddNormals(std::vector &normals, + std::vector &areas, + float threshold = 1.0f); + void AddAnchors(std::vector &anchors); + protected: + vcg::Point3f scaledNormal; + vcg::Point3f frontAnchor; + vcg::Point3f backAnchor; + + friend class NCone3s; + }; + + + + //this is not anchored... need a bounding sphere to report something + class NCone3s { + public: + void Import(const ANCone3f &c); + + bool Backface(const vcg::Sphere3f &sphere, + const vcg::Point3f &view) const; + bool Frontface(const vcg::Sphere3f &sphere, + const vcg::Point3f &view) const; + + //encode normal and sin(alpha) in n[3] + short n[4]; + }; + +} + +#endif