#include "sort_triangles.h" #include "barycenter.h" #include "sort.h" #include "sortrows.h" #include "slice.h" #include "round.h" #include "colon.h" #include "matlab_format.h" #include template < typename DerivedV, typename DerivedF, typename DerivedMV, typename DerivedP, typename DerivedFF, typename DerivedI> IGL_INLINE void igl::sort_triangles( const Eigen::PlainObjectBase & V, const Eigen::PlainObjectBase & F, const Eigen::PlainObjectBase & MV, const Eigen::PlainObjectBase & P, Eigen::PlainObjectBase & FF, Eigen::PlainObjectBase & I) { using namespace Eigen; using namespace igl; using namespace std; // Barycenter, centroid Eigen::Matrix D,sD; Eigen::Matrix BC,PBC; barycenter(V,F,BC); D = BC*(MV.transpose()*P.transpose().eval().col(2)); sort(D,1,false,sD,I); //// Closest corner //Eigen::Matrix D,sD; //D.setConstant(F.rows(),1,-1e26); //for(int c = 0;c<3;c++) //{ // Eigen::Matrix C; // Eigen::Matrix DC; // C.resize(F.rows(),4); // for(int f = 0;fD.array()).select(DC,D).eval(); //} //sort(D,1,false,sD,I); //// Closest corner with tie breaks //Eigen::Matrix D,sD,ssD; //D.resize(F.rows(),3); //for(int c = 0;c<3;c++) //{ // Eigen::Matrix C; // C.resize(F.rows(),4); // for(int f = 0;f void igl::sort_triangles( const Eigen::PlainObjectBase & V, const Eigen::PlainObjectBase & F, Eigen::PlainObjectBase & FF, Eigen::PlainObjectBase & I) { using namespace Eigen; using namespace igl; using namespace std; // Put model, projection, and viewport matrices into double arrays Matrix4d MV; Matrix4d P; glGetDoublev(GL_MODELVIEW_MATRIX, MV.data()); glGetDoublev(GL_PROJECTION_MATRIX, P.data()); if(V.cols() == 3) { Matrix hV; hV.resize(V.rows(),4); hV.block(0,0,V.rows(),V.cols()) = V; hV.col(3).setConstant(1); return sort_triangles(hV,F,MV,P,FF,I); }else { return sort_triangles(V,F,MV,P,FF,I); } } #include "project.h" #include template < typename DerivedV, typename DerivedF, typename DerivedFF, typename DerivedI> void igl::sort_triangles_slow( const Eigen::PlainObjectBase & V, const Eigen::PlainObjectBase & F, Eigen::PlainObjectBase & FF, Eigen::PlainObjectBase & I) { using namespace Eigen; using namespace igl; using namespace std; // Barycenter, centroid Eigen::Matrix D,sD; Eigen::Matrix BC; D.resize(F.rows(),3); barycenter(V,F,BC); for(int f = 0;f bc,pbc; bc = BC.row(f); project(bc,pbc); D(f) = pbc(2); } sort(D,1,false,sD,I); slice(F,I,1,FF); } #include "EPS.h" #include #include static int tough_count = 0; template class Triangle { public: static inline bool z_comp(const Vec3 & A, const Vec3 & B) { return A(2) > B(2); } static typename Vec3::Scalar ZERO() { return igl::EPS(); return 0; } public: int id; // Sorted projected coners: c[0] has smallest z value Vec3 c[3]; Vec3 n; public: Triangle():id(-1) { }; Triangle(int id, const Vec3 c0, const Vec3 c1, const Vec3 c2): id(id) { using namespace std; c[0] = c0; c[1] = c1; c[2] = c2; sort(c,c+3,Triangle::z_comp); // normal pointed toward viewpoint n = (c0-c1).cross(c2-c0); if(n(2) < 0) { n *= -1.0; } // Avoid NaNs typename Vec3::Scalar len = n.norm(); if(len == 0) { cout<<"avoid NaN"<=0); return n.dot(r-c[closest]); } // Z-values of this are < z-values of that bool is_completely_behind(const Triangle & that) const { const typename Vec3::Scalar ac0 = that.c[0](2); const typename Vec3::Scalar ac1 = that.c[1](2); const typename Vec3::Scalar ac2 = that.c[2](2); const typename Vec3::Scalar ic0 = this->c[0](2); const typename Vec3::Scalar ic1 = this->c[1](2); const typename Vec3::Scalar ic2 = this->c[2](2); return (ic0 < ac2 && ic1 <= ac2 && ic2 <= ac2) || (ic0 <= ac2 && ic1 < ac2 && ic2 <= ac2) || (ic0 <= ac2 && ic1 <= ac2 && ic2 < ac2); } bool is_behind_plane(const Triangle &that) const { using namespace std; const typename Vec3::Scalar apc0 = that.project(this->c[0]); const typename Vec3::Scalar apc1 = that.project(this->c[1]); const typename Vec3::Scalar apc2 = that.project(this->c[2]); cout<<" "<< apc0<<", "<< apc1<<", "<< apc2<<", "<c[0]); const typename Vec3::Scalar apc1 = that.project(this->c[1]); const typename Vec3::Scalar apc2 = that.project(this->c[2]); cout<<" "<< apc0<<", "<< apc1<<", "<< apc2<<", "< ZERO() && apc1 > ZERO() && apc2 > ZERO()); } bool is_coplanar(const Triangle &that) const { using namespace std; const typename Vec3::Scalar apc0 = that.project(this->c[0]); const typename Vec3::Scalar apc1 = that.project(this->c[1]); const typename Vec3::Scalar apc2 = that.project(this->c[2]); return (fabs(apc0)<=ZERO() && fabs(apc1)<=ZERO() && fabs(apc2)<=ZERO()); } // http://stackoverflow.com/a/14561664/148668 // a1 is line1 start, a2 is line1 end, b1 is line2 start, b2 is line2 end static bool seg_seg_intersect(const Vec3 & a1, const Vec3 & a2, const Vec3 & b1, const Vec3 & b2) { Vec3 b = a2-a1; Vec3 d = b2-b1; typename Vec3::Scalar bDotDPerp = b(0) * d(1) - b(1) * d(0); // if b dot d == 0, it means the lines are parallel so have infinite intersection points if (bDotDPerp == 0) return false; Vec3 c = b1-a1; typename Vec3::Scalar t = (c(0) * d(1) - c(1) * d(0)) / bDotDPerp; if (t < 0 || t > 1) return false; typename Vec3::Scalar u = (c(0) * b(1) - c(1) * b(0)) / bDotDPerp; if (u < 0 || u > 1) return false; return true; } bool has_corner_inside(const Triangle & that) const { // http://www.blackpawn.com/texts/pointinpoly/ // Compute vectors Vec3 A = that.c[0]; Vec3 B = that.c[1]; Vec3 C = that.c[2]; A(2) = B(2) = C(2) = 0; for(int ci = 0;ci<3;ci++) { Vec3 P = this->c[ci]; P(2) = 0; Vec3 v0 = C - A; Vec3 v1 = B - A; Vec3 v2 = P - A; // Compute dot products typename Vec3::Scalar dot00 = v0.dot(v0); typename Vec3::Scalar dot01 = v0.dot(v1); typename Vec3::Scalar dot02 = v0.dot(v2); typename Vec3::Scalar dot11 = v1.dot(v1); typename Vec3::Scalar dot12 = v1.dot(v2); // Compute barycentric coordinates typename Vec3::Scalar invDenom = 1 / (dot00 * dot11 - dot01 * dot01); typename Vec3::Scalar u = (dot11 * dot02 - dot01 * dot12) * invDenom; typename Vec3::Scalar v = (dot00 * dot12 - dot01 * dot02) * invDenom; // Check if point is in triangle if((u >= 0) && (v >= 0) && (u + v < 1)) { return true; } } return false; } bool overlaps(const Triangle &that) const { // Edges cross for(int e = 0;e<3;e++) { for(int f = 0;f<3;f++) { if(seg_seg_intersect( this->c[e],this->c[(e+1)%3], that.c[e],that.c[(e+1)%3])) { return true; } } } // This could be entirely inside that if(this->has_corner_inside(that)) { return true; } // vice versa if(that.has_corner_inside(*this)) { return true; } return false; } bool operator< (const Triangle &that) const { // THIS < THAT if "depth" of THIS < "depth" of THAT // " if THIS should be draw before THAT using namespace std; bool ret = false; // Self compare if(that.id == this->id) { ret = false; } if(this->is_completely_behind(that)) { cout<<" "<id<<" completely behind "<id<overlaps(that)) { assert(!that.overlaps(*this)); cout<<" THIS does not overlap THAT"<c[0](2) + this->c[1](2) + this->c[2](2)) > 1./3.*(that.c[0](2) + that.c[1](2) + that.c[2](2)); }else { if(this->is_coplanar(that) || that.is_coplanar(*this)) { cout<<" coplanar"<c[0](2) + this->c[1](2) + this->c[2](2)) > 1./3.*(that.c[0](2) + that.c[1](2) + that.c[2](2)); }else if(this->is_behind_plane(that)) { cout<<" THIS behind plane of THAT"<is_in_front_of_plane(that)) { cout<<" THIS in front plane of THAT"<c[0](2) + this->c[1](2) + this->c[2](2)) > 1./3.*(that.c[0](2) + that.c[1](2) + that.c[2](2)); } } } if(ret) { // THIS < THAT so better not be THAT < THIS cout<id<<" < "<= THAT so could be THAT < THIS or THAT == THIS } return ret; } }; //#include // //template < // typename DerivedV, // typename DerivedF, // typename DerivedMV, // typename DerivedP, // typename DerivedFF, // typename DerivedI> //IGL_INLINE void igl::sort_triangles_robust( // const Eigen::PlainObjectBase & V, // const Eigen::PlainObjectBase & F, // const Eigen::PlainObjectBase & MV, // const Eigen::PlainObjectBase & P, // Eigen::PlainObjectBase & FF, // Eigen::PlainObjectBase & I) //{ // assert(false && // "THIS WILL NEVER WORK because depth sorting is not a numerical sort where" // "pairwise comparisons of triangles are transitive. Rather it is a" // "topological sort on a dependecy graph. Dependency encodes 'This triangle" // "must be drawn before that one'"); // using namespace std; // using namespace Eigen; // using namespace igl; // typedef Matrix Vec3; // assert(V.cols() == 4); // Matrix VMVP = // V*(MV.transpose()*P.transpose().eval().block(0,0,4,3)); // // MatrixXd projV(V.rows(),3); // for(int v = 0;v > vF(F.rows()); // MatrixXd N(F.rows(),3); // MatrixXd C(F.rows()*3,3); // for(int f = 0;f(f,VMVP.row(F(f,0)),VMVP.row(F(f,1)),VMVP.row(F(f,2))); // Triangle(f,projV.row(F(f,0)),projV.row(F(f,1)),projV.row(F(f,2))); // N.row(f) = vF[f].n; // for(int c = 0;c<3;c++) // for(int d = 0;d<3;d++) // C(f*3+c,d) = vF[f].c[c](d); // } // MatlabWorkspace mw; // mw.save_index(F,"F"); // mw.save(V,"V"); // mw.save(MV,"MV"); // mw.save(P,"P"); // Vector4i VP; // glGetIntegerv(GL_VIEWPORT, VP.data()); // mw.save(projV,"projV"); // mw.save(VP,"VP"); // mw.save(VMVP,"VMVP"); // mw.save(N,"N"); // mw.save(C,"C"); // mw.write("ao.mat"); // sort(vF.begin(),vF.end()); // // // check // for(int f = 0;f //IGL_INLINE void igl::sort_triangles_robust( // const Eigen::PlainObjectBase & V, // const Eigen::PlainObjectBase & F, // Eigen::PlainObjectBase & FF, // Eigen::PlainObjectBase & I) //{ // using namespace Eigen; // using namespace igl; // using namespace std; // // Put model, projection, and viewport matrices into double arrays // Matrix4d MV; // Matrix4d P; // glGetDoublev(GL_MODELVIEW_MATRIX, MV.data()); // glGetDoublev(GL_PROJECTION_MATRIX, P.data()); // if(V.cols() == 3) // { // Matrix hV; // hV.resize(V.rows(),4); // hV.block(0,0,V.rows(),V.cols()) = V; // hV.col(3).setConstant(1); // return sort_triangles_robust(hV,F,MV,P,FF,I); // }else // { // return sort_triangles_robust(V,F,MV,P,FF,I); // } //} #endif #ifndef IGL_HEADER_ONLY // Explicit template instanciation //template void igl::sort_triangles_robust, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(Eigen::PlainObjectBase > const&, Eigen::PlainObjectBase > const&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); #ifndef IGL_NO_OPENGL template void igl::sort_triangles, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(Eigen::PlainObjectBase > const&, Eigen::PlainObjectBase > const&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); template void igl::sort_triangles_slow, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(Eigen::PlainObjectBase > const&, Eigen::PlainObjectBase > const&, Eigen::PlainObjectBase >&, Eigen::PlainObjectBase >&); #endif #endif